Browse Source

Merge branch 'main' into median-filter

pull/2219/head
James Jackson-South 4 years ago
committed by GitHub
parent
commit
c359b53ed9
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 30
      .editorconfig
  2. 2
      shared-infrastructure
  3. 4
      src/Directory.Build.props
  4. 7
      src/ImageSharp.ruleset
  5. 21
      src/ImageSharp/Advanced/AdvancedImageExtensions.cs
  6. 5
      src/ImageSharp/Advanced/PreserveAttribute.cs
  7. 13
      src/ImageSharp/Color/Color.cs
  8. 60
      src/ImageSharp/ColorSpaces/CieLab.cs
  9. 66
      src/ImageSharp/ColorSpaces/CieLch.cs
  10. 62
      src/ImageSharp/ColorSpaces/CieLchuv.cs
  11. 58
      src/ImageSharp/ColorSpaces/CieLuv.cs
  12. 46
      src/ImageSharp/ColorSpaces/CieXyy.cs
  13. 48
      src/ImageSharp/ColorSpaces/CieXyz.cs
  14. 60
      src/ImageSharp/ColorSpaces/Cmyk.cs
  15. 21
      src/ImageSharp/ColorSpaces/Companding/SRgbCompanding.cs
  16. 4
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Adapt.cs
  17. 27
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLab.cs
  18. 7
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLch.cs
  19. 29
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLchuv.cs
  20. 24
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLuv.cs
  21. 56
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyy.cs
  22. 30
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyz.cs
  23. 50
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Cmyk.cs
  24. 50
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsl.cs
  25. 50
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsv.cs
  26. 2
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.HunterLab.cs
  27. 61
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.LinearRgb.cs
  28. 2
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Lms.cs
  29. 60
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Rgb.cs
  30. 54
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.YCbCr.cs
  31. 46
      src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyChromaticityCoordinates.cs
  32. 6
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CIeLchToCieLabConverter.cs
  33. 4
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLabToCieLchConverter.cs
  34. 8
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLabToCieXyzConverter.cs
  35. 4
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLchuvToCieLuvConverter.cs
  36. 4
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLuvToCieLchuvConverter.cs
  37. 4
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLuvToCieXyzConverter.cs
  38. 8
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzAndCieXyyConverter.cs
  39. 6
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzAndLmsConverter.cs
  40. 10
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CmykAndRgbConverter.cs
  41. 6
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/HslAndRgbConverter.cs
  42. 6
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/HsvAndRgbConverter.cs
  43. 2
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/HunterLabToCieXyzConverter.cs
  44. 19
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/LinearRgbAndCieXyzConverterBase.cs
  45. 2
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/LinearRgbToCieXyzConverter.cs
  46. 8
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/LinearRgbToRgbConverter.cs
  47. 8
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/RgbToLinearRgbConverter.cs
  48. 8
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/YCbCrAndRgbConverter.cs
  49. 2
      src/ImageSharp/ColorSpaces/Conversion/Implementation/VonKriesChromaticAdaptation.cs
  50. 48
      src/ImageSharp/ColorSpaces/Hsl.cs
  51. 48
      src/ImageSharp/ColorSpaces/Hsv.cs
  52. 58
      src/ImageSharp/ColorSpaces/HunterLab.cs
  53. 56
      src/ImageSharp/ColorSpaces/LinearRgb.cs
  54. 48
      src/ImageSharp/ColorSpaces/Lms.cs
  55. 60
      src/ImageSharp/ColorSpaces/Rgb.cs
  56. 46
      src/ImageSharp/ColorSpaces/YCbCr.cs
  57. 35
      src/ImageSharp/Common/Extensions/EncoderExtensions.cs
  58. 46
      src/ImageSharp/Common/Extensions/StreamExtensions.cs
  59. 2
      src/ImageSharp/Common/Helpers/HexConverter.cs
  60. 6
      src/ImageSharp/Common/Helpers/InliningOptions.cs
  61. 146
      src/ImageSharp/Common/Helpers/Numerics.cs
  62. 32
      src/ImageSharp/Common/Helpers/RuntimeEnvironment.cs
  63. 46
      src/ImageSharp/Common/Helpers/RuntimeUtility.cs
  64. 7
      src/ImageSharp/Common/Helpers/Shuffle/IComponentShuffle.cs
  65. 216
      src/ImageSharp/Common/Helpers/SimdUtils.BasicIntrinsics256.cs
  66. 35
      src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs
  67. 20
      src/ImageSharp/Common/Helpers/SimdUtils.FallbackIntrinsics128.cs
  68. 88
      src/ImageSharp/Common/Helpers/SimdUtils.HwIntrinsics.cs
  69. 26
      src/ImageSharp/Common/Helpers/SimdUtils.Pack.cs
  70. 18
      src/ImageSharp/Common/Helpers/SimdUtils.Shuffle.cs
  71. 19
      src/ImageSharp/Common/Helpers/SimdUtils.cs
  72. 3
      src/ImageSharp/Common/Helpers/UnitConverter.cs
  73. 22
      src/ImageSharp/Compression/Zlib/Adler32.cs
  74. 16
      src/ImageSharp/Compression/Zlib/Crc32.cs
  75. 6
      src/ImageSharp/Compression/Zlib/DeflaterEngine.cs
  76. 4
      src/ImageSharp/Compression/Zlib/DeflaterOutputStream.cs
  77. 2
      src/ImageSharp/Compression/Zlib/DeflaterPendingBuffer.cs
  78. 2
      src/ImageSharp/Configuration.cs
  79. 7
      src/ImageSharp/Diagnostics/MemoryDiagnostics.cs
  80. 37
      src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs
  81. 51
      src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs
  82. 25
      src/ImageSharp/Formats/Bmp/BmpInfoHeader.cs
  83. 4
      src/ImageSharp/Formats/DecoderOptions.cs
  84. 27
      src/ImageSharp/Formats/Gif/GifEncoderCore.cs
  85. 2
      src/ImageSharp/Formats/Gif/Sections/GifImageDescriptor.cs
  86. 2
      src/ImageSharp/Formats/Gif/Sections/GifNetscapeLoopingApplicationExtension.cs
  87. 4
      src/ImageSharp/Formats/Gif/Sections/GifXmpApplicationExtension.cs
  88. 2
      src/ImageSharp/Formats/ImageFormatManager.cs
  89. 2
      src/ImageSharp/Formats/Jpeg/Components/Block8x8.Intrinsic.cs
  90. 68
      src/ImageSharp/Formats/Jpeg/Components/Block8x8.cs
  91. 4
      src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Intrinsic.cs
  92. 148
      src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs
  93. 2
      src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.CmykAvx.cs
  94. 2
      src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.GrayScaleAvx.cs
  95. 2
      src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.RgbAvx.cs
  96. 2
      src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.YCbCrAvx.cs
  97. 2
      src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.YccKAvx.cs
  98. 2
      src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverterAvx.cs
  99. 14
      src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverterBase.cs
  100. 25
      src/ImageSharp/Formats/Jpeg/Components/Decoder/ArithmeticScanDecoder.cs

30
.editorconfig

@ -1,5 +1,5 @@
# Version: 2.1.0 (Using https://semver.org/) # Version: 4.1.1 (Using https://semver.org/)
# Updated: 2021-03-03 # Updated: 2022-05-23
# See https://github.com/RehanSaeed/EditorConfig/releases for release notes. # See https://github.com/RehanSaeed/EditorConfig/releases for release notes.
# See https://github.com/RehanSaeed/EditorConfig for updates to this file. # See https://github.com/RehanSaeed/EditorConfig for updates to this file.
# See http://EditorConfig.org for more information about .editorconfig files. # See http://EditorConfig.org for more information about .editorconfig files.
@ -49,11 +49,11 @@ indent_size = 2
indent_size = 2 indent_size = 2
# Markdown Files # Markdown Files
[*.md] [*.{md,mdx}]
trim_trailing_whitespace = false trim_trailing_whitespace = false
# Web Files # Web Files
[*.{htm,html,js,jsm,ts,tsx,css,sass,scss,less,svg,vue}] [*.{htm,html,js,jsm,ts,tsx,cjs,cts,ctsx,mjs,mts,mtsx,css,sass,scss,less,pcss,svg,vue}]
indent_size = 2 indent_size = 2
# Batch Files # Batch Files
@ -75,7 +75,7 @@ indent_style = tab
[*.{cs,csx,cake,vb,vbx}] [*.{cs,csx,cake,vb,vbx}]
# Default Severity for all .NET Code Style rules below # Default Severity for all .NET Code Style rules below
dotnet_analyzer_diagnostic.category-style.severity = warning dotnet_analyzer_diagnostic.severity = warning
########################################## ##########################################
# Language Rules # Language Rules
@ -128,14 +128,15 @@ file_header_template = Copyright (c) Six Labors.\nLicensed under the Six Labors
# dotnet_diagnostic.SA1636.severity = none # dotnet_diagnostic.SA1636.severity = none
# Undocumented # Undocumented
dotnet_style_operator_placement_when_wrapping = end_of_line dotnet_style_operator_placement_when_wrapping = end_of_line:warning
csharp_style_prefer_null_check_over_type_check = true:warning
# C# Style Rules # C# Style Rules
# https://docs.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/language-rules#c-style-rules # https://docs.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/language-rules#c-style-rules
[*.{cs,csx,cake}] [*.{cs,csx,cake}]
# 'var' preferences # 'var' preferences
csharp_style_var_for_built_in_types = never csharp_style_var_for_built_in_types = false:warning
csharp_style_var_when_type_is_apparent = true:warning csharp_style_var_when_type_is_apparent = false:warning
csharp_style_var_elsewhere = false:warning csharp_style_var_elsewhere = false:warning
# Expression-bodied members # Expression-bodied members
csharp_style_expression_bodied_methods = true:warning csharp_style_expression_bodied_methods = true:warning
@ -200,12 +201,15 @@ dotnet_diagnostic.IDE0059.severity = suggestion
# Organize using directives # Organize using directives
dotnet_sort_system_directives_first = true dotnet_sort_system_directives_first = true
dotnet_separate_import_directive_groups = false dotnet_separate_import_directive_groups = false
# Dotnet namespace options
dotnet_style_namespace_match_folder = true:suggestion
dotnet_diagnostic.IDE0130.severity = suggestion
# C# formatting rules # C# formatting rules
# https://docs.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/formatting-rules#c-formatting-rules # https://docs.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/formatting-rules#c-formatting-rules
[*.{cs,csx,cake}] [*.{cs,csx,cake}]
# Newline options # Newline options
# https://docs.microsoft.com/visualstudio/ide/editorconfig-formatting-conventions#new-line-options # https://docs.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/formatting-rules#new-line-options
csharp_new_line_before_open_brace = all csharp_new_line_before_open_brace = all
csharp_new_line_before_else = true csharp_new_line_before_else = true
csharp_new_line_before_catch = true csharp_new_line_before_catch = true
@ -214,7 +218,7 @@ csharp_new_line_before_members_in_object_initializers = true
csharp_new_line_before_members_in_anonymous_types = true csharp_new_line_before_members_in_anonymous_types = true
csharp_new_line_between_query_expression_clauses = true csharp_new_line_between_query_expression_clauses = true
# Indentation options # Indentation options
# https://docs.microsoft.com/visualstudio/ide/editorconfig-formatting-conventions#indentation-options # https://docs.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/formatting-rules#indentation-options
csharp_indent_case_contents = true csharp_indent_case_contents = true
csharp_indent_switch_labels = true csharp_indent_switch_labels = true
csharp_indent_labels = no_change csharp_indent_labels = no_change
@ -222,7 +226,7 @@ csharp_indent_block_contents = true
csharp_indent_braces = false csharp_indent_braces = false
csharp_indent_case_contents_when_block = false csharp_indent_case_contents_when_block = false
# Spacing options # Spacing options
# https://docs.microsoft.com/visualstudio/ide/editorconfig-formatting-conventions#spacing-options # https://docs.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/formatting-rules#spacing-options
csharp_space_after_cast = false csharp_space_after_cast = false
csharp_space_after_keywords_in_control_flow_statements = true csharp_space_after_keywords_in_control_flow_statements = true
csharp_space_between_parentheses = false csharp_space_between_parentheses = false
@ -246,7 +250,7 @@ csharp_space_before_open_square_brackets = false
csharp_space_between_empty_square_brackets = false csharp_space_between_empty_square_brackets = false
csharp_space_between_square_brackets = false csharp_space_between_square_brackets = false
# Wrap options # Wrap options
# https://docs.microsoft.com/visualstudio/ide/editorconfig-formatting-conventions#wrap-options # https://docs.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/formatting-rules#wrap-options
csharp_preserve_single_line_statements = false csharp_preserve_single_line_statements = false
csharp_preserve_single_line_blocks = true csharp_preserve_single_line_blocks = true
@ -448,4 +452,4 @@ dotnet_naming_rule.parameters_rule.severity = warning
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
# OTHER DEALINGS IN THE SOFTWARE. # OTHER DEALINGS IN THE SOFTWARE.
########################################## ##########################################

2
shared-infrastructure

@ -1 +1 @@
Subproject commit c0e0353c1ee89398def0ccdc3e945380034fbea8 Subproject commit 5eb77e2d9eb4f0ece012c996941ab78db1af2a41

4
src/Directory.Build.props

@ -21,6 +21,10 @@
<TreatWarningsAsErrors>true</TreatWarningsAsErrors> <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup> </PropertyGroup>
<PropertyGroup>
<CodeAnalysisRuleSet>..\ImageSharp.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup> <ItemGroup>
<!-- DynamicProxyGenAssembly2 is needed so Moq can use our internals --> <!-- DynamicProxyGenAssembly2 is needed so Moq can use our internals -->
<InternalsVisibleTo Include="DynamicProxyGenAssembly2" Key="0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7" /> <InternalsVisibleTo Include="DynamicProxyGenAssembly2" Key="0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7" />

7
src/ImageSharp.ruleset

@ -0,0 +1,7 @@
<?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>

21
src/ImageSharp/Advanced/AdvancedImageExtensions.cs

@ -3,6 +3,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization;
using System.IO; using System.IO;
using System.Text; using System.Text;
using System.Threading; using System.Threading;
@ -34,11 +35,11 @@ namespace SixLabors.ImageSharp.Advanced
IImageFormat format = source.GetConfiguration().ImageFormatsManager.FindFormatByFileExtension(ext); IImageFormat format = source.GetConfiguration().ImageFormatsManager.FindFormatByFileExtension(ext);
if (format is null) if (format is null)
{ {
var sb = new StringBuilder(); StringBuilder sb = new();
sb.AppendLine($"No encoder was found for extension '{ext}'. Registered encoders include:"); sb.AppendLine(CultureInfo.InvariantCulture, $"No encoder was found for extension '{ext}'. Registered encoders include:");
foreach (IImageFormat fmt in source.GetConfiguration().ImageFormats) foreach (IImageFormat fmt in source.GetConfiguration().ImageFormats)
{ {
sb.AppendFormat(" - {0} : {1}{2}", fmt.Name, string.Join(", ", fmt.FileExtensions), Environment.NewLine); sb.AppendFormat(CultureInfo.InvariantCulture, " - {0} : {1}{2}", fmt.Name, string.Join(", ", fmt.FileExtensions), Environment.NewLine);
} }
throw new NotSupportedException(sb.ToString()); throw new NotSupportedException(sb.ToString());
@ -48,11 +49,11 @@ namespace SixLabors.ImageSharp.Advanced
if (encoder is null) if (encoder is null)
{ {
var sb = new StringBuilder(); StringBuilder sb = new();
sb.AppendLine($"No encoder was found for extension '{ext}' using image format '{format.Name}'. Registered encoders include:"); sb.AppendLine(CultureInfo.InvariantCulture, $"No encoder was found for extension '{ext}' using image format '{format.Name}'. Registered encoders include:");
foreach (KeyValuePair<IImageFormat, IImageEncoder> enc in source.GetConfiguration().ImageFormatsManager.ImageEncoders) foreach (KeyValuePair<IImageFormat, IImageEncoder> enc in source.GetConfiguration().ImageFormatsManager.ImageEncoders)
{ {
sb.AppendFormat(" - {0} : {1}{2}", enc.Key, enc.Value.GetType().Name, Environment.NewLine); sb.AppendFormat(CultureInfo.InvariantCulture, " - {0} : {1}{2}", enc.Key, enc.Value.GetType().Name, Environment.NewLine);
} }
throw new NotSupportedException(sb.ToString()); throw new NotSupportedException(sb.ToString());
@ -116,6 +117,7 @@ namespace SixLabors.ImageSharp.Advanced
/// Certain Image Processors may invalidate the returned <see cref="IMemoryGroup{T}"/> and all it's buffers, /// Certain Image Processors may invalidate the returned <see cref="IMemoryGroup{T}"/> and all it's buffers,
/// therefore it's not recommended to mutate the image while holding a reference to it's <see cref="IMemoryGroup{T}"/>. /// therefore it's not recommended to mutate the image while holding a reference to it's <see cref="IMemoryGroup{T}"/>.
/// </remarks> /// </remarks>
/// <exception cref="ArgumentNullException">Thrown when the <paramref name="source"/> in <see langword="null"/>.</exception>
public static IMemoryGroup<TPixel> GetPixelMemoryGroup<TPixel>(this ImageFrame<TPixel> source) public static IMemoryGroup<TPixel> GetPixelMemoryGroup<TPixel>(this ImageFrame<TPixel> source)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
=> source?.PixelBuffer.FastMemoryGroup.View ?? throw new ArgumentNullException(nameof(source)); => source?.PixelBuffer.FastMemoryGroup.View ?? throw new ArgumentNullException(nameof(source));
@ -131,13 +133,14 @@ namespace SixLabors.ImageSharp.Advanced
/// Certain Image Processors may invalidate the returned <see cref="IMemoryGroup{T}"/> and all it's buffers, /// Certain Image Processors may invalidate the returned <see cref="IMemoryGroup{T}"/> and all it's buffers,
/// therefore it's not recommended to mutate the image while holding a reference to it's <see cref="IMemoryGroup{T}"/>. /// therefore it's not recommended to mutate the image while holding a reference to it's <see cref="IMemoryGroup{T}"/>.
/// </remarks> /// </remarks>
/// <exception cref="ArgumentNullException">Thrown when the <paramref name="source"/> in <see langword="null"/>.</exception>
public static IMemoryGroup<TPixel> GetPixelMemoryGroup<TPixel>(this Image<TPixel> source) public static IMemoryGroup<TPixel> GetPixelMemoryGroup<TPixel>(this Image<TPixel> source)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
=> source?.Frames.RootFrame.GetPixelMemoryGroup() ?? throw new ArgumentNullException(nameof(source)); => source?.Frames.RootFrame.GetPixelMemoryGroup() ?? throw new ArgumentNullException(nameof(source));
/// <summary> /// <summary>
/// Gets the representation of the pixels as a <see cref="Span{T}"/> of contiguous memory /// Gets the representation of the pixels as a <see cref="Span{T}"/> of contiguous memory
/// at row <paramref name="rowIndex"/> beginning from the the first pixel on that row. /// at row <paramref name="rowIndex"/> beginning from the first pixel on that row.
/// </summary> /// </summary>
/// <typeparam name="TPixel">The type of the pixel.</typeparam> /// <typeparam name="TPixel">The type of the pixel.</typeparam>
/// <param name="source">The source.</param> /// <param name="source">The source.</param>
@ -154,8 +157,8 @@ namespace SixLabors.ImageSharp.Advanced
} }
/// <summary> /// <summary>
/// Gets the representation of the pixels as <see cref="Span{T}"/> of of contiguous memory /// Gets the representation of the pixels as <see cref="Span{T}"/> of contiguous memory
/// at row <paramref name="rowIndex"/> beginning from the the first pixel on that row. /// at row <paramref name="rowIndex"/> beginning from the first pixel on that row.
/// </summary> /// </summary>
/// <typeparam name="TPixel">The type of the pixel.</typeparam> /// <typeparam name="TPixel">The type of the pixel.</typeparam>
/// <param name="source">The source.</param> /// <param name="source">The source.</param>

5
src/ImageSharp/Advanced/PreserveAttribute.cs

@ -1,6 +1,8 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Six Labors Split License. // Licensed under the Six Labors Split License.
using System;
namespace SixLabors.ImageSharp.Advanced namespace SixLabors.ImageSharp.Advanced
{ {
/// <summary> /// <summary>
@ -8,7 +10,8 @@ namespace SixLabors.ImageSharp.Advanced
/// The only thing that matters is the class name. /// The only thing that matters is the class name.
/// There is no need to use or inherit from the PreserveAttribute class in each environment. /// There is no need to use or inherit from the PreserveAttribute class in each environment.
/// </summary> /// </summary>
internal sealed class PreserveAttribute : System.Attribute [AttributeUsage(AttributeTargets.Method)]
internal sealed class PreserveAttribute : Attribute
{ {
} }
} }

13
src/ImageSharp/Color/Color.cs

@ -151,7 +151,7 @@ namespace SixLabors.ImageSharp
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public static Color ParseHex(string hex) public static Color ParseHex(string hex)
{ {
var rgba = Rgba32.ParseHex(hex); Rgba32 rgba = Rgba32.ParseHex(hex);
return new Color(rgba); return new Color(rgba);
} }
@ -193,6 +193,7 @@ namespace SixLabors.ImageSharp
/// <returns> /// <returns>
/// The <see cref="Color"/>. /// The <see cref="Color"/>.
/// </returns> /// </returns>
/// <exception cref="ArgumentException">Input string is not in the correct format.</exception>
public static Color Parse(string input) public static Color Parse(string input)
{ {
Guard.NotNull(input, nameof(input)); Guard.NotNull(input, nameof(input));
@ -241,7 +242,7 @@ namespace SixLabors.ImageSharp
/// <returns>The color having it's alpha channel altered.</returns> /// <returns>The color having it's alpha channel altered.</returns>
public Color WithAlpha(float alpha) public Color WithAlpha(float alpha)
{ {
var v = (Vector4)this; Vector4 v = (Vector4)this;
v.W = alpha; v.W = alpha;
return new Color(v); return new Color(v);
} }
@ -290,12 +291,12 @@ namespace SixLabors.ImageSharp
/// <param name="source">The source color span.</param> /// <param name="source">The source color span.</param>
/// <param name="destination">The destination pixel span.</param> /// <param name="destination">The destination pixel span.</param>
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public static void ToPixel<TPixel>( #pragma warning disable RCS1163 // Unused parameter.
Configuration configuration, public static void ToPixel<TPixel>(Configuration configuration, ReadOnlySpan<Color> source, Span<TPixel> destination)
ReadOnlySpan<Color> source, #pragma warning restore RCS1163 // Unused parameter.
Span<TPixel> destination)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
// TODO: Investigate bulk operations utilizing configuration parameter here.
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
for (int i = 0; i < source.Length; i++) for (int i = 0; i < source.Length; i++)
{ {

60
src/ImageSharp/ColorSpaces/CieLab.cs

@ -1,4 +1,4 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Six Labors Split License. // Licensed under the Six Labors Split License.
using System; using System;
@ -19,29 +19,6 @@ namespace SixLabors.ImageSharp.ColorSpaces
/// </summary> /// </summary>
public static readonly CieXyz DefaultWhitePoint = Illuminants.D50; public static readonly CieXyz DefaultWhitePoint = Illuminants.D50;
/// <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;
/// <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;
/// <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;
/// <summary>
/// Gets the reference white point of this color
/// </summary>
public readonly CieXyz WhitePoint;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="CieLab"/> struct. /// Initializes a new instance of the <see cref="CieLab"/> struct.
/// </summary> /// </summary>
@ -95,6 +72,29 @@ namespace SixLabors.ImageSharp.ColorSpaces
this.WhitePoint = whitePoint; 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> /// <summary>
/// Compares two <see cref="CieLab"/> objects for equality. /// Compares two <see cref="CieLab"/> objects for equality.
/// </summary> /// </summary>
@ -128,12 +128,10 @@ namespace SixLabors.ImageSharp.ColorSpaces
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public bool Equals(CieLab other) public bool Equals(CieLab other) =>
{ this.L.Equals(other.L)
return this.L.Equals(other.L) && this.A.Equals(other.A)
&& this.A.Equals(other.A) && this.B.Equals(other.B)
&& this.B.Equals(other.B) && this.WhitePoint.Equals(other.WhitePoint);
&& this.WhitePoint.Equals(other.WhitePoint);
}
} }
} }

66
src/ImageSharp/ColorSpaces/CieLch.cs

@ -1,4 +1,4 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Six Labors Split License. // Licensed under the Six Labors Split License.
using System; using System;
@ -19,31 +19,8 @@ namespace SixLabors.ImageSharp.ColorSpaces
/// </summary> /// </summary>
public static readonly CieXyz DefaultWhitePoint = Illuminants.D50; public static readonly CieXyz DefaultWhitePoint = Illuminants.D50;
private static readonly Vector3 Min = new Vector3(0, -200, 0); private static readonly Vector3 Min = new(0, -200, 0);
private static readonly Vector3 Max = new Vector3(100, 200, 360); private static readonly Vector3 Max = new(100, 200, 360);
/// <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;
/// <summary>
/// Gets the a chroma component.
/// <remarks>A value ranging from 0 to 200.</remarks>
/// </summary>
public readonly float C;
/// <summary>
/// Gets the h° hue component in degrees.
/// <remarks>A value ranging from 0 to 360.</remarks>
/// </summary>
public readonly float H;
/// <summary>
/// Gets the reference white point of this color
/// </summary>
public readonly CieXyz WhitePoint;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="CieLch"/> struct. /// Initializes a new instance of the <see cref="CieLch"/> struct.
@ -97,6 +74,29 @@ namespace SixLabors.ImageSharp.ColorSpaces
this.WhitePoint = whitePoint; 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> /// <summary>
/// Compares two <see cref="CieLch"/> objects for equality. /// Compares two <see cref="CieLch"/> objects for equality.
/// </summary> /// </summary>
@ -121,9 +121,7 @@ namespace SixLabors.ImageSharp.ColorSpaces
/// <inheritdoc/> /// <inheritdoc/>
public override int GetHashCode() public override int GetHashCode()
{ => HashCode.Combine(this.L, this.C, this.H, this.WhitePoint);
return HashCode.Combine(this.L, this.C, this.H, this.WhitePoint);
}
/// <inheritdoc/> /// <inheritdoc/>
public override string ToString() => FormattableString.Invariant($"CieLch({this.L:#0.##}, {this.C:#0.##}, {this.H:#0.##})"); public override string ToString() => FormattableString.Invariant($"CieLch({this.L:#0.##}, {this.C:#0.##}, {this.H:#0.##})");
@ -135,12 +133,10 @@ namespace SixLabors.ImageSharp.ColorSpaces
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public bool Equals(CieLch other) public bool Equals(CieLch other)
{ => this.L.Equals(other.L)
return this.L.Equals(other.L) && this.C.Equals(other.C)
&& this.C.Equals(other.C) && this.H.Equals(other.H)
&& this.H.Equals(other.H) && this.WhitePoint.Equals(other.WhitePoint);
&& this.WhitePoint.Equals(other.WhitePoint);
}
/// <summary> /// <summary>
/// Computes the saturation of the color (chroma normalized by lightness) /// Computes the saturation of the color (chroma normalized by lightness)

62
src/ImageSharp/ColorSpaces/CieLchuv.cs

@ -1,4 +1,4 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Six Labors Split License. // Licensed under the Six Labors Split License.
using System; using System;
@ -13,8 +13,8 @@ namespace SixLabors.ImageSharp.ColorSpaces
/// </summary> /// </summary>
public readonly struct CieLchuv : IEquatable<CieLchuv> public readonly struct CieLchuv : IEquatable<CieLchuv>
{ {
private static readonly Vector3 Min = new Vector3(0, -200, 0); private static readonly Vector3 Min = new(0, -200, 0);
private static readonly Vector3 Max = new Vector3(100, 200, 360); private static readonly Vector3 Max = new(100, 200, 360);
/// <summary> /// <summary>
/// D50 standard illuminant. /// D50 standard illuminant.
@ -22,29 +22,6 @@ namespace SixLabors.ImageSharp.ColorSpaces
/// </summary> /// </summary>
public static readonly CieXyz DefaultWhitePoint = Illuminants.D65; public static readonly CieXyz DefaultWhitePoint = Illuminants.D65;
/// <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;
/// <summary>
/// Gets the a chroma component.
/// <remarks>A value ranging from 0 to 200.</remarks>
/// </summary>
public readonly float C;
/// <summary>
/// Gets the h° hue component in degrees.
/// <remarks>A value ranging from 0 to 360.</remarks>
/// </summary>
public readonly float H;
/// <summary>
/// Gets the reference white point of this color
/// </summary>
public readonly CieXyz WhitePoint;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="CieLchuv"/> struct. /// Initializes a new instance of the <see cref="CieLchuv"/> struct.
/// </summary> /// </summary>
@ -98,6 +75,29 @@ namespace SixLabors.ImageSharp.ColorSpaces
this.WhitePoint = whitePoint; 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> /// <summary>
/// Compares two <see cref="CieLchuv"/> objects for equality. /// Compares two <see cref="CieLchuv"/> objects for equality.
/// </summary> /// </summary>
@ -130,12 +130,10 @@ namespace SixLabors.ImageSharp.ColorSpaces
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public bool Equals(CieLchuv other) public bool Equals(CieLchuv other)
{ => this.L.Equals(other.L)
return this.L.Equals(other.L) && this.C.Equals(other.C)
&& this.C.Equals(other.C) && this.H.Equals(other.H)
&& this.H.Equals(other.H) && this.WhitePoint.Equals(other.WhitePoint);
&& this.WhitePoint.Equals(other.WhitePoint);
}
/// <summary> /// <summary>
/// Computes the saturation of the color (chroma normalized by lightness) /// Computes the saturation of the color (chroma normalized by lightness)

58
src/ImageSharp/ColorSpaces/CieLuv.cs

@ -1,4 +1,4 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Six Labors Split License. // Licensed under the Six Labors Split License.
using System; using System;
@ -21,29 +21,6 @@ namespace SixLabors.ImageSharp.ColorSpaces
/// </summary> /// </summary>
public static readonly CieXyz DefaultWhitePoint = Illuminants.D65; public static readonly CieXyz DefaultWhitePoint = Illuminants.D65;
/// <summary>
/// Gets the lightness dimension
/// <remarks>A value usually ranging between 0 and 100.</remarks>
/// </summary>
public readonly float L;
/// <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;
/// <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;
/// <summary>
/// Gets the reference white point of this color
/// </summary>
public readonly CieXyz WhitePoint;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="CieLuv"/> struct. /// Initializes a new instance of the <see cref="CieLuv"/> struct.
/// </summary> /// </summary>
@ -96,6 +73,29 @@ namespace SixLabors.ImageSharp.ColorSpaces
this.WhitePoint = whitePoint; 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> /// <summary>
/// Compares two <see cref="CieLuv"/> objects for equality. /// Compares two <see cref="CieLuv"/> objects for equality.
/// </summary> /// </summary>
@ -130,11 +130,9 @@ namespace SixLabors.ImageSharp.ColorSpaces
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public bool Equals(CieLuv other) public bool Equals(CieLuv other)
{ => this.L.Equals(other.L)
return this.L.Equals(other.L) && this.U.Equals(other.U)
&& this.U.Equals(other.U) && this.V.Equals(other.V)
&& this.V.Equals(other.V) && this.WhitePoint.Equals(other.WhitePoint);
&& this.WhitePoint.Equals(other.WhitePoint);
}
} }
} }

46
src/ImageSharp/ColorSpaces/CieXyy.cs

@ -1,4 +1,4 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Six Labors Split License. // Licensed under the Six Labors Split License.
using System; using System;
@ -13,24 +13,6 @@ namespace SixLabors.ImageSharp.ColorSpaces
/// </summary> /// </summary>
public readonly struct CieXyy : IEquatable<CieXyy> public readonly struct CieXyy : IEquatable<CieXyy>
{ {
/// <summary>
/// Gets the X chrominance component.
/// <remarks>A value usually ranging between 0 and 1.</remarks>
/// </summary>
public readonly float X;
/// <summary>
/// Gets the Y chrominance component.
/// <remarks>A value usually ranging between 0 and 1.</remarks>
/// </summary>
public readonly float Y;
/// <summary>
/// Gets the Y luminance component.
/// <remarks>A value usually ranging between 0 and 1.</remarks>
/// </summary>
public readonly float Yl;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="CieXyy"/> struct. /// Initializes a new instance of the <see cref="CieXyy"/> struct.
/// </summary> /// </summary>
@ -60,6 +42,24 @@ namespace SixLabors.ImageSharp.ColorSpaces
this.Yl = vector.Z; this.Yl = vector.Z;
} }
/// <summary>
/// Gets the X chrominance component.
/// <remarks>A value usually ranging between 0 and 1.</remarks>
/// </summary>
public readonly 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; }
/// <summary>
/// Gets the Y luminance component.
/// <remarks>A value usually ranging between 0 and 1.</remarks>
/// </summary>
public readonly float Yl { get; }
/// <summary> /// <summary>
/// Compares two <see cref="CieXyy"/> objects for equality. /// Compares two <see cref="CieXyy"/> objects for equality.
/// </summary> /// </summary>
@ -94,10 +94,8 @@ namespace SixLabors.ImageSharp.ColorSpaces
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public bool Equals(CieXyy other) public bool Equals(CieXyy other)
{ => this.X.Equals(other.X)
return this.X.Equals(other.X) && this.Y.Equals(other.Y)
&& this.Y.Equals(other.Y) && this.Yl.Equals(other.Yl);
&& this.Yl.Equals(other.Yl);
}
} }
} }

48
src/ImageSharp/ColorSpaces/CieXyz.cs

@ -1,4 +1,4 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Six Labors Split License. // Licensed under the Six Labors Split License.
using System; using System;
@ -13,24 +13,6 @@ namespace SixLabors.ImageSharp.ColorSpaces
/// </summary> /// </summary>
public readonly struct CieXyz : IEquatable<CieXyz> public readonly struct CieXyz : IEquatable<CieXyz>
{ {
/// <summary>
/// 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;
/// <summary>
/// Gets the Y luminance component.
/// <remarks>A value usually ranging between 0 and 1.</remarks>
/// </summary>
public readonly float Y;
/// <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;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="CieXyz"/> struct. /// Initializes a new instance of the <see cref="CieXyz"/> struct.
/// </summary> /// </summary>
@ -56,6 +38,24 @@ namespace SixLabors.ImageSharp.ColorSpaces
this.Z = vector.Z; this.Z = vector.Z;
} }
/// <summary>
/// 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; }
/// <summary>
/// Gets the Y luminance component.
/// <remarks>A value usually ranging between 0 and 1.</remarks>
/// </summary>
public readonly 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; }
/// <summary> /// <summary>
/// Compares two <see cref="CieXyz"/> objects for equality. /// Compares two <see cref="CieXyz"/> objects for equality.
/// </summary> /// </summary>
@ -83,7 +83,7 @@ namespace SixLabors.ImageSharp.ColorSpaces
/// </summary> /// </summary>
/// <returns>The <see cref="Vector3"/>.</returns> /// <returns>The <see cref="Vector3"/>.</returns>
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public Vector3 ToVector3() => new Vector3(this.X, this.Y, this.Z); public Vector3 ToVector3() => new(this.X, this.Y, this.Z);
/// <inheritdoc/> /// <inheritdoc/>
public override int GetHashCode() => HashCode.Combine(this.X, this.Y, this.Z); public override int GetHashCode() => HashCode.Combine(this.X, this.Y, this.Z);
@ -97,10 +97,8 @@ namespace SixLabors.ImageSharp.ColorSpaces
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public bool Equals(CieXyz other) public bool Equals(CieXyz other)
{ => this.X.Equals(other.X)
return this.X.Equals(other.X) && this.Y.Equals(other.Y)
&& this.Y.Equals(other.Y) && this.Z.Equals(other.Z);
&& this.Z.Equals(other.Z);
}
} }
} }

60
src/ImageSharp/ColorSpaces/Cmyk.cs

@ -1,4 +1,4 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Six Labors Split License. // Licensed under the Six Labors Split License.
using System; using System;
@ -15,30 +15,6 @@ namespace SixLabors.ImageSharp.ColorSpaces
private static readonly Vector4 Min = Vector4.Zero; private static readonly Vector4 Min = Vector4.Zero;
private static readonly Vector4 Max = Vector4.One; private static readonly Vector4 Max = Vector4.One;
/// <summary>
/// Gets the cyan color component.
/// <remarks>A value ranging between 0 and 1.</remarks>
/// </summary>
public readonly float C;
/// <summary>
/// Gets the magenta color component.
/// <remarks>A value ranging between 0 and 1.</remarks>
/// </summary>
public readonly float M;
/// <summary>
/// Gets the yellow color component.
/// <remarks>A value ranging between 0 and 1.</remarks>
/// </summary>
public readonly float Y;
/// <summary>
/// Gets the keyline black color component.
/// <remarks>A value ranging between 0 and 1.</remarks>
/// </summary>
public readonly float K;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="Cmyk"/> struct. /// Initializes a new instance of the <see cref="Cmyk"/> struct.
/// </summary> /// </summary>
@ -66,6 +42,30 @@ namespace SixLabors.ImageSharp.ColorSpaces
this.K = vector.W; 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> /// <summary>
/// Compares two <see cref="Cmyk"/> objects for equality. /// Compares two <see cref="Cmyk"/> objects for equality.
/// </summary> /// </summary>
@ -101,11 +101,9 @@ namespace SixLabors.ImageSharp.ColorSpaces
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public bool Equals(Cmyk other) public bool Equals(Cmyk other)
{ => this.C.Equals(other.C)
return this.C.Equals(other.C) && this.M.Equals(other.M)
&& this.M.Equals(other.M) && this.Y.Equals(other.Y)
&& this.Y.Equals(other.Y) && this.K.Equals(other.K);
&& this.K.Equals(other.K);
}
} }
} }

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

@ -5,10 +5,8 @@ using System;
using System.Numerics; using System.Numerics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
#if SUPPORTS_RUNTIME_INTRINSICS
using System.Runtime.Intrinsics; using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.X86; using System.Runtime.Intrinsics.X86;
#endif
namespace SixLabors.ImageSharp.ColorSpaces.Companding namespace SixLabors.ImageSharp.ColorSpaces.Companding
{ {
@ -25,10 +23,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Companding
private const int Length = Scale + 2; // 256kb @ 16bit precision. private const int Length = Scale + 2; // 256kb @ 16bit precision.
private const int Scale = (1 << 16) - 1; private const int Scale = (1 << 16) - 1;
private static readonly Lazy<float[]> LazyCompressTable = new Lazy<float[]>( private static readonly Lazy<float[]> LazyCompressTable = new(
() => () =>
{ {
var result = new float[Length]; float[] result = new float[Length];
for (int i = 0; i < result.Length; i++) for (int i = 0; i < result.Length; i++)
{ {
@ -49,10 +47,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Companding
}, },
true); true);
private static readonly Lazy<float[]> LazyExpandTable = new Lazy<float[]>( private static readonly Lazy<float[]> LazyExpandTable = new(
() => () =>
{ {
var result = new float[Length]; float[] result = new float[Length];
for (int i = 0; i < result.Length; i++) for (int i = 0; i < result.Length; i++)
{ {
@ -84,7 +82,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Companding
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Expand(Span<Vector4> vectors) public static void Expand(Span<Vector4> vectors)
{ {
#if SUPPORTS_RUNTIME_INTRINSICS
if (Avx2.IsSupported && vectors.Length >= 2) if (Avx2.IsSupported && vectors.Length >= 2)
{ {
CompandAvx2(vectors, ExpandTable); CompandAvx2(vectors, ExpandTable);
@ -92,11 +89,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Companding
if (Numerics.Modulo2(vectors.Length) != 0) if (Numerics.Modulo2(vectors.Length) != 0)
{ {
// Vector4 fits neatly in pairs. Any overlap has to be equal to 1. // Vector4 fits neatly in pairs. Any overlap has to be equal to 1.
Expand(ref MemoryMarshal.GetReference(vectors.Slice(vectors.Length - 1))); Expand(ref MemoryMarshal.GetReference(vectors[^1..]));
} }
} }
else else
#endif
{ {
CompandScalar(vectors, ExpandTable); CompandScalar(vectors, ExpandTable);
} }
@ -109,7 +105,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Companding
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe void Compress(Span<Vector4> vectors) public static unsafe void Compress(Span<Vector4> vectors)
{ {
#if SUPPORTS_RUNTIME_INTRINSICS
if (Avx2.IsSupported && vectors.Length >= 2) if (Avx2.IsSupported && vectors.Length >= 2)
{ {
CompandAvx2(vectors, CompressTable); CompandAvx2(vectors, CompressTable);
@ -117,11 +112,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Companding
if (Numerics.Modulo2(vectors.Length) != 0) if (Numerics.Modulo2(vectors.Length) != 0)
{ {
// Vector4 fits neatly in pairs. Any overlap has to be equal to 1. // Vector4 fits neatly in pairs. Any overlap has to be equal to 1.
Compress(ref MemoryMarshal.GetReference(vectors.Slice(vectors.Length - 1))); Compress(ref MemoryMarshal.GetReference(vectors[^1..]));
} }
} }
else else
#endif
{ {
CompandScalar(vectors, CompressTable); CompandScalar(vectors, CompressTable);
} }
@ -171,8 +165,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Companding
public static float Compress(float channel) public static float Compress(float channel)
=> channel <= 0.0031308F ? 12.92F * channel : (1.055F * MathF.Pow(channel, 0.416666666666667F)) - 0.055F; => channel <= 0.0031308F ? 12.92F * channel : (1.055F * MathF.Pow(channel, 0.416666666666667F)) - 0.055F;
#if SUPPORTS_RUNTIME_INTRINSICS
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static unsafe void CompandAvx2(Span<Vector4> vectors, float[] table) private static unsafe void CompandAvx2(Span<Vector4> vectors, float[] table)
{ {
@ -204,7 +196,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Companding
} }
} }
} }
#endif
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static unsafe void CompandScalar(Span<Vector4> vectors, float[] table) private static unsafe void CompandScalar(Span<Vector4> vectors, float[] table)

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

@ -150,9 +150,9 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
return color; return color;
} }
var linearInput = this.ToLinearRgb(color); var linearInput = ToLinearRgb(color);
LinearRgb linearOutput = this.Adapt(linearInput); LinearRgb linearOutput = this.Adapt(linearInput);
return this.ToRgb(linearOutput); return ToRgb(linearOutput);
} }
} }
} }

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

@ -12,11 +12,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </content> /// </content>
public partial class ColorSpaceConverter public partial class ColorSpaceConverter
{ {
/// <summary>
/// The converter for converting between CieLch to CieLab.
/// </summary>
private static readonly CieLchToCieLabConverter CieLchToCieLabConverter = new CieLchToCieLabConverter();
/// <summary> /// <summary>
/// Converts a <see cref="CieLch"/> into a <see cref="CieLab"/>. /// Converts a <see cref="CieLch"/> into a <see cref="CieLab"/>.
/// </summary> /// </summary>
@ -58,7 +53,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="CieLab"/></returns> /// <returns>The <see cref="CieLab"/></returns>
public CieLab ToCieLab(in CieLchuv color) public CieLab ToCieLab(in CieLchuv color)
{ {
var xyzColor = this.ToCieXyz(color); CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLab(xyzColor); return this.ToCieLab(xyzColor);
} }
@ -91,7 +86,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="CieLab"/></returns> /// <returns>The <see cref="CieLab"/></returns>
public CieLab ToCieLab(in CieLuv color) public CieLab ToCieLab(in CieLuv color)
{ {
var xyzColor = this.ToCieXyz(color); CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLab(xyzColor); return this.ToCieLab(xyzColor);
} }
@ -124,7 +119,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="CieLab"/></returns> /// <returns>The <see cref="CieLab"/></returns>
public CieLab ToCieLab(in CieXyy color) public CieLab ToCieLab(in CieXyy color)
{ {
var xyzColor = this.ToCieXyz(color); CieXyz xyzColor = ToCieXyz(color);
return this.ToCieLab(xyzColor); return this.ToCieLab(xyzColor);
} }
@ -190,7 +185,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="CieLab"/></returns> /// <returns>The <see cref="CieLab"/></returns>
public CieLab ToCieLab(in Cmyk color) public CieLab ToCieLab(in Cmyk color)
{ {
var xyzColor = this.ToCieXyz(color); CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLab(xyzColor); return this.ToCieLab(xyzColor);
} }
@ -222,7 +217,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="CieLab"/></returns> /// <returns>The <see cref="CieLab"/></returns>
public CieLab ToCieLab(in Hsl color) public CieLab ToCieLab(in Hsl color)
{ {
var xyzColor = this.ToCieXyz(color); CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLab(xyzColor); return this.ToCieLab(xyzColor);
} }
@ -255,7 +250,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="CieLab"/></returns> /// <returns>The <see cref="CieLab"/></returns>
public CieLab ToCieLab(in Hsv color) public CieLab ToCieLab(in Hsv color)
{ {
var xyzColor = this.ToCieXyz(color); CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLab(xyzColor); return this.ToCieLab(xyzColor);
} }
@ -287,7 +282,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="CieLab"/></returns> /// <returns>The <see cref="CieLab"/></returns>
public CieLab ToCieLab(in HunterLab color) public CieLab ToCieLab(in HunterLab color)
{ {
var xyzColor = this.ToCieXyz(color); CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLab(xyzColor); return this.ToCieLab(xyzColor);
} }
@ -320,7 +315,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="CieLab"/></returns> /// <returns>The <see cref="CieLab"/></returns>
public CieLab ToCieLab(in Lms color) public CieLab ToCieLab(in Lms color)
{ {
var xyzColor = this.ToCieXyz(color); CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLab(xyzColor); return this.ToCieLab(xyzColor);
} }
@ -353,7 +348,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="CieLab"/></returns> /// <returns>The <see cref="CieLab"/></returns>
public CieLab ToCieLab(in LinearRgb color) public CieLab ToCieLab(in LinearRgb color)
{ {
var xyzColor = this.ToCieXyz(color); CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLab(xyzColor); return this.ToCieLab(xyzColor);
} }
@ -386,7 +381,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="CieLab"/></returns> /// <returns>The <see cref="CieLab"/></returns>
public CieLab ToCieLab(in Rgb color) public CieLab ToCieLab(in Rgb color)
{ {
var xyzColor = this.ToCieXyz(color); CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLab(xyzColor); return this.ToCieLab(xyzColor);
} }
@ -419,7 +414,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="CieLab"/></returns> /// <returns>The <see cref="CieLab"/></returns>
public CieLab ToCieLab(in YCbCr color) public CieLab ToCieLab(in YCbCr color)
{ {
var xyzColor = this.ToCieXyz(color); CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLab(xyzColor); return this.ToCieLab(xyzColor);
} }

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

@ -12,11 +12,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </content> /// </content>
public partial class ColorSpaceConverter public partial class ColorSpaceConverter
{ {
/// <summary>
/// The converter for converting between CieLab to CieLch.
/// </summary>
private static readonly CieLabToCieLchConverter CieLabToCieLchConverter = new CieLabToCieLchConverter();
/// <summary> /// <summary>
/// Converts a <see cref="CieLab"/> into a <see cref="CieLch"/> /// Converts a <see cref="CieLab"/> into a <see cref="CieLch"/>
/// </summary> /// </summary>
@ -123,7 +118,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="CieLch"/></returns> /// <returns>The <see cref="CieLch"/></returns>
public CieLch ToCieLch(in CieXyy color) public CieLch ToCieLch(in CieXyy color)
{ {
var xyzColor = this.ToCieXyz(color); var xyzColor = ToCieXyz(color);
return this.ToCieLch(xyzColor); return this.ToCieLch(xyzColor);
} }

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

@ -12,11 +12,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </content> /// </content>
public partial class ColorSpaceConverter public partial class ColorSpaceConverter
{ {
/// <summary>
/// The converter for converting between CieLab to CieLchuv.
/// </summary>
private static readonly CieLuvToCieLchuvConverter CieLuvToCieLchuvConverter = new CieLuvToCieLchuvConverter();
/// <summary> /// <summary>
/// Converts a <see cref="CieLab"/> into a <see cref="CieLchuv"/> /// Converts a <see cref="CieLab"/> into a <see cref="CieLchuv"/>
/// </summary> /// </summary>
@ -24,7 +19,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="CieLchuv"/></returns> /// <returns>The <see cref="CieLchuv"/></returns>
public CieLchuv ToCieLchuv(in CieLab color) public CieLchuv ToCieLchuv(in CieLab color)
{ {
var xyzColor = this.ToCieXyz(color); CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLchuv(xyzColor); return this.ToCieLchuv(xyzColor);
} }
@ -57,7 +52,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="CieLchuv"/></returns> /// <returns>The <see cref="CieLchuv"/></returns>
public CieLchuv ToCieLchuv(in CieLch color) public CieLchuv ToCieLchuv(in CieLch color)
{ {
var xyzColor = this.ToCieXyz(color); CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLchuv(xyzColor); return this.ToCieLchuv(xyzColor);
} }
@ -123,7 +118,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="CieLchuv"/></returns> /// <returns>The <see cref="CieLchuv"/></returns>
public CieLchuv ToCieLchuv(in CieXyy color) public CieLchuv ToCieLchuv(in CieXyy color)
{ {
var xyzColor = this.ToCieXyz(color); CieXyz xyzColor = ToCieXyz(color);
return this.ToCieLchuv(xyzColor); return this.ToCieLchuv(xyzColor);
} }
@ -156,7 +151,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="CieLchuv"/></returns> /// <returns>The <see cref="CieLchuv"/></returns>
public CieLchuv ToCieLchuv(in CieXyz color) public CieLchuv ToCieLchuv(in CieXyz color)
{ {
var luvColor = this.ToCieLuv(color); CieLuv luvColor = this.ToCieLuv(color);
return this.ToCieLchuv(luvColor); return this.ToCieLchuv(luvColor);
} }
@ -189,7 +184,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="CieLchuv"/></returns> /// <returns>The <see cref="CieLchuv"/></returns>
public CieLchuv ToCieLchuv(in Cmyk color) public CieLchuv ToCieLchuv(in Cmyk color)
{ {
var xyzColor = this.ToCieXyz(color); CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLchuv(xyzColor); return this.ToCieLchuv(xyzColor);
} }
@ -222,7 +217,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="CieLchuv"/></returns> /// <returns>The <see cref="CieLchuv"/></returns>
public CieLchuv ToCieLchuv(in Hsl color) public CieLchuv ToCieLchuv(in Hsl color)
{ {
var xyzColor = this.ToCieXyz(color); CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLchuv(xyzColor); return this.ToCieLchuv(xyzColor);
} }
@ -255,7 +250,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="CieLchuv"/></returns> /// <returns>The <see cref="CieLchuv"/></returns>
public CieLchuv ToCieLchuv(in Hsv color) public CieLchuv ToCieLchuv(in Hsv color)
{ {
var xyzColor = this.ToCieXyz(color); CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLchuv(xyzColor); return this.ToCieLchuv(xyzColor);
} }
@ -288,7 +283,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="CieLchuv"/></returns> /// <returns>The <see cref="CieLchuv"/></returns>
public CieLchuv ToCieLchuv(in HunterLab color) public CieLchuv ToCieLchuv(in HunterLab color)
{ {
var xyzColor = this.ToCieXyz(color); CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLchuv(xyzColor); return this.ToCieLchuv(xyzColor);
} }
@ -321,7 +316,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="CieLchuv"/></returns> /// <returns>The <see cref="CieLchuv"/></returns>
public CieLchuv ToCieLchuv(in LinearRgb color) public CieLchuv ToCieLchuv(in LinearRgb color)
{ {
var xyzColor = this.ToCieXyz(color); CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLchuv(xyzColor); return this.ToCieLchuv(xyzColor);
} }
@ -354,7 +349,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="CieLchuv"/></returns> /// <returns>The <see cref="CieLchuv"/></returns>
public CieLchuv ToCieLchuv(in Lms color) public CieLchuv ToCieLchuv(in Lms color)
{ {
var xyzColor = this.ToCieXyz(color); CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLchuv(xyzColor); return this.ToCieLchuv(xyzColor);
} }
@ -387,7 +382,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="CieLchuv"/></returns> /// <returns>The <see cref="CieLchuv"/></returns>
public CieLchuv ToCieLchuv(in Rgb color) public CieLchuv ToCieLchuv(in Rgb color)
{ {
var xyzColor = this.ToCieXyz(color); CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLchuv(xyzColor); return this.ToCieLchuv(xyzColor);
} }
@ -420,7 +415,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="CieLchuv"/></returns> /// <returns>The <see cref="CieLchuv"/></returns>
public CieLchuv ToCieLchuv(in YCbCr color) public CieLchuv ToCieLchuv(in YCbCr color)
{ {
var xyzColor = this.ToCieXyz(color); CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLchuv(xyzColor); return this.ToCieLchuv(xyzColor);
} }

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

@ -12,8 +12,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </content> /// </content>
public partial class ColorSpaceConverter public partial class ColorSpaceConverter
{ {
private static readonly CieLchuvToCieLuvConverter CieLchuvToCieLuvConverter = new CieLchuvToCieLuvConverter();
/// <summary> /// <summary>
/// Converts a <see cref="CieLab"/> into a <see cref="CieLuv"/>. /// Converts a <see cref="CieLab"/> into a <see cref="CieLuv"/>.
/// </summary> /// </summary>
@ -21,7 +19,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="CieLuv"/></returns> /// <returns>The <see cref="CieLuv"/></returns>
public CieLuv ToCieLuv(in CieLab color) public CieLuv ToCieLuv(in CieLab color)
{ {
var xyzColor = this.ToCieXyz(color); CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLuv(xyzColor); return this.ToCieLuv(xyzColor);
} }
@ -53,7 +51,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="CieLuv"/></returns> /// <returns>The <see cref="CieLuv"/></returns>
public CieLuv ToCieLuv(in CieLch color) public CieLuv ToCieLuv(in CieLch color)
{ {
var xyzColor = this.ToCieXyz(color); CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLuv(xyzColor); return this.ToCieLuv(xyzColor);
} }
@ -120,7 +118,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="CieLuv"/></returns> /// <returns>The <see cref="CieLuv"/></returns>
public CieLuv ToCieLuv(in CieXyy color) public CieLuv ToCieLuv(in CieXyy color)
{ {
var xyzColor = this.ToCieXyz(color); CieXyz xyzColor = ToCieXyz(color);
return this.ToCieLuv(xyzColor); return this.ToCieLuv(xyzColor);
} }
@ -187,7 +185,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="CieLuv"/></returns> /// <returns>The <see cref="CieLuv"/></returns>
public CieLuv ToCieLuv(in Cmyk color) public CieLuv ToCieLuv(in Cmyk color)
{ {
var xyzColor = this.ToCieXyz(color); CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLuv(xyzColor); return this.ToCieLuv(xyzColor);
} }
@ -219,7 +217,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="CieLuv"/></returns> /// <returns>The <see cref="CieLuv"/></returns>
public CieLuv ToCieLuv(in Hsl color) public CieLuv ToCieLuv(in Hsl color)
{ {
var xyzColor = this.ToCieXyz(color); CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLuv(xyzColor); return this.ToCieLuv(xyzColor);
} }
@ -251,7 +249,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="CieLuv"/></returns> /// <returns>The <see cref="CieLuv"/></returns>
public CieLuv ToCieLuv(in Hsv color) public CieLuv ToCieLuv(in Hsv color)
{ {
var xyzColor = this.ToCieXyz(color); CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLuv(xyzColor); return this.ToCieLuv(xyzColor);
} }
@ -283,7 +281,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="CieLuv"/></returns> /// <returns>The <see cref="CieLuv"/></returns>
public CieLuv ToCieLuv(in HunterLab color) public CieLuv ToCieLuv(in HunterLab color)
{ {
var xyzColor = this.ToCieXyz(color); CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLuv(xyzColor); return this.ToCieLuv(xyzColor);
} }
@ -315,7 +313,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="CieLuv"/></returns> /// <returns>The <see cref="CieLuv"/></returns>
public CieLuv ToCieLuv(in Lms color) public CieLuv ToCieLuv(in Lms color)
{ {
var xyzColor = this.ToCieXyz(color); CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLuv(xyzColor); return this.ToCieLuv(xyzColor);
} }
@ -347,7 +345,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="CieLuv"/></returns> /// <returns>The <see cref="CieLuv"/></returns>
public CieLuv ToCieLuv(in LinearRgb color) public CieLuv ToCieLuv(in LinearRgb color)
{ {
var xyzColor = this.ToCieXyz(color); CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLuv(xyzColor); return this.ToCieLuv(xyzColor);
} }
@ -379,7 +377,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="CieLuv"/></returns> /// <returns>The <see cref="CieLuv"/></returns>
public CieLuv ToCieLuv(in Rgb color) public CieLuv ToCieLuv(in Rgb color)
{ {
var xyzColor = this.ToCieXyz(color); CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLuv(xyzColor); return this.ToCieLuv(xyzColor);
} }
@ -411,7 +409,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="CieLuv"/></returns> /// <returns>The <see cref="CieLuv"/></returns>
public CieLuv ToCieLuv(in YCbCr color) public CieLuv ToCieLuv(in YCbCr color)
{ {
var xyzColor = this.ToCieXyz(color); CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLuv(xyzColor); return this.ToCieLuv(xyzColor);
} }

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

@ -12,8 +12,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </content> /// </content>
public partial class ColorSpaceConverter public partial class ColorSpaceConverter
{ {
private static readonly CieXyzAndCieXyyConverter CieXyzAndCieXyyConverter = new CieXyzAndCieXyyConverter();
/// <summary> /// <summary>
/// Converts a <see cref="CieLab"/> into a <see cref="CieXyy"/> /// Converts a <see cref="CieLab"/> into a <see cref="CieXyy"/>
/// </summary> /// </summary>
@ -21,9 +19,9 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="CieXyy"/></returns> /// <returns>The <see cref="CieXyy"/></returns>
public CieXyy ToCieXyy(in CieLab color) public CieXyy ToCieXyy(in CieLab color)
{ {
var xyzColor = this.ToCieXyz(color); CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieXyy(xyzColor); return ToCieXyy(xyzColor);
} }
/// <summary> /// <summary>
@ -54,9 +52,9 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="CieXyy"/></returns> /// <returns>The <see cref="CieXyy"/></returns>
public CieXyy ToCieXyy(in CieLch color) public CieXyy ToCieXyy(in CieLch color)
{ {
var xyzColor = this.ToCieXyz(color); CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieXyy(xyzColor); return ToCieXyy(xyzColor);
} }
/// <summary> /// <summary>
@ -87,9 +85,9 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="CieXyy"/></returns> /// <returns>The <see cref="CieXyy"/></returns>
public CieXyy ToCieXyy(in CieLchuv color) public CieXyy ToCieXyy(in CieLchuv color)
{ {
var xyzColor = this.ToCieXyz(color); CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieXyy(xyzColor); return ToCieXyy(xyzColor);
} }
/// <summary> /// <summary>
@ -120,9 +118,9 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="CieXyy"/></returns> /// <returns>The <see cref="CieXyy"/></returns>
public CieXyy ToCieXyy(in CieLuv color) public CieXyy ToCieXyy(in CieLuv color)
{ {
var xyzColor = this.ToCieXyz(color); CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieXyy(xyzColor); return ToCieXyy(xyzColor);
} }
/// <summary> /// <summary>
@ -151,14 +149,14 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary> /// </summary>
/// <param name="color">The color to convert.</param> /// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieXyy"/></returns> /// <returns>The <see cref="CieXyy"/></returns>
public CieXyy ToCieXyy(in CieXyz color) => CieXyzAndCieXyyConverter.Convert(color); public static CieXyy ToCieXyy(in CieXyz color) => CieXyzAndCieXyyConverter.Convert(color);
/// <summary> /// <summary>
/// Performs the bulk conversion from <see cref="CieXyz"/> into <see cref="CieXyy"/> /// Performs the bulk conversion from <see cref="CieXyz"/> into <see cref="CieXyy"/>
/// </summary> /// </summary>
/// <param name="source">The span to the source colors</param> /// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param> /// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieXyz> source, Span<CieXyy> destination) public static void Convert(ReadOnlySpan<CieXyz> source, Span<CieXyy> destination)
{ {
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length; int count = source.Length;
@ -170,7 +168,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
{ {
ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i); ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i);
ref CieXyy dp = ref Unsafe.Add(ref destRef, i); ref CieXyy dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieXyy(sp); dp = ToCieXyy(sp);
} }
} }
@ -181,9 +179,9 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="CieXyy"/></returns> /// <returns>The <see cref="CieXyy"/></returns>
public CieXyy ToCieXyy(in Cmyk color) public CieXyy ToCieXyy(in Cmyk color)
{ {
var xyzColor = this.ToCieXyz(color); CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieXyy(xyzColor); return ToCieXyy(xyzColor);
} }
/// <summary> /// <summary>
@ -214,9 +212,9 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="CieXyy"/></returns> /// <returns>The <see cref="CieXyy"/></returns>
public CieXyy ToCieXyy(Hsl color) public CieXyy ToCieXyy(Hsl color)
{ {
var xyzColor = this.ToCieXyz(color); CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieXyy(xyzColor); return ToCieXyy(xyzColor);
} }
/// <summary> /// <summary>
@ -247,9 +245,9 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="CieXyy"/></returns> /// <returns>The <see cref="CieXyy"/></returns>
public CieXyy ToCieXyy(in Hsv color) public CieXyy ToCieXyy(in Hsv color)
{ {
var xyzColor = this.ToCieXyz(color); CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieXyy(xyzColor); return ToCieXyy(xyzColor);
} }
/// <summary> /// <summary>
@ -280,9 +278,9 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="CieXyy"/></returns> /// <returns>The <see cref="CieXyy"/></returns>
public CieXyy ToCieXyy(in HunterLab color) public CieXyy ToCieXyy(in HunterLab color)
{ {
var xyzColor = this.ToCieXyz(color); CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieXyy(xyzColor); return ToCieXyy(xyzColor);
} }
/// <summary> /// <summary>
@ -313,9 +311,9 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="CieXyy"/></returns> /// <returns>The <see cref="CieXyy"/></returns>
public CieXyy ToCieXyy(in LinearRgb color) public CieXyy ToCieXyy(in LinearRgb color)
{ {
var xyzColor = this.ToCieXyz(color); CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieXyy(xyzColor); return ToCieXyy(xyzColor);
} }
/// <summary> /// <summary>
@ -346,9 +344,9 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="CieXyy"/></returns> /// <returns>The <see cref="CieXyy"/></returns>
public CieXyy ToCieXyy(in Lms color) public CieXyy ToCieXyy(in Lms color)
{ {
var xyzColor = this.ToCieXyz(color); CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieXyy(xyzColor); return ToCieXyy(xyzColor);
} }
/// <summary> /// <summary>
@ -379,9 +377,9 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="CieXyy"/></returns> /// <returns>The <see cref="CieXyy"/></returns>
public CieXyy ToCieXyy(in Rgb color) public CieXyy ToCieXyy(in Rgb color)
{ {
var xyzColor = this.ToCieXyz(color); CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieXyy(xyzColor); return ToCieXyy(xyzColor);
} }
/// <summary> /// <summary>
@ -412,9 +410,9 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="CieXyy"/></returns> /// <returns>The <see cref="CieXyy"/></returns>
public CieXyy ToCieXyy(in YCbCr color) public CieXyy ToCieXyy(in YCbCr color)
{ {
var xyzColor = this.ToCieXyz(color); CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieXyy(xyzColor); return ToCieXyy(xyzColor);
} }
/// <summary> /// <summary>

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

@ -12,12 +12,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </content> /// </content>
public partial class ColorSpaceConverter public partial class ColorSpaceConverter
{ {
private static readonly CieLabToCieXyzConverter CieLabToCieXyzConverter = new CieLabToCieXyzConverter(); private static readonly HunterLabToCieXyzConverter HunterLabToCieXyzConverter = new();
private static readonly CieLuvToCieXyzConverter CieLuvToCieXyzConverter = new CieLuvToCieXyzConverter();
private static readonly HunterLabToCieXyzConverter
HunterLabToCieXyzConverter = new HunterLabToCieXyzConverter();
private LinearRgbToCieXyzConverter linearRgbToCieXyzConverter; private LinearRgbToCieXyzConverter linearRgbToCieXyzConverter;
@ -166,18 +161,17 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary> /// </summary>
/// <param name="color">The color to convert.</param> /// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieXyz"/></returns> /// <returns>The <see cref="CieXyz"/></returns>
public CieXyz ToCieXyz(in CieXyy color) public static CieXyz ToCieXyz(in CieXyy color)
{
// Conversion // Conversion
return CieXyzAndCieXyyConverter.Convert(color); => CieXyzAndCieXyyConverter.Convert(color);
}
/// <summary> /// <summary>
/// Performs the bulk conversion from <see cref="CieXyy"/> into <see cref="CieXyz"/>. /// Performs the bulk conversion from <see cref="CieXyy"/> into <see cref="CieXyz"/>.
/// </summary> /// </summary>
/// <param name="source">The span to the source colors</param> /// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param> /// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieXyy> source, Span<CieXyz> destination) public static void Convert(ReadOnlySpan<CieXyy> source, Span<CieXyz> destination)
{ {
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length; int count = source.Length;
@ -189,7 +183,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
{ {
ref CieXyy sp = ref Unsafe.Add(ref sourceRef, i); ref CieXyy sp = ref Unsafe.Add(ref sourceRef, i);
ref CieXyz dp = ref Unsafe.Add(ref destRef, i); ref CieXyz dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieXyz(sp); dp = ToCieXyz(sp);
} }
} }
@ -200,7 +194,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="CieXyz"/></returns> /// <returns>The <see cref="CieXyz"/></returns>
public CieXyz ToCieXyz(in Cmyk color) public CieXyz ToCieXyz(in Cmyk color)
{ {
var rgb = this.ToRgb(color); Rgb rgb = ToRgb(color);
return this.ToCieXyz(rgb); return this.ToCieXyz(rgb);
} }
@ -233,7 +227,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="CieXyz"/></returns> /// <returns>The <see cref="CieXyz"/></returns>
public CieXyz ToCieXyz(in Hsl color) public CieXyz ToCieXyz(in Hsl color)
{ {
var rgb = this.ToRgb(color); Rgb rgb = ToRgb(color);
return this.ToCieXyz(rgb); return this.ToCieXyz(rgb);
} }
@ -267,7 +261,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
public CieXyz ToCieXyz(in Hsv color) public CieXyz ToCieXyz(in Hsv color)
{ {
// Conversion // Conversion
var rgb = this.ToRgb(color); Rgb rgb = ToRgb(color);
return this.ToCieXyz(rgb); return this.ToCieXyz(rgb);
} }
@ -367,9 +361,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <param name="color">The color to convert.</param> /// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieXyz"/></returns> /// <returns>The <see cref="CieXyz"/></returns>
public CieXyz ToCieXyz(in Lms color) public CieXyz ToCieXyz(in Lms color)
{ => this.cieXyzAndLmsConverter.Convert(color);
return this.cieXyzAndLmsConverter.Convert(color);
}
/// <summary> /// <summary>
/// Performs the bulk conversion from <see cref="Lms"/> into <see cref="CieXyz"/>. /// Performs the bulk conversion from <see cref="Lms"/> into <see cref="CieXyz"/>.
@ -432,7 +424,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="CieXyz"/></returns> /// <returns>The <see cref="CieXyz"/></returns>
public CieXyz ToCieXyz(in YCbCr color) public CieXyz ToCieXyz(in YCbCr color)
{ {
var rgb = this.ToRgb(color); Rgb rgb = this.ToRgb(color);
return this.ToCieXyz(rgb); return this.ToCieXyz(rgb);
} }

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

@ -12,8 +12,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </content> /// </content>
public partial class ColorSpaceConverter public partial class ColorSpaceConverter
{ {
private static readonly CmykAndRgbConverter CmykAndRgbConverter = new CmykAndRgbConverter();
/// <summary> /// <summary>
/// Converts a <see cref="CieLab"/> into a <see cref="Cmyk"/>. /// Converts a <see cref="CieLab"/> into a <see cref="Cmyk"/>.
/// </summary> /// </summary>
@ -21,7 +19,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="Cmyk"/></returns> /// <returns>The <see cref="Cmyk"/></returns>
public Cmyk ToCmyk(in CieLab color) public Cmyk ToCmyk(in CieLab color)
{ {
var xyzColor = this.ToCieXyz(color); CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCmyk(xyzColor); return this.ToCmyk(xyzColor);
} }
@ -54,7 +52,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="Cmyk"/></returns> /// <returns>The <see cref="Cmyk"/></returns>
public Cmyk ToCmyk(in CieLch color) public Cmyk ToCmyk(in CieLch color)
{ {
var xyzColor = this.ToCieXyz(color); CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCmyk(xyzColor); return this.ToCmyk(xyzColor);
} }
@ -87,7 +85,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="Cmyk"/></returns> /// <returns>The <see cref="Cmyk"/></returns>
public Cmyk ToCmyk(in CieLchuv color) public Cmyk ToCmyk(in CieLchuv color)
{ {
var xyzColor = this.ToCieXyz(color); CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCmyk(xyzColor); return this.ToCmyk(xyzColor);
} }
@ -120,7 +118,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="Cmyk"/></returns> /// <returns>The <see cref="Cmyk"/></returns>
public Cmyk ToCmyk(in CieLuv color) public Cmyk ToCmyk(in CieLuv color)
{ {
var xyzColor = this.ToCieXyz(color); CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCmyk(xyzColor); return this.ToCmyk(xyzColor);
} }
@ -153,7 +151,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="Cmyk"/></returns> /// <returns>The <see cref="Cmyk"/></returns>
public Cmyk ToCmyk(in CieXyy color) public Cmyk ToCmyk(in CieXyy color)
{ {
var xyzColor = this.ToCieXyz(color); CieXyz xyzColor = ToCieXyz(color);
return this.ToCmyk(xyzColor); return this.ToCmyk(xyzColor);
} }
@ -186,7 +184,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="Cmyk"/></returns> /// <returns>The <see cref="Cmyk"/></returns>
public Cmyk ToCmyk(in CieXyz color) public Cmyk ToCmyk(in CieXyz color)
{ {
var rgb = this.ToRgb(color); Rgb rgb = this.ToRgb(color);
return CmykAndRgbConverter.Convert(rgb); return CmykAndRgbConverter.Convert(rgb);
} }
@ -217,9 +215,9 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary> /// </summary>
/// <param name="color">The color to convert.</param> /// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Cmyk"/></returns> /// <returns>The <see cref="Cmyk"/></returns>
public Cmyk ToCmyk(in Hsl color) public static Cmyk ToCmyk(in Hsl color)
{ {
var rgb = this.ToRgb(color); Rgb rgb = ToRgb(color);
return CmykAndRgbConverter.Convert(rgb); return CmykAndRgbConverter.Convert(rgb);
} }
@ -229,7 +227,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary> /// </summary>
/// <param name="source">The span to the source colors</param> /// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param> /// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Hsl> source, Span<Cmyk> destination) public static void Convert(ReadOnlySpan<Hsl> source, Span<Cmyk> destination)
{ {
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length; int count = source.Length;
@ -241,7 +239,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
{ {
ref Hsl sp = ref Unsafe.Add(ref sourceRef, i); ref Hsl sp = ref Unsafe.Add(ref sourceRef, i);
ref Cmyk dp = ref Unsafe.Add(ref destRef, i); ref Cmyk dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCmyk(sp); dp = ToCmyk(sp);
} }
} }
@ -250,9 +248,9 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary> /// </summary>
/// <param name="color">The color to convert.</param> /// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Cmyk"/></returns> /// <returns>The <see cref="Cmyk"/></returns>
public Cmyk ToCmyk(in Hsv color) public static Cmyk ToCmyk(in Hsv color)
{ {
var rgb = this.ToRgb(color); Rgb rgb = ToRgb(color);
return CmykAndRgbConverter.Convert(rgb); return CmykAndRgbConverter.Convert(rgb);
} }
@ -262,7 +260,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary> /// </summary>
/// <param name="source">The span to the source colors</param> /// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param> /// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Hsv> source, Span<Cmyk> destination) public static void Convert(ReadOnlySpan<Hsv> source, Span<Cmyk> destination)
{ {
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length; int count = source.Length;
@ -274,7 +272,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
{ {
ref Hsv sp = ref Unsafe.Add(ref sourceRef, i); ref Hsv sp = ref Unsafe.Add(ref sourceRef, i);
ref Cmyk dp = ref Unsafe.Add(ref destRef, i); ref Cmyk dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCmyk(sp); dp = ToCmyk(sp);
} }
} }
@ -285,7 +283,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="Cmyk"/></returns> /// <returns>The <see cref="Cmyk"/></returns>
public Cmyk ToCmyk(in HunterLab color) public Cmyk ToCmyk(in HunterLab color)
{ {
var xyzColor = this.ToCieXyz(color); CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCmyk(xyzColor); return this.ToCmyk(xyzColor);
} }
@ -316,9 +314,9 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary> /// </summary>
/// <param name="color">The color to convert.</param> /// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Cmyk"/></returns> /// <returns>The <see cref="Cmyk"/></returns>
public Cmyk ToCmyk(in LinearRgb color) public static Cmyk ToCmyk(in LinearRgb color)
{ {
var rgb = this.ToRgb(color); Rgb rgb = ToRgb(color);
return CmykAndRgbConverter.Convert(rgb); return CmykAndRgbConverter.Convert(rgb);
} }
@ -328,7 +326,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary> /// </summary>
/// <param name="source">The span to the source colors</param> /// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param> /// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<LinearRgb> source, Span<Cmyk> destination) public static void Convert(ReadOnlySpan<LinearRgb> source, Span<Cmyk> destination)
{ {
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length; int count = source.Length;
@ -340,7 +338,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
{ {
ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i); ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i);
ref Cmyk dp = ref Unsafe.Add(ref destRef, i); ref Cmyk dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCmyk(sp); dp = ToCmyk(sp);
} }
} }
@ -351,7 +349,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="Cmyk"/></returns> /// <returns>The <see cref="Cmyk"/></returns>
public Cmyk ToCmyk(in Lms color) public Cmyk ToCmyk(in Lms color)
{ {
var xyzColor = this.ToCieXyz(color); CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCmyk(xyzColor); return this.ToCmyk(xyzColor);
} }
@ -382,14 +380,14 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary> /// </summary>
/// <param name="color">The color to convert.</param> /// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Cmyk"/></returns> /// <returns>The <see cref="Cmyk"/></returns>
public Cmyk ToCmyk(in Rgb color) => CmykAndRgbConverter.Convert(color); public static Cmyk ToCmyk(in Rgb color) => CmykAndRgbConverter.Convert(color);
/// <summary> /// <summary>
/// Performs the bulk conversion from <see cref="Rgb"/> into <see cref="Cmyk"/> /// Performs the bulk conversion from <see cref="Rgb"/> into <see cref="Cmyk"/>
/// </summary> /// </summary>
/// <param name="source">The span to the source colors</param> /// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param> /// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Rgb> source, Span<Cmyk> destination) public static void Convert(ReadOnlySpan<Rgb> source, Span<Cmyk> destination)
{ {
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length; int count = source.Length;
@ -401,7 +399,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
{ {
ref Rgb sp = ref Unsafe.Add(ref sourceRef, i); ref Rgb sp = ref Unsafe.Add(ref sourceRef, i);
ref Cmyk dp = ref Unsafe.Add(ref destRef, i); ref Cmyk dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCmyk(sp); dp = ToCmyk(sp);
} }
} }
@ -412,7 +410,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="Cmyk"/></returns> /// <returns>The <see cref="Cmyk"/></returns>
public Cmyk ToCmyk(in YCbCr color) public Cmyk ToCmyk(in YCbCr color)
{ {
var rgb = this.ToRgb(color); Rgb rgb = this.ToRgb(color);
return CmykAndRgbConverter.Convert(rgb); return CmykAndRgbConverter.Convert(rgb);
} }

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

@ -12,8 +12,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </content> /// </content>
public partial class ColorSpaceConverter public partial class ColorSpaceConverter
{ {
private static readonly HslAndRgbConverter HslAndRgbConverter = new HslAndRgbConverter();
/// <summary> /// <summary>
/// Converts a <see cref="CieLab"/> into a <see cref="Hsl"/>. /// Converts a <see cref="CieLab"/> into a <see cref="Hsl"/>.
/// </summary> /// </summary>
@ -21,7 +19,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="Hsl"/></returns> /// <returns>The <see cref="Hsl"/></returns>
public Hsl ToHsl(in CieLab color) public Hsl ToHsl(in CieLab color)
{ {
var xyzColor = this.ToCieXyz(color); CieXyz xyzColor = this.ToCieXyz(color);
return this.ToHsl(xyzColor); return this.ToHsl(xyzColor);
} }
@ -54,7 +52,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="Hsl"/></returns> /// <returns>The <see cref="Hsl"/></returns>
public Hsl ToHsl(in CieLch color) public Hsl ToHsl(in CieLch color)
{ {
var xyzColor = this.ToCieXyz(color); CieXyz xyzColor = this.ToCieXyz(color);
return this.ToHsl(xyzColor); return this.ToHsl(xyzColor);
} }
@ -87,7 +85,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="Hsl"/></returns> /// <returns>The <see cref="Hsl"/></returns>
public Hsl ToHsl(in CieLchuv color) public Hsl ToHsl(in CieLchuv color)
{ {
var xyzColor = this.ToCieXyz(color); CieXyz xyzColor = this.ToCieXyz(color);
return this.ToHsl(xyzColor); return this.ToHsl(xyzColor);
} }
@ -120,7 +118,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="Hsl"/></returns> /// <returns>The <see cref="Hsl"/></returns>
public Hsl ToHsl(in CieLuv color) public Hsl ToHsl(in CieLuv color)
{ {
var xyzColor = this.ToCieXyz(color); CieXyz xyzColor = this.ToCieXyz(color);
return this.ToHsl(xyzColor); return this.ToHsl(xyzColor);
} }
@ -153,7 +151,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="Hsl"/></returns> /// <returns>The <see cref="Hsl"/></returns>
public Hsl ToHsl(in CieXyy color) public Hsl ToHsl(in CieXyy color)
{ {
var xyzColor = this.ToCieXyz(color); CieXyz xyzColor = ToCieXyz(color);
return this.ToHsl(xyzColor); return this.ToHsl(xyzColor);
} }
@ -186,7 +184,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="Hsl"/></returns> /// <returns>The <see cref="Hsl"/></returns>
public Hsl ToHsl(in CieXyz color) public Hsl ToHsl(in CieXyz color)
{ {
var rgb = this.ToRgb(color); Rgb rgb = this.ToRgb(color);
return HslAndRgbConverter.Convert(rgb); return HslAndRgbConverter.Convert(rgb);
} }
@ -217,9 +215,9 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary> /// </summary>
/// <param name="color">The color to convert.</param> /// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Hsl"/></returns> /// <returns>The <see cref="Hsl"/></returns>
public Hsl ToHsl(in Cmyk color) public static Hsl ToHsl(in Cmyk color)
{ {
var rgb = this.ToRgb(color); Rgb rgb = ToRgb(color);
return HslAndRgbConverter.Convert(rgb); return HslAndRgbConverter.Convert(rgb);
} }
@ -229,7 +227,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary> /// </summary>
/// <param name="source">The span to the source colors</param> /// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param> /// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Cmyk> source, Span<Hsl> destination) public static void Convert(ReadOnlySpan<Cmyk> source, Span<Hsl> destination)
{ {
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length; int count = source.Length;
@ -241,7 +239,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
{ {
ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i); ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i);
ref Hsl dp = ref Unsafe.Add(ref destRef, i); ref Hsl dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToHsl(sp); dp = ToHsl(sp);
} }
} }
@ -250,9 +248,9 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary> /// </summary>
/// <param name="color">The color to convert.</param> /// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Hsl"/></returns> /// <returns>The <see cref="Hsl"/></returns>
public Hsl ToHsl(in Hsv color) public static Hsl ToHsl(in Hsv color)
{ {
var rgb = this.ToRgb(color); Rgb rgb = ToRgb(color);
return HslAndRgbConverter.Convert(rgb); return HslAndRgbConverter.Convert(rgb);
} }
@ -262,7 +260,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary> /// </summary>
/// <param name="source">The span to the source colors</param> /// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param> /// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Hsv> source, Span<Hsl> destination) public static void Convert(ReadOnlySpan<Hsv> source, Span<Hsl> destination)
{ {
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length; int count = source.Length;
@ -274,7 +272,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
{ {
ref Hsv sp = ref Unsafe.Add(ref sourceRef, i); ref Hsv sp = ref Unsafe.Add(ref sourceRef, i);
ref Hsl dp = ref Unsafe.Add(ref destRef, i); ref Hsl dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToHsl(sp); dp = ToHsl(sp);
} }
} }
@ -285,7 +283,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="Hsl"/></returns> /// <returns>The <see cref="Hsl"/></returns>
public Hsl ToHsl(in HunterLab color) public Hsl ToHsl(in HunterLab color)
{ {
var xyzColor = this.ToCieXyz(color); CieXyz xyzColor = this.ToCieXyz(color);
return this.ToHsl(xyzColor); return this.ToHsl(xyzColor);
} }
@ -316,9 +314,9 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary> /// </summary>
/// <param name="color">The color to convert.</param> /// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Hsl"/></returns> /// <returns>The <see cref="Hsl"/></returns>
public Hsl ToHsl(in LinearRgb color) public static Hsl ToHsl(in LinearRgb color)
{ {
var rgb = this.ToRgb(color); Rgb rgb = ToRgb(color);
return HslAndRgbConverter.Convert(rgb); return HslAndRgbConverter.Convert(rgb);
} }
@ -328,7 +326,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary> /// </summary>
/// <param name="source">The span to the source colors</param> /// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param> /// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<LinearRgb> source, Span<Hsl> destination) public static void Convert(ReadOnlySpan<LinearRgb> source, Span<Hsl> destination)
{ {
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length; int count = source.Length;
@ -340,7 +338,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
{ {
ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i); ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i);
ref Hsl dp = ref Unsafe.Add(ref destRef, i); ref Hsl dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToHsl(sp); dp = ToHsl(sp);
} }
} }
@ -351,7 +349,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="Hsl"/></returns> /// <returns>The <see cref="Hsl"/></returns>
public Hsl ToHsl(Lms color) public Hsl ToHsl(Lms color)
{ {
var xyzColor = this.ToCieXyz(color); CieXyz xyzColor = this.ToCieXyz(color);
return this.ToHsl(xyzColor); return this.ToHsl(xyzColor);
} }
@ -382,14 +380,14 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary> /// </summary>
/// <param name="color">The color to convert.</param> /// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Hsl"/></returns> /// <returns>The <see cref="Hsl"/></returns>
public Hsl ToHsl(in Rgb color) => HslAndRgbConverter.Convert(color); public static Hsl ToHsl(in Rgb color) => HslAndRgbConverter.Convert(color);
/// <summary> /// <summary>
/// Performs the bulk conversion from <see cref="Rgb"/> into <see cref="Hsl"/>. /// Performs the bulk conversion from <see cref="Rgb"/> into <see cref="Hsl"/>.
/// </summary> /// </summary>
/// <param name="source">The span to the source colors</param> /// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param> /// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Rgb> source, Span<Hsl> destination) public static void Convert(ReadOnlySpan<Rgb> source, Span<Hsl> destination)
{ {
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length; int count = source.Length;
@ -401,7 +399,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
{ {
ref Rgb sp = ref Unsafe.Add(ref sourceRef, i); ref Rgb sp = ref Unsafe.Add(ref sourceRef, i);
ref Hsl dp = ref Unsafe.Add(ref destRef, i); ref Hsl dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToHsl(sp); dp = ToHsl(sp);
} }
} }
@ -412,7 +410,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="Hsl"/></returns> /// <returns>The <see cref="Hsl"/></returns>
public Hsl ToHsl(in YCbCr color) public Hsl ToHsl(in YCbCr color)
{ {
var rgb = this.ToRgb(color); Rgb rgb = this.ToRgb(color);
return HslAndRgbConverter.Convert(rgb); return HslAndRgbConverter.Convert(rgb);
} }

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

@ -12,8 +12,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </content> /// </content>
public partial class ColorSpaceConverter public partial class ColorSpaceConverter
{ {
private static readonly HsvAndRgbConverter HsvAndRgbConverter = new HsvAndRgbConverter();
/// <summary> /// <summary>
/// Converts a <see cref="CieLab"/> into a <see cref="Hsv"/> /// Converts a <see cref="CieLab"/> into a <see cref="Hsv"/>
/// </summary> /// </summary>
@ -21,7 +19,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="Hsv"/></returns> /// <returns>The <see cref="Hsv"/></returns>
public Hsv ToHsv(in CieLab color) public Hsv ToHsv(in CieLab color)
{ {
var xyzColor = this.ToCieXyz(color); CieXyz xyzColor = this.ToCieXyz(color);
return this.ToHsv(xyzColor); return this.ToHsv(xyzColor);
} }
@ -54,7 +52,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="Hsv"/></returns> /// <returns>The <see cref="Hsv"/></returns>
public Hsv ToHsv(in CieLch color) public Hsv ToHsv(in CieLch color)
{ {
var xyzColor = this.ToCieXyz(color); CieXyz xyzColor = this.ToCieXyz(color);
return this.ToHsv(xyzColor); return this.ToHsv(xyzColor);
} }
@ -87,7 +85,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="Hsv"/></returns> /// <returns>The <see cref="Hsv"/></returns>
public Hsv ToHsv(in CieLchuv color) public Hsv ToHsv(in CieLchuv color)
{ {
var xyzColor = this.ToCieXyz(color); CieXyz xyzColor = this.ToCieXyz(color);
return this.ToHsv(xyzColor); return this.ToHsv(xyzColor);
} }
@ -120,7 +118,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="Hsv"/></returns> /// <returns>The <see cref="Hsv"/></returns>
public Hsv ToHsv(in CieLuv color) public Hsv ToHsv(in CieLuv color)
{ {
var xyzColor = this.ToCieXyz(color); CieXyz xyzColor = this.ToCieXyz(color);
return this.ToHsv(xyzColor); return this.ToHsv(xyzColor);
} }
@ -153,7 +151,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="Hsv"/></returns> /// <returns>The <see cref="Hsv"/></returns>
public Hsv ToHsv(in CieXyy color) public Hsv ToHsv(in CieXyy color)
{ {
var xyzColor = this.ToCieXyz(color); CieXyz xyzColor = ToCieXyz(color);
return this.ToHsv(xyzColor); return this.ToHsv(xyzColor);
} }
@ -186,7 +184,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="Hsv"/></returns> /// <returns>The <see cref="Hsv"/></returns>
public Hsv ToHsv(in CieXyz color) public Hsv ToHsv(in CieXyz color)
{ {
var rgb = this.ToRgb(color); Rgb rgb = this.ToRgb(color);
return HsvAndRgbConverter.Convert(rgb); return HsvAndRgbConverter.Convert(rgb);
} }
@ -217,9 +215,9 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary> /// </summary>
/// <param name="color">The color to convert.</param> /// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Hsv"/></returns> /// <returns>The <see cref="Hsv"/></returns>
public Hsv ToHsv(in Cmyk color) public static Hsv ToHsv(in Cmyk color)
{ {
var rgb = this.ToRgb(color); Rgb rgb = ToRgb(color);
return HsvAndRgbConverter.Convert(rgb); return HsvAndRgbConverter.Convert(rgb);
} }
@ -229,7 +227,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary> /// </summary>
/// <param name="source">The span to the source colors</param> /// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param> /// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Cmyk> source, Span<Hsv> destination) public static void Convert(ReadOnlySpan<Cmyk> source, Span<Hsv> destination)
{ {
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length; int count = source.Length;
@ -241,7 +239,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
{ {
ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i); ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i);
ref Hsv dp = ref Unsafe.Add(ref destRef, i); ref Hsv dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToHsv(sp); dp = ToHsv(sp);
} }
} }
@ -250,9 +248,9 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary> /// </summary>
/// <param name="color">The color to convert.</param> /// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Hsv"/></returns> /// <returns>The <see cref="Hsv"/></returns>
public Hsv ToHsv(in Hsl color) public static Hsv ToHsv(in Hsl color)
{ {
var rgb = this.ToRgb(color); Rgb rgb = ToRgb(color);
return HsvAndRgbConverter.Convert(rgb); return HsvAndRgbConverter.Convert(rgb);
} }
@ -262,7 +260,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary> /// </summary>
/// <param name="source">The span to the source colors</param> /// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors.</param> /// <param name="destination">The span to the destination colors.</param>
public void Convert(ReadOnlySpan<Hsl> source, Span<Hsv> destination) public static void Convert(ReadOnlySpan<Hsl> source, Span<Hsv> destination)
{ {
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length; int count = source.Length;
@ -274,7 +272,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
{ {
ref Hsl sp = ref Unsafe.Add(ref sourceRef, i); ref Hsl sp = ref Unsafe.Add(ref sourceRef, i);
ref Hsv dp = ref Unsafe.Add(ref destRef, i); ref Hsv dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToHsv(sp); dp = ToHsv(sp);
} }
} }
@ -285,7 +283,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="Hsv"/></returns> /// <returns>The <see cref="Hsv"/></returns>
public Hsv ToHsv(in HunterLab color) public Hsv ToHsv(in HunterLab color)
{ {
var xyzColor = this.ToCieXyz(color); CieXyz xyzColor = this.ToCieXyz(color);
return this.ToHsv(xyzColor); return this.ToHsv(xyzColor);
} }
@ -316,9 +314,9 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary> /// </summary>
/// <param name="color">The color to convert.</param> /// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Hsv"/></returns> /// <returns>The <see cref="Hsv"/></returns>
public Hsv ToHsv(in LinearRgb color) public static Hsv ToHsv(in LinearRgb color)
{ {
var rgb = this.ToRgb(color); Rgb rgb = ToRgb(color);
return HsvAndRgbConverter.Convert(rgb); return HsvAndRgbConverter.Convert(rgb);
} }
@ -328,7 +326,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary> /// </summary>
/// <param name="source">The span to the source colors</param> /// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param> /// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<LinearRgb> source, Span<Hsv> destination) public static void Convert(ReadOnlySpan<LinearRgb> source, Span<Hsv> destination)
{ {
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length; int count = source.Length;
@ -340,7 +338,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
{ {
ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i); ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i);
ref Hsv dp = ref Unsafe.Add(ref destRef, i); ref Hsv dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToHsv(sp); dp = ToHsv(sp);
} }
} }
@ -351,7 +349,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="Hsv"/></returns> /// <returns>The <see cref="Hsv"/></returns>
public Hsv ToHsv(Lms color) public Hsv ToHsv(Lms color)
{ {
var xyzColor = this.ToCieXyz(color); CieXyz xyzColor = this.ToCieXyz(color);
return this.ToHsv(xyzColor); return this.ToHsv(xyzColor);
} }
@ -382,14 +380,14 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary> /// </summary>
/// <param name="color">The color to convert.</param> /// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Hsv"/></returns> /// <returns>The <see cref="Hsv"/></returns>
public Hsv ToHsv(in Rgb color) => HsvAndRgbConverter.Convert(color); public static Hsv ToHsv(in Rgb color) => HsvAndRgbConverter.Convert(color);
/// <summary> /// <summary>
/// Performs the bulk conversion from <see cref="Rgb"/> into <see cref="Hsv"/> /// Performs the bulk conversion from <see cref="Rgb"/> into <see cref="Hsv"/>
/// </summary> /// </summary>
/// <param name="source">The span to the source colors</param> /// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param> /// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Rgb> source, Span<Hsv> destination) public static void Convert(ReadOnlySpan<Rgb> source, Span<Hsv> destination)
{ {
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length; int count = source.Length;
@ -401,7 +399,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
{ {
ref Rgb sp = ref Unsafe.Add(ref sourceRef, i); ref Rgb sp = ref Unsafe.Add(ref sourceRef, i);
ref Hsv dp = ref Unsafe.Add(ref destRef, i); ref Hsv dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToHsv(sp); dp = ToHsv(sp);
} }
} }
@ -412,7 +410,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="Hsv"/></returns> /// <returns>The <see cref="Hsv"/></returns>
public Hsv ToHsv(in YCbCr color) public Hsv ToHsv(in YCbCr color)
{ {
var rgb = this.ToRgb(color); Rgb rgb = this.ToRgb(color);
return HsvAndRgbConverter.Convert(rgb); return HsvAndRgbConverter.Convert(rgb);
} }

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

@ -336,7 +336,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="HunterLab"/></returns> /// <returns>The <see cref="HunterLab"/></returns>
public HunterLab ToHunterLab(in CieXyy color) public HunterLab ToHunterLab(in CieXyy color)
{ {
var xyzColor = this.ToCieXyz(color); var xyzColor = ToCieXyz(color);
return this.ToHunterLab(xyzColor); return this.ToHunterLab(xyzColor);
} }

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

@ -12,8 +12,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </content> /// </content>
public partial class ColorSpaceConverter public partial class ColorSpaceConverter
{ {
private static readonly RgbToLinearRgbConverter RgbToLinearRgbConverter = new RgbToLinearRgbConverter();
/// <summary> /// <summary>
/// Performs the bulk conversion from <see cref="CieLab"/> into <see cref="LinearRgb"/>. /// Performs the bulk conversion from <see cref="CieLab"/> into <see cref="LinearRgb"/>.
/// </summary> /// </summary>
@ -145,7 +143,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary> /// </summary>
/// <param name="source">The span to the source colors.</param> /// <param name="source">The span to the source colors.</param>
/// <param name="destination">The span to the destination colors.</param> /// <param name="destination">The span to the destination colors.</param>
public void Convert(ReadOnlySpan<Cmyk> source, Span<LinearRgb> destination) public static void Convert(ReadOnlySpan<Cmyk> source, Span<LinearRgb> destination)
{ {
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length; int count = source.Length;
@ -157,7 +155,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
{ {
ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i); ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i);
ref LinearRgb dp = ref Unsafe.Add(ref destRef, i); ref LinearRgb dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToLinearRgb(sp); dp = ToLinearRgb(sp);
} }
} }
@ -166,7 +164,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary> /// </summary>
/// <param name="source">The span to the source colors.</param> /// <param name="source">The span to the source colors.</param>
/// <param name="destination">The span to the destination colors.</param> /// <param name="destination">The span to the destination colors.</param>
public void Convert(ReadOnlySpan<Hsl> source, Span<LinearRgb> destination) public static void Convert(ReadOnlySpan<Hsl> source, Span<LinearRgb> destination)
{ {
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length; int count = source.Length;
@ -178,7 +176,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
{ {
ref Hsl sp = ref Unsafe.Add(ref sourceRef, i); ref Hsl sp = ref Unsafe.Add(ref sourceRef, i);
ref LinearRgb dp = ref Unsafe.Add(ref destRef, i); ref LinearRgb dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToLinearRgb(sp); dp = ToLinearRgb(sp);
} }
} }
@ -187,7 +185,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary> /// </summary>
/// <param name="source">The span to the source colors.</param> /// <param name="source">The span to the source colors.</param>
/// <param name="destination">The span to the destination colors.</param> /// <param name="destination">The span to the destination colors.</param>
public void Convert(ReadOnlySpan<Hsv> source, Span<LinearRgb> destination) public static void Convert(ReadOnlySpan<Hsv> source, Span<LinearRgb> destination)
{ {
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length; int count = source.Length;
@ -199,7 +197,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
{ {
ref Hsv sp = ref Unsafe.Add(ref sourceRef, i); ref Hsv sp = ref Unsafe.Add(ref sourceRef, i);
ref LinearRgb dp = ref Unsafe.Add(ref destRef, i); ref LinearRgb dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToLinearRgb(sp); dp = ToLinearRgb(sp);
} }
} }
@ -250,7 +248,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary> /// </summary>
/// <param name="source">The span to the source colors</param> /// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param> /// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Rgb> source, Span<LinearRgb> destination) public static void Convert(ReadOnlySpan<Rgb> source, Span<LinearRgb> destination)
{ {
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length; int count = source.Length;
@ -262,7 +260,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
{ {
ref Rgb sp = ref Unsafe.Add(ref sourceRef, i); ref Rgb sp = ref Unsafe.Add(ref sourceRef, i);
ref LinearRgb dp = ref Unsafe.Add(ref destRef, i); ref LinearRgb dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToLinearRgb(sp); dp = ToLinearRgb(sp);
} }
} }
@ -294,7 +292,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="LinearRgb"/></returns> /// <returns>The <see cref="LinearRgb"/></returns>
public LinearRgb ToLinearRgb(in CieLab color) public LinearRgb ToLinearRgb(in CieLab color)
{ {
var xyzColor = this.ToCieXyz(color); CieXyz xyzColor = this.ToCieXyz(color);
return this.ToLinearRgb(xyzColor); return this.ToLinearRgb(xyzColor);
} }
@ -305,7 +303,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="LinearRgb"/></returns> /// <returns>The <see cref="LinearRgb"/></returns>
public LinearRgb ToLinearRgb(in CieLch color) public LinearRgb ToLinearRgb(in CieLch color)
{ {
var xyzColor = this.ToCieXyz(color); CieXyz xyzColor = this.ToCieXyz(color);
return this.ToLinearRgb(xyzColor); return this.ToLinearRgb(xyzColor);
} }
@ -316,7 +314,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="LinearRgb"/></returns> /// <returns>The <see cref="LinearRgb"/></returns>
public LinearRgb ToLinearRgb(in CieLchuv color) public LinearRgb ToLinearRgb(in CieLchuv color)
{ {
var xyzColor = this.ToCieXyz(color); CieXyz xyzColor = this.ToCieXyz(color);
return this.ToLinearRgb(xyzColor); return this.ToLinearRgb(xyzColor);
} }
@ -327,7 +325,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="LinearRgb"/></returns> /// <returns>The <see cref="LinearRgb"/></returns>
public LinearRgb ToLinearRgb(in CieLuv color) public LinearRgb ToLinearRgb(in CieLuv color)
{ {
var xyzColor = this.ToCieXyz(color); CieXyz xyzColor = this.ToCieXyz(color);
return this.ToLinearRgb(xyzColor); return this.ToLinearRgb(xyzColor);
} }
@ -338,7 +336,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="LinearRgb"/></returns> /// <returns>The <see cref="LinearRgb"/></returns>
public LinearRgb ToLinearRgb(in CieXyy color) public LinearRgb ToLinearRgb(in CieXyy color)
{ {
var xyzColor = this.ToCieXyz(color); CieXyz xyzColor = ToCieXyz(color);
return this.ToLinearRgb(xyzColor); return this.ToLinearRgb(xyzColor);
} }
@ -361,10 +359,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary> /// </summary>
/// <param name="color">The color to convert.</param> /// <param name="color">The color to convert.</param>
/// <returns>The <see cref="LinearRgb"/></returns> /// <returns>The <see cref="LinearRgb"/></returns>
public LinearRgb ToLinearRgb(in Cmyk color) public static LinearRgb ToLinearRgb(in Cmyk color)
{ {
var rgb = this.ToRgb(color); Rgb rgb = ToRgb(color);
return this.ToLinearRgb(rgb); return ToLinearRgb(rgb);
} }
/// <summary> /// <summary>
@ -372,10 +370,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary> /// </summary>
/// <param name="color">The color to convert.</param> /// <param name="color">The color to convert.</param>
/// <returns>The <see cref="LinearRgb"/></returns> /// <returns>The <see cref="LinearRgb"/></returns>
public LinearRgb ToLinearRgb(in Hsl color) public static LinearRgb ToLinearRgb(in Hsl color)
{ {
var rgb = this.ToRgb(color); Rgb rgb = ToRgb(color);
return this.ToLinearRgb(rgb); return ToLinearRgb(rgb);
} }
/// <summary> /// <summary>
@ -383,10 +381,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary> /// </summary>
/// <param name="color">The color to convert.</param> /// <param name="color">The color to convert.</param>
/// <returns>The <see cref="LinearRgb"/></returns> /// <returns>The <see cref="LinearRgb"/></returns>
public LinearRgb ToLinearRgb(in Hsv color) public static LinearRgb ToLinearRgb(in Hsv color)
{ {
var rgb = this.ToRgb(color); Rgb rgb = ToRgb(color);
return this.ToLinearRgb(rgb); return ToLinearRgb(rgb);
} }
/// <summary> /// <summary>
@ -396,7 +394,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="LinearRgb"/></returns> /// <returns>The <see cref="LinearRgb"/></returns>
public LinearRgb ToLinearRgb(in HunterLab color) public LinearRgb ToLinearRgb(in HunterLab color)
{ {
var xyzColor = this.ToCieXyz(color); CieXyz xyzColor = this.ToCieXyz(color);
return this.ToLinearRgb(xyzColor); return this.ToLinearRgb(xyzColor);
} }
@ -407,7 +405,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="LinearRgb"/></returns> /// <returns>The <see cref="LinearRgb"/></returns>
public LinearRgb ToLinearRgb(in Lms color) public LinearRgb ToLinearRgb(in Lms color)
{ {
var xyzColor = this.ToCieXyz(color); CieXyz xyzColor = this.ToCieXyz(color);
return this.ToLinearRgb(xyzColor); return this.ToLinearRgb(xyzColor);
} }
@ -416,11 +414,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary> /// </summary>
/// <param name="color">The color to convert.</param> /// <param name="color">The color to convert.</param>
/// <returns>The <see cref="LinearRgb"/></returns> /// <returns>The <see cref="LinearRgb"/></returns>
public LinearRgb ToLinearRgb(in Rgb color) public static LinearRgb ToLinearRgb(in Rgb color)
{ => RgbToLinearRgbConverter.Convert(color);
// Conversion
return RgbToLinearRgbConverter.Convert(color);
}
/// <summary> /// <summary>
/// Converts a <see cref="YCbCr"/> into a <see cref="LinearRgb"/>. /// Converts a <see cref="YCbCr"/> into a <see cref="LinearRgb"/>.
@ -429,8 +424,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="LinearRgb"/></returns> /// <returns>The <see cref="LinearRgb"/></returns>
public LinearRgb ToLinearRgb(in YCbCr color) public LinearRgb ToLinearRgb(in YCbCr color)
{ {
var rgb = this.ToRgb(color); Rgb rgb = this.ToRgb(color);
return this.ToLinearRgb(rgb); return ToLinearRgb(rgb);
} }
} }
} }

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

@ -336,7 +336,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="Lms"/></returns> /// <returns>The <see cref="Lms"/></returns>
public Lms ToLms(in CieXyy color) public Lms ToLms(in CieXyy color)
{ {
var xyzColor = this.ToCieXyz(color); var xyzColor = ToCieXyz(color);
return this.ToLms(xyzColor); return this.ToLms(xyzColor);
} }

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

@ -12,8 +12,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </content> /// </content>
public partial class ColorSpaceConverter public partial class ColorSpaceConverter
{ {
private static readonly LinearRgbToRgbConverter LinearRgbToRgbConverter = new LinearRgbToRgbConverter();
/// <summary> /// <summary>
/// Performs the bulk conversion from <see cref="CieLab"/> into <see cref="Rgb"/> /// Performs the bulk conversion from <see cref="CieLab"/> into <see cref="Rgb"/>
/// </summary> /// </summary>
@ -145,7 +143,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary> /// </summary>
/// <param name="source">The span to the source colors</param> /// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param> /// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Cmyk> source, Span<Rgb> destination) public static void Convert(ReadOnlySpan<Cmyk> source, Span<Rgb> destination)
{ {
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length; int count = source.Length;
@ -157,7 +155,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
{ {
ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i); ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgb dp = ref Unsafe.Add(ref destRef, i); ref Rgb dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToRgb(sp); dp = ToRgb(sp);
} }
} }
@ -166,7 +164,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary> /// </summary>
/// <param name="source">The span to the source colors</param> /// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param> /// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Hsv> source, Span<Rgb> destination) public static void Convert(ReadOnlySpan<Hsv> source, Span<Rgb> destination)
{ {
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length; int count = source.Length;
@ -178,7 +176,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
{ {
ref Hsv sp = ref Unsafe.Add(ref sourceRef, i); ref Hsv sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgb dp = ref Unsafe.Add(ref destRef, i); ref Rgb dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToRgb(sp); dp = ToRgb(sp);
} }
} }
@ -187,7 +185,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary> /// </summary>
/// <param name="source">The span to the source colors</param> /// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param> /// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Hsl> source, Span<Rgb> destination) public static void Convert(ReadOnlySpan<Hsl> source, Span<Rgb> destination)
{ {
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length; int count = source.Length;
@ -199,7 +197,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
{ {
ref Hsl sp = ref Unsafe.Add(ref sourceRef, i); ref Hsl sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgb dp = ref Unsafe.Add(ref destRef, i); ref Rgb dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToRgb(sp); dp = ToRgb(sp);
} }
} }
@ -229,7 +227,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary> /// </summary>
/// <param name="source">The span to the source colors</param> /// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param> /// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<LinearRgb> source, Span<Rgb> destination) public static void Convert(ReadOnlySpan<LinearRgb> source, Span<Rgb> destination)
{ {
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length; int count = source.Length;
@ -241,7 +239,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
{ {
ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i); ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgb dp = ref Unsafe.Add(ref destRef, i); ref Rgb dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToRgb(sp); dp = ToRgb(sp);
} }
} }
@ -294,7 +292,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="Rgb"/></returns> /// <returns>The <see cref="Rgb"/></returns>
public Rgb ToRgb(in CieLab color) public Rgb ToRgb(in CieLab color)
{ {
var xyzColor = this.ToCieXyz(color); CieXyz xyzColor = this.ToCieXyz(color);
return this.ToRgb(xyzColor); return this.ToRgb(xyzColor);
} }
@ -305,7 +303,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="Rgb"/></returns> /// <returns>The <see cref="Rgb"/></returns>
public Rgb ToRgb(in CieLch color) public Rgb ToRgb(in CieLch color)
{ {
var xyzColor = this.ToCieXyz(color); CieXyz xyzColor = this.ToCieXyz(color);
return this.ToRgb(xyzColor); return this.ToRgb(xyzColor);
} }
@ -316,7 +314,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="Rgb"/></returns> /// <returns>The <see cref="Rgb"/></returns>
public Rgb ToRgb(in CieLchuv color) public Rgb ToRgb(in CieLchuv color)
{ {
var xyzColor = this.ToCieXyz(color); CieXyz xyzColor = this.ToCieXyz(color);
return this.ToRgb(xyzColor); return this.ToRgb(xyzColor);
} }
@ -327,7 +325,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="Rgb"/></returns> /// <returns>The <see cref="Rgb"/></returns>
public Rgb ToRgb(in CieLuv color) public Rgb ToRgb(in CieLuv color)
{ {
var xyzColor = this.ToCieXyz(color); CieXyz xyzColor = this.ToCieXyz(color);
return this.ToRgb(xyzColor); return this.ToRgb(xyzColor);
} }
@ -338,7 +336,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="Rgb"/></returns> /// <returns>The <see cref="Rgb"/></returns>
public Rgb ToRgb(in CieXyy color) public Rgb ToRgb(in CieXyy color)
{ {
var xyzColor = this.ToCieXyz(color); CieXyz xyzColor = ToCieXyz(color);
return this.ToRgb(xyzColor); return this.ToRgb(xyzColor);
} }
@ -350,10 +348,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
public Rgb ToRgb(in CieXyz color) public Rgb ToRgb(in CieXyz color)
{ {
// Conversion // Conversion
var linear = this.ToLinearRgb(color); LinearRgb linear = this.ToLinearRgb(color);
// Compand // Compand
return this.ToRgb(linear); return ToRgb(linear);
} }
/// <summary> /// <summary>
@ -361,33 +359,21 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary> /// </summary>
/// <param name="color">The color to convert.</param> /// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Rgb"/></returns> /// <returns>The <see cref="Rgb"/></returns>
public Rgb ToRgb(in Cmyk color) public static Rgb ToRgb(in Cmyk color) => CmykAndRgbConverter.Convert(color);
{
// Conversion
return CmykAndRgbConverter.Convert(color);
}
/// <summary> /// <summary>
/// Converts a <see cref="Hsv"/> into a <see cref="Rgb"/> /// Converts a <see cref="Hsv"/> into a <see cref="Rgb"/>
/// </summary> /// </summary>
/// <param name="color">The color to convert.</param> /// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Rgb"/></returns> /// <returns>The <see cref="Rgb"/></returns>
public Rgb ToRgb(in Hsv color) public static Rgb ToRgb(in Hsv color) => HsvAndRgbConverter.Convert(color);
{
// Conversion
return HsvAndRgbConverter.Convert(color);
}
/// <summary> /// <summary>
/// Converts a <see cref="Hsl"/> into a <see cref="Rgb"/> /// Converts a <see cref="Hsl"/> into a <see cref="Rgb"/>
/// </summary> /// </summary>
/// <param name="color">The color to convert.</param> /// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Rgb"/></returns> /// <returns>The <see cref="Rgb"/></returns>
public Rgb ToRgb(in Hsl color) public static Rgb ToRgb(in Hsl color) => HslAndRgbConverter.Convert(color);
{
// Conversion
return HslAndRgbConverter.Convert(color);
}
/// <summary> /// <summary>
/// Converts a <see cref="HunterLab"/> into a <see cref="Rgb"/> /// Converts a <see cref="HunterLab"/> into a <see cref="Rgb"/>
@ -396,7 +382,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="Rgb"/></returns> /// <returns>The <see cref="Rgb"/></returns>
public Rgb ToRgb(in HunterLab color) public Rgb ToRgb(in HunterLab color)
{ {
var xyzColor = this.ToCieXyz(color); CieXyz xyzColor = this.ToCieXyz(color);
return this.ToRgb(xyzColor); return this.ToRgb(xyzColor);
} }
@ -405,11 +391,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary> /// </summary>
/// <param name="color">The color to convert.</param> /// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Rgb"/></returns> /// <returns>The <see cref="Rgb"/></returns>
public Rgb ToRgb(in LinearRgb color) public static Rgb ToRgb(in LinearRgb color) => LinearRgbToRgbConverter.Convert(color);
{
// Conversion
return LinearRgbToRgbConverter.Convert(color);
}
/// <summary> /// <summary>
/// Converts a <see cref="Lms"/> into a <see cref="Rgb"/> /// Converts a <see cref="Lms"/> into a <see cref="Rgb"/>
@ -418,7 +400,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="Rgb"/></returns> /// <returns>The <see cref="Rgb"/></returns>
public Rgb ToRgb(in Lms color) public Rgb ToRgb(in Lms color)
{ {
var xyzColor = this.ToCieXyz(color); CieXyz xyzColor = this.ToCieXyz(color);
return this.ToRgb(xyzColor); return this.ToRgb(xyzColor);
} }

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

@ -12,8 +12,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </content> /// </content>
public partial class ColorSpaceConverter public partial class ColorSpaceConverter
{ {
private static readonly YCbCrAndRgbConverter YCbCrAndRgbConverter = new YCbCrAndRgbConverter();
/// <summary> /// <summary>
/// Performs the bulk conversion from <see cref="CieLab"/> into <see cref="YCbCr"/>. /// Performs the bulk conversion from <see cref="CieLab"/> into <see cref="YCbCr"/>.
/// </summary> /// </summary>
@ -124,7 +122,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary> /// </summary>
/// <param name="source">The span to the source colors</param> /// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param> /// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Cmyk> source, Span<YCbCr> destination) public static void Convert(ReadOnlySpan<Cmyk> source, Span<YCbCr> destination)
{ {
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length; int count = source.Length;
@ -136,7 +134,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
{ {
ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i); ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i);
ref YCbCr dp = ref Unsafe.Add(ref destRef, i); ref YCbCr dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToYCbCr(sp); dp = ToYCbCr(sp);
} }
} }
@ -145,7 +143,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary> /// </summary>
/// <param name="source">The span to the source colors</param> /// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param> /// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Hsl> source, Span<YCbCr> destination) public static void Convert(ReadOnlySpan<Hsl> source, Span<YCbCr> destination)
{ {
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length; int count = source.Length;
@ -157,7 +155,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
{ {
ref Hsl sp = ref Unsafe.Add(ref sourceRef, i); ref Hsl sp = ref Unsafe.Add(ref sourceRef, i);
ref YCbCr dp = ref Unsafe.Add(ref destRef, i); ref YCbCr dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToYCbCr(sp); dp = ToYCbCr(sp);
} }
} }
@ -166,7 +164,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary> /// </summary>
/// <param name="source">The span to the source colors</param> /// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param> /// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Hsv> source, Span<YCbCr> destination) public static void Convert(ReadOnlySpan<Hsv> source, Span<YCbCr> destination)
{ {
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length; int count = source.Length;
@ -178,7 +176,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
{ {
ref Hsv sp = ref Unsafe.Add(ref sourceRef, i); ref Hsv sp = ref Unsafe.Add(ref sourceRef, i);
ref YCbCr dp = ref Unsafe.Add(ref destRef, i); ref YCbCr dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToYCbCr(sp); dp = ToYCbCr(sp);
} }
} }
@ -208,7 +206,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary> /// </summary>
/// <param name="source">The span to the source colors</param> /// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param> /// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<LinearRgb> source, Span<YCbCr> destination) public static void Convert(ReadOnlySpan<LinearRgb> source, Span<YCbCr> destination)
{ {
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length; int count = source.Length;
@ -220,7 +218,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
{ {
ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i); ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i);
ref YCbCr dp = ref Unsafe.Add(ref destRef, i); ref YCbCr dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToYCbCr(sp); dp = ToYCbCr(sp);
} }
} }
@ -250,7 +248,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary> /// </summary>
/// <param name="source">The span to the source colors</param> /// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param> /// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Rgb> source, Span<YCbCr> destination) public static void Convert(ReadOnlySpan<Rgb> source, Span<YCbCr> destination)
{ {
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length; int count = source.Length;
@ -262,7 +260,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
{ {
ref Rgb sp = ref Unsafe.Add(ref sourceRef, i); ref Rgb sp = ref Unsafe.Add(ref sourceRef, i);
ref YCbCr dp = ref Unsafe.Add(ref destRef, i); ref YCbCr dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToYCbCr(sp); dp = ToYCbCr(sp);
} }
} }
@ -273,7 +271,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="YCbCr"/></returns> /// <returns>The <see cref="YCbCr"/></returns>
public YCbCr ToYCbCr(in CieLab color) public YCbCr ToYCbCr(in CieLab color)
{ {
var xyzColor = this.ToCieXyz(color); CieXyz xyzColor = this.ToCieXyz(color);
return this.ToYCbCr(xyzColor); return this.ToYCbCr(xyzColor);
} }
@ -285,7 +283,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="YCbCr"/></returns> /// <returns>The <see cref="YCbCr"/></returns>
public YCbCr ToYCbCr(in CieLch color) public YCbCr ToYCbCr(in CieLch color)
{ {
var xyzColor = this.ToCieXyz(color); CieXyz xyzColor = this.ToCieXyz(color);
return this.ToYCbCr(xyzColor); return this.ToYCbCr(xyzColor);
} }
@ -297,7 +295,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="YCbCr"/></returns> /// <returns>The <see cref="YCbCr"/></returns>
public YCbCr ToYCbCr(in CieLuv color) public YCbCr ToYCbCr(in CieLuv color)
{ {
var xyzColor = this.ToCieXyz(color); CieXyz xyzColor = this.ToCieXyz(color);
return this.ToYCbCr(xyzColor); return this.ToYCbCr(xyzColor);
} }
@ -309,7 +307,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="YCbCr"/></returns> /// <returns>The <see cref="YCbCr"/></returns>
public YCbCr ToYCbCr(in CieXyy color) public YCbCr ToYCbCr(in CieXyy color)
{ {
var xyzColor = this.ToCieXyz(color); CieXyz xyzColor = ToCieXyz(color);
return this.ToYCbCr(xyzColor); return this.ToYCbCr(xyzColor);
} }
@ -321,7 +319,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="YCbCr"/></returns> /// <returns>The <see cref="YCbCr"/></returns>
public YCbCr ToYCbCr(in CieXyz color) public YCbCr ToYCbCr(in CieXyz color)
{ {
var rgb = this.ToRgb(color); Rgb rgb = this.ToRgb(color);
return YCbCrAndRgbConverter.Convert(rgb); return YCbCrAndRgbConverter.Convert(rgb);
} }
@ -331,9 +329,9 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary> /// </summary>
/// <param name="color">The color to convert.</param> /// <param name="color">The color to convert.</param>
/// <returns>The <see cref="YCbCr"/></returns> /// <returns>The <see cref="YCbCr"/></returns>
public YCbCr ToYCbCr(in Cmyk color) public static YCbCr ToYCbCr(in Cmyk color)
{ {
var rgb = this.ToRgb(color); Rgb rgb = ToRgb(color);
return YCbCrAndRgbConverter.Convert(rgb); return YCbCrAndRgbConverter.Convert(rgb);
} }
@ -343,9 +341,9 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary> /// </summary>
/// <param name="color">The color to convert.</param> /// <param name="color">The color to convert.</param>
/// <returns>The <see cref="YCbCr"/></returns> /// <returns>The <see cref="YCbCr"/></returns>
public YCbCr ToYCbCr(in Hsl color) public static YCbCr ToYCbCr(in Hsl color)
{ {
var rgb = this.ToRgb(color); Rgb rgb = ToRgb(color);
return YCbCrAndRgbConverter.Convert(rgb); return YCbCrAndRgbConverter.Convert(rgb);
} }
@ -355,9 +353,9 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary> /// </summary>
/// <param name="color">The color to convert.</param> /// <param name="color">The color to convert.</param>
/// <returns>The <see cref="YCbCr"/></returns> /// <returns>The <see cref="YCbCr"/></returns>
public YCbCr ToYCbCr(in Hsv color) public static YCbCr ToYCbCr(in Hsv color)
{ {
var rgb = this.ToRgb(color); Rgb rgb = ToRgb(color);
return YCbCrAndRgbConverter.Convert(rgb); return YCbCrAndRgbConverter.Convert(rgb);
} }
@ -369,7 +367,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="YCbCr"/></returns> /// <returns>The <see cref="YCbCr"/></returns>
public YCbCr ToYCbCr(in HunterLab color) public YCbCr ToYCbCr(in HunterLab color)
{ {
var xyzColor = this.ToCieXyz(color); CieXyz xyzColor = this.ToCieXyz(color);
return this.ToYCbCr(xyzColor); return this.ToYCbCr(xyzColor);
} }
@ -379,9 +377,9 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary> /// </summary>
/// <param name="color">The color to convert.</param> /// <param name="color">The color to convert.</param>
/// <returns>The <see cref="YCbCr"/></returns> /// <returns>The <see cref="YCbCr"/></returns>
public YCbCr ToYCbCr(in LinearRgb color) public static YCbCr ToYCbCr(in LinearRgb color)
{ {
var rgb = this.ToRgb(color); Rgb rgb = ToRgb(color);
return YCbCrAndRgbConverter.Convert(rgb); return YCbCrAndRgbConverter.Convert(rgb);
} }
@ -393,7 +391,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="YCbCr"/></returns> /// <returns>The <see cref="YCbCr"/></returns>
public YCbCr ToYCbCr(in Lms color) public YCbCr ToYCbCr(in Lms color)
{ {
var xyzColor = this.ToCieXyz(color); CieXyz xyzColor = this.ToCieXyz(color);
return this.ToYCbCr(xyzColor); return this.ToYCbCr(xyzColor);
} }
@ -403,6 +401,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary> /// </summary>
/// <param name="color">The color to convert.</param> /// <param name="color">The color to convert.</param>
/// <returns>The <see cref="YCbCr"/></returns> /// <returns>The <see cref="YCbCr"/></returns>
public YCbCr ToYCbCr(in Rgb color) => YCbCrAndRgbConverter.Convert(color); public static YCbCr ToYCbCr(in Rgb color) => YCbCrAndRgbConverter.Convert(color);
} }
} }

46
src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyChromaticityCoordinates.cs

@ -12,13 +12,25 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary> /// </summary>
public readonly struct CieXyChromaticityCoordinates : IEquatable<CieXyChromaticityCoordinates> public readonly struct CieXyChromaticityCoordinates : IEquatable<CieXyChromaticityCoordinates>
{ {
/// <summary>
/// Initializes a new instance of the <see cref="CieXyChromaticityCoordinates"/> struct.
/// </summary>
/// <param name="x">Chromaticity coordinate x (usually from 0 to 1)</param>
/// <param name="y">Chromaticity coordinate y (usually from 0 to 1)</param>
[MethodImpl(InliningOptions.ShortMethod)]
public CieXyChromaticityCoordinates(float x, float y)
{
this.X = x;
this.Y = y;
}
/// <summary> /// <summary>
/// Gets the chromaticity X-coordinate. /// Gets the chromaticity X-coordinate.
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// Ranges usually from 0 to 1. /// Ranges usually from 0 to 1.
/// </remarks> /// </remarks>
public readonly float X; public readonly float X { get; }
/// <summary> /// <summary>
/// Gets the chromaticity Y-coordinate /// Gets the chromaticity Y-coordinate
@ -26,19 +38,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <remarks> /// <remarks>
/// Ranges usually from 0 to 1. /// Ranges usually from 0 to 1.
/// </remarks> /// </remarks>
public readonly float Y; public readonly float Y { get; }
/// <summary>
/// Initializes a new instance of the <see cref="CieXyChromaticityCoordinates"/> struct.
/// </summary>
/// <param name="x">Chromaticity coordinate x (usually from 0 to 1)</param>
/// <param name="y">Chromaticity coordinate y (usually from 0 to 1)</param>
[MethodImpl(InliningOptions.ShortMethod)]
public CieXyChromaticityCoordinates(float x, float y)
{
this.X = x;
this.Y = y;
}
/// <summary> /// <summary>
/// Compares two <see cref="CieXyChromaticityCoordinates"/> objects for equality. /// Compares two <see cref="CieXyChromaticityCoordinates"/> objects for equality.
@ -49,7 +49,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// True if the current left is equal to the <paramref name="right"/> parameter; otherwise, false. /// True if the current left is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns> /// </returns>
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public static bool operator ==(CieXyChromaticityCoordinates left, CieXyChromaticityCoordinates right) => left.Equals(right); public static bool operator ==(CieXyChromaticityCoordinates left, CieXyChromaticityCoordinates right)
=> left.Equals(right);
/// <summary> /// <summary>
/// Compares two <see cref="CieXyChromaticityCoordinates"/> objects for inequality /// Compares two <see cref="CieXyChromaticityCoordinates"/> objects for inequality
@ -60,20 +61,25 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// True if the current left is unequal to the <paramref name="right"/> parameter; otherwise, false. /// True if the current left is unequal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns> /// </returns>
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public static bool operator !=(CieXyChromaticityCoordinates left, CieXyChromaticityCoordinates right) => !left.Equals(right); public static bool operator !=(CieXyChromaticityCoordinates left, CieXyChromaticityCoordinates right)
=> !left.Equals(right);
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public override int GetHashCode() => HashCode.Combine(this.X, this.Y); public override int GetHashCode()
=> HashCode.Combine(this.X, this.Y);
/// <inheritdoc/> /// <inheritdoc/>
public override string ToString() => FormattableString.Invariant($"CieXyChromaticityCoordinates({this.X:#0.##}, {this.Y:#0.##})"); public override string ToString()
=> FormattableString.Invariant($"CieXyChromaticityCoordinates({this.X:#0.##}, {this.Y:#0.##})");
/// <inheritdoc/> /// <inheritdoc/>
public override bool Equals(object obj) => obj is CieXyChromaticityCoordinates other && this.Equals(other); public override bool Equals(object obj)
=> obj is CieXyChromaticityCoordinates other && this.Equals(other);
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public bool Equals(CieXyChromaticityCoordinates other) => this.X.Equals(other.X) && this.Y.Equals(other.Y); public bool Equals(CieXyChromaticityCoordinates other)
=> this.X.Equals(other.X) && this.Y.Equals(other.Y);
} }
} }

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

@ -1,4 +1,4 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Six Labors Split License. // Licensed under the Six Labors Split License.
using System; using System;
@ -9,7 +9,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <summary> /// <summary>
/// Converts from <see cref="CieLch"/> to <see cref="CieLab"/>. /// Converts from <see cref="CieLch"/> to <see cref="CieLab"/>.
/// </summary> /// </summary>
internal sealed class CieLchToCieLabConverter internal static class CieLchToCieLabConverter
{ {
/// <summary> /// <summary>
/// Performs the conversion from the <see cref="CieLch"/> input to an instance of <see cref="CieLab"/> type. /// Performs the conversion from the <see cref="CieLch"/> input to an instance of <see cref="CieLab"/> type.
@ -17,7 +17,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <param name="input">The input color instance.</param> /// <param name="input">The input color instance.</param>
/// <returns>The converted result</returns> /// <returns>The converted result</returns>
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public CieLab Convert(in CieLch input) public static CieLab Convert(in CieLch input)
{ {
// Conversion algorithm described here: // Conversion algorithm described here:
// https://en.wikipedia.org/wiki/Lab_color_space#Cylindrical_representation:_CIELCh_or_CIEHLC // https://en.wikipedia.org/wiki/Lab_color_space#Cylindrical_representation:_CIELCh_or_CIEHLC

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

@ -9,7 +9,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <summary> /// <summary>
/// Converts from <see cref="CieLab"/> to <see cref="CieLch"/>. /// Converts from <see cref="CieLab"/> to <see cref="CieLch"/>.
/// </summary> /// </summary>
internal sealed class CieLabToCieLchConverter internal static class CieLabToCieLchConverter
{ {
/// <summary> /// <summary>
/// Performs the conversion from the <see cref="CieLab"/> input to an instance of <see cref="CieLch"/> type. /// Performs the conversion from the <see cref="CieLab"/> input to an instance of <see cref="CieLch"/> type.
@ -17,7 +17,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <param name="input">The input color instance.</param> /// <param name="input">The input color instance.</param>
/// <returns>The converted result</returns> /// <returns>The converted result</returns>
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public CieLch Convert(in CieLab input) public static CieLch Convert(in CieLab input)
{ {
// Conversion algorithm described here: // Conversion algorithm described here:
// https://en.wikipedia.org/wiki/Lab_color_space#Cylindrical_representation:_CIELCh_or_CIEHLC // https://en.wikipedia.org/wiki/Lab_color_space#Cylindrical_representation:_CIELCh_or_CIEHLC

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

@ -9,7 +9,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <summary> /// <summary>
/// Converts from <see cref="CieLab"/> to <see cref="CieXyz"/>. /// Converts from <see cref="CieLab"/> to <see cref="CieXyz"/>.
/// </summary> /// </summary>
internal sealed class CieLabToCieXyzConverter internal static class CieLabToCieXyzConverter
{ {
/// <summary> /// <summary>
/// Performs the conversion from the <see cref="CieLab"/> input to an instance of <see cref="CieXyz"/> type. /// Performs the conversion from the <see cref="CieLab"/> input to an instance of <see cref="CieXyz"/> type.
@ -17,7 +17,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <param name="input">The input color instance.</param> /// <param name="input">The input color instance.</param>
/// <returns>The converted result</returns> /// <returns>The converted result</returns>
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public CieXyz Convert(in CieLab input) public static CieXyz Convert(in CieLab input)
{ {
// Conversion algorithm described here: http://www.brucelindbloom.com/index.html?Eqn_Lab_to_XYZ.html // 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 l = input.L, a = input.A, b = input.B;
@ -32,10 +32,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
float yr = l > CieConstants.Kappa * CieConstants.Epsilon ? Numerics.Pow3((l + 16F) / 116F) : l / 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; float zr = fz3 > CieConstants.Epsilon ? fz3 : ((116F * fz) - 16F) / CieConstants.Kappa;
var wxyz = new Vector3(input.WhitePoint.X, input.WhitePoint.Y, input.WhitePoint.Z); Vector3 wxyz = new(input.WhitePoint.X, input.WhitePoint.Y, input.WhitePoint.Z);
// Avoids XYZ coordinates out range (restricted by 0 and XYZ reference white) // Avoids XYZ coordinates out range (restricted by 0 and XYZ reference white)
var xyzr = Vector3.Clamp(new Vector3(xr, yr, zr), Vector3.Zero, Vector3.One); Vector3 xyzr = Vector3.Clamp(new Vector3(xr, yr, zr), Vector3.Zero, Vector3.One);
Vector3 xyz = xyzr * wxyz; Vector3 xyz = xyzr * wxyz;
return new CieXyz(xyz); return new CieXyz(xyz);

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

@ -9,7 +9,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <summary> /// <summary>
/// Converts from <see cref="CieLch"/> to <see cref="CieLab"/>. /// Converts from <see cref="CieLch"/> to <see cref="CieLab"/>.
/// </summary> /// </summary>
internal sealed class CieLchuvToCieLuvConverter internal static class CieLchuvToCieLuvConverter
{ {
/// <summary> /// <summary>
/// Performs the conversion from the <see cref="CieLchuv"/> input to an instance of <see cref="CieLuv"/> type. /// Performs the conversion from the <see cref="CieLchuv"/> input to an instance of <see cref="CieLuv"/> type.
@ -17,7 +17,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <param name="input">The input color instance.</param> /// <param name="input">The input color instance.</param>
/// <returns>The converted result</returns> /// <returns>The converted result</returns>
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public CieLuv Convert(in CieLchuv input) public static CieLuv Convert(in CieLchuv input)
{ {
// Conversion algorithm described here: // Conversion algorithm described here:
// https://en.wikipedia.org/wiki/CIELUV#Cylindrical_representation_.28CIELCH.29 // https://en.wikipedia.org/wiki/CIELUV#Cylindrical_representation_.28CIELCH.29

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

@ -9,7 +9,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <summary> /// <summary>
/// Converts from <see cref="CieLab"/> to <see cref="CieLch"/>. /// Converts from <see cref="CieLab"/> to <see cref="CieLch"/>.
/// </summary> /// </summary>
internal sealed class CieLuvToCieLchuvConverter internal static class CieLuvToCieLchuvConverter
{ {
/// <summary> /// <summary>
/// Performs the conversion from the <see cref="CieLuv"/> input to an instance of <see cref="CieLchuv"/> type. /// Performs the conversion from the <see cref="CieLuv"/> input to an instance of <see cref="CieLchuv"/> type.
@ -17,7 +17,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <param name="input">The input color instance.</param> /// <param name="input">The input color instance.</param>
/// <returns>The converted result</returns> /// <returns>The converted result</returns>
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public CieLchuv Convert(in CieLuv input) public static CieLchuv Convert(in CieLuv input)
{ {
// Conversion algorithm described here: // Conversion algorithm described here:
// https://en.wikipedia.org/wiki/CIELUV#Cylindrical_representation_.28CIELCH.29 // https://en.wikipedia.org/wiki/CIELUV#Cylindrical_representation_.28CIELCH.29

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

@ -8,14 +8,14 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <summary> /// <summary>
/// Converts from <see cref="CieLuv"/> to <see cref="CieXyz"/>. /// Converts from <see cref="CieLuv"/> to <see cref="CieXyz"/>.
/// </summary> /// </summary>
internal sealed class CieLuvToCieXyzConverter internal static class CieLuvToCieXyzConverter
{ {
/// <summary> /// <summary>
/// Performs the conversion from the <see cref="CieLuv"/> input to an instance of <see cref="CieXyz"/> type. /// Performs the conversion from the <see cref="CieLuv"/> input to an instance of <see cref="CieXyz"/> type.
/// </summary> /// </summary>
/// <param name="input">The input color instance.</param> /// <param name="input">The input color instance.</param>
/// <returns>The converted result</returns> /// <returns>The converted result</returns>
public CieXyz Convert(in CieLuv input) public static CieXyz Convert(in CieLuv input)
{ {
// Conversion algorithm described here: http://www.brucelindbloom.com/index.html?Eqn_Luv_to_XYZ.html // 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 l = input.L, u = input.U, v = input.V;

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

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

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

@ -1,4 +1,4 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Six Labors Split License. // Licensed under the Six Labors Split License.
using System.Numerics; using System.Numerics;
@ -49,7 +49,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public Lms Convert(in CieXyz input) public Lms Convert(in CieXyz input)
{ {
var vector = Vector3.Transform(input.ToVector3(), this.transformationMatrix); Vector3 vector = Vector3.Transform(input.ToVector3(), this.transformationMatrix);
return new Lms(vector); return new Lms(vector);
} }
@ -62,7 +62,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public CieXyz Convert(in Lms input) public CieXyz Convert(in Lms input)
{ {
var vector = Vector3.Transform(input.ToVector3(), this.inverseTransformationMatrix); Vector3 vector = Vector3.Transform(input.ToVector3(), this.inverseTransformationMatrix);
return new CieXyz(vector); return new CieXyz(vector);
} }

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

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

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

@ -10,7 +10,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// Color converter between HSL and Rgb /// Color converter between HSL and Rgb
/// See <see href="http://www.poynton.com/PDFs/coloureq.pdf"/> for formulas. /// See <see href="http://www.poynton.com/PDFs/coloureq.pdf"/> for formulas.
/// </summary> /// </summary>
internal sealed class HslAndRgbConverter internal static class HslAndRgbConverter
{ {
/// <summary> /// <summary>
/// Performs the conversion from the <see cref="Hsl"/> input to an instance of <see cref="Rgb"/> type. /// Performs the conversion from the <see cref="Hsl"/> input to an instance of <see cref="Rgb"/> type.
@ -18,7 +18,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <param name="input">The input color instance.</param> /// <param name="input">The input color instance.</param>
/// <returns>The converted result</returns> /// <returns>The converted result</returns>
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public Rgb Convert(in Hsl input) public static Rgb Convert(in Hsl input)
{ {
float rangedH = input.H / 360F; float rangedH = input.H / 360F;
float r = 0; float r = 0;
@ -53,7 +53,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <param name="input">The input color instance.</param> /// <param name="input">The input color instance.</param>
/// <returns>The converted result</returns> /// <returns>The converted result</returns>
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public Hsl Convert(in Rgb input) public static Hsl Convert(in Rgb input)
{ {
float r = input.R; float r = input.R;
float g = input.G; float g = input.G;

6
src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/HsvAndRgbConverter.cs

@ -10,7 +10,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// Color converter between HSV and Rgb /// Color converter between HSV and Rgb
/// See <see href="http://www.poynton.com/PDFs/coloureq.pdf"/> for formulas. /// See <see href="http://www.poynton.com/PDFs/coloureq.pdf"/> for formulas.
/// </summary> /// </summary>
internal sealed class HsvAndRgbConverter internal static class HsvAndRgbConverter
{ {
/// <summary> /// <summary>
/// Performs the conversion from the <see cref="Hsv"/> input to an instance of <see cref="Rgb"/> type. /// Performs the conversion from the <see cref="Hsv"/> input to an instance of <see cref="Rgb"/> type.
@ -18,7 +18,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <param name="input">The input color instance.</param> /// <param name="input">The input color instance.</param>
/// <returns>The converted result</returns> /// <returns>The converted result</returns>
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public Rgb Convert(in Hsv input) public static Rgb Convert(in Hsv input)
{ {
float s = input.S; float s = input.S;
float v = input.V; float v = input.V;
@ -85,7 +85,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <param name="input">The input color instance.</param> /// <param name="input">The input color instance.</param>
/// <returns>The converted result</returns> /// <returns>The converted result</returns>
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public Hsv Convert(in Rgb input) public static Hsv Convert(in Rgb input)
{ {
float r = input.R; float r = input.R;
float g = input.G; float g = input.G;

2
src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/HunterLabToCieXyzConverter.cs

@ -17,7 +17,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <param name="input">The input color instance.</param> /// <param name="input">The input color instance.</param>
/// <returns>The converted result</returns> /// <returns>The converted result</returns>
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public CieXyz Convert(in HunterLab input) public static CieXyz Convert(in HunterLab input)
{ {
// Conversion algorithm described here: http://en.wikipedia.org/wiki/Lab_color_space#Hunter_Lab // Conversion algorithm described here: http://en.wikipedia.org/wiki/Lab_color_space#Hunter_Lab
float l = input.L, a = input.A, b = input.B; float l = input.L, a = input.A, b = input.B;

19
src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/LinearRgbAndCieXyzConverterBase.cs

@ -28,25 +28,22 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
float yb = chromaticity.B.Y; float yb = chromaticity.B.Y;
float mXr = xr / yr; float mXr = xr / yr;
const float Yr = 1;
float mZr = (1 - xr - yr) / yr; float mZr = (1 - xr - yr) / yr;
float mXg = xg / yg; float mXg = xg / yg;
const float Yg = 1;
float mZg = (1 - xg - yg) / yg; float mZg = (1 - xg - yg) / yg;
float mXb = xb / yb; float mXb = xb / yb;
const float Yb = 1;
float mZb = (1 - xb - yb) / yb; float mZb = (1 - xb - yb) / yb;
var xyzMatrix = new Matrix4x4 Matrix4x4 xyzMatrix = new()
{ {
M11 = mXr, M11 = mXr,
M21 = mXg, M21 = mXg,
M31 = mXb, M31 = mXb,
M12 = Yr, M12 = 1F,
M22 = Yg, M22 = 1F,
M32 = Yb, M32 = 1F,
M13 = mZr, M13 = mZr,
M23 = mZg, M23 = mZg,
M33 = mZb, M33 = mZb,
@ -55,7 +52,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
Matrix4x4.Invert(xyzMatrix, out Matrix4x4 inverseXyzMatrix); Matrix4x4.Invert(xyzMatrix, out Matrix4x4 inverseXyzMatrix);
var vector = Vector3.Transform(workingSpace.WhitePoint.ToVector3(), inverseXyzMatrix); Vector3 vector = Vector3.Transform(workingSpace.WhitePoint.ToVector3(), inverseXyzMatrix);
// Use transposed Rows/Columns // Use transposed Rows/Columns
// TODO: Is there a built in method for this multiplication? // TODO: Is there a built in method for this multiplication?
@ -64,9 +61,9 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
M11 = vector.X * mXr, M11 = vector.X * mXr,
M21 = vector.Y * mXg, M21 = vector.Y * mXg,
M31 = vector.Z * mXb, M31 = vector.Z * mXb,
M12 = vector.X * Yr, M12 = vector.X * 1,
M22 = vector.Y * Yg, M22 = vector.Y * 1,
M32 = vector.Z * Yb, M32 = vector.Z * 1,
M13 = vector.X * mZr, M13 = vector.X * mZr,
M23 = vector.Y * mZg, M23 = vector.Y * mZg,
M33 = vector.Z * mZb, M33 = vector.Z * mZb,

2
src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/LinearRgbToCieXyzConverter.cs

@ -46,7 +46,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
{ {
DebugGuard.IsTrue(input.WorkingSpace.Equals(this.SourceWorkingSpace), nameof(input.WorkingSpace), "Input and source working spaces must be equal."); DebugGuard.IsTrue(input.WorkingSpace.Equals(this.SourceWorkingSpace), nameof(input.WorkingSpace), "Input and source working spaces must be equal.");
var vector = Vector3.Transform(input.ToVector3(), this.conversionMatrix); Vector3 vector = Vector3.Transform(input.ToVector3(), this.conversionMatrix);
return new CieXyz(vector); return new CieXyz(vector);
} }
} }

8
src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/LinearRgbToRgbConverter.cs

@ -8,7 +8,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <summary> /// <summary>
/// Color converter between <see cref="LinearRgb"/> and <see cref="Rgb"/>. /// Color converter between <see cref="LinearRgb"/> and <see cref="Rgb"/>.
/// </summary> /// </summary>
internal sealed class LinearRgbToRgbConverter internal static class LinearRgbToRgbConverter
{ {
/// <summary> /// <summary>
/// Performs the conversion from the <see cref="LinearRgb"/> input to an instance of <see cref="Rgb"/> type. /// Performs the conversion from the <see cref="LinearRgb"/> input to an instance of <see cref="Rgb"/> type.
@ -16,13 +16,11 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <param name="input">The input color instance.</param> /// <param name="input">The input color instance.</param>
/// <returns>The converted result.</returns> /// <returns>The converted result.</returns>
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public Rgb Convert(in LinearRgb input) public static Rgb Convert(in LinearRgb input) =>
{ new(
return new Rgb(
r: input.WorkingSpace.Compress(input.R), r: input.WorkingSpace.Compress(input.R),
g: input.WorkingSpace.Compress(input.G), g: input.WorkingSpace.Compress(input.G),
b: input.WorkingSpace.Compress(input.B), b: input.WorkingSpace.Compress(input.B),
workingSpace: input.WorkingSpace); workingSpace: input.WorkingSpace);
}
} }
} }

8
src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/RgbToLinearRgbConverter.cs

@ -8,7 +8,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <summary> /// <summary>
/// Color converter between Rgb and LinearRgb. /// Color converter between Rgb and LinearRgb.
/// </summary> /// </summary>
internal class RgbToLinearRgbConverter internal static class RgbToLinearRgbConverter
{ {
/// <summary> /// <summary>
/// Performs the conversion from the <see cref="Rgb"/> input to an instance of <see cref="LinearRgb"/> type. /// Performs the conversion from the <see cref="Rgb"/> input to an instance of <see cref="LinearRgb"/> type.
@ -16,13 +16,11 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <param name="input">The input color instance.</param> /// <param name="input">The input color instance.</param>
/// <returns>The converted result.</returns> /// <returns>The converted result.</returns>
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public LinearRgb Convert(in Rgb input) public static LinearRgb Convert(in Rgb input)
{ => new(
return new LinearRgb(
r: input.WorkingSpace.Expand(input.R), r: input.WorkingSpace.Expand(input.R),
g: input.WorkingSpace.Expand(input.G), g: input.WorkingSpace.Expand(input.G),
b: input.WorkingSpace.Expand(input.B), b: input.WorkingSpace.Expand(input.B),
workingSpace: input.WorkingSpace); workingSpace: input.WorkingSpace);
}
} }
} }

8
src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/YCbCrAndRgbConverter.cs

@ -11,9 +11,9 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// Color converter between <see cref="YCbCr"/> and <see cref="Rgb"/> /// Color converter between <see cref="YCbCr"/> and <see cref="Rgb"/>
/// See <see href="https://en.wikipedia.org/wiki/YCbCr#JPEG_conversion"/> for formulas. /// See <see href="https://en.wikipedia.org/wiki/YCbCr#JPEG_conversion"/> for formulas.
/// </summary> /// </summary>
internal sealed class YCbCrAndRgbConverter internal static class YCbCrAndRgbConverter
{ {
private static readonly Vector3 MaxBytes = new Vector3(255F); private static readonly Vector3 MaxBytes = new(255F);
/// <summary> /// <summary>
/// Performs the conversion from the <see cref="YCbCr"/> input to an instance of <see cref="Rgb"/> type. /// Performs the conversion from the <see cref="YCbCr"/> input to an instance of <see cref="Rgb"/> type.
@ -21,7 +21,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <param name="input">The input color instance.</param> /// <param name="input">The input color instance.</param>
/// <returns>The converted result.</returns> /// <returns>The converted result.</returns>
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public Rgb Convert(in YCbCr input) public static Rgb Convert(in YCbCr input)
{ {
float y = input.Y; float y = input.Y;
float cb = input.Cb - 128F; float cb = input.Cb - 128F;
@ -40,7 +40,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <param name="input">The input color instance.</param> /// <param name="input">The input color instance.</param>
/// <returns>The converted result.</returns> /// <returns>The converted result.</returns>
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public YCbCr Convert(in Rgb input) public static YCbCr Convert(in Rgb input)
{ {
Vector3 rgb = input.ToVector3() * MaxBytes; Vector3 rgb = input.ToVector3() * MaxBytes;
float r = rgb.X; float r = rgb.X;

2
src/ImageSharp/ColorSpaces/Conversion/Implementation/VonKriesChromaticAdaptation.cs

@ -75,7 +75,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
if (sourceWhitePoint.Equals(destinationWhitePoint)) if (sourceWhitePoint.Equals(destinationWhitePoint))
{ {
source.CopyTo(destination.Slice(0, count)); source.CopyTo(destination[..count]);
return; return;
} }

48
src/ImageSharp/ColorSpaces/Hsl.cs

@ -1,4 +1,4 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Six Labors Split License. // Licensed under the Six Labors Split License.
using System; using System;
@ -13,25 +13,7 @@ namespace SixLabors.ImageSharp.ColorSpaces
public readonly struct Hsl : IEquatable<Hsl> public readonly struct Hsl : IEquatable<Hsl>
{ {
private static readonly Vector3 Min = Vector3.Zero; private static readonly Vector3 Min = Vector3.Zero;
private static readonly Vector3 Max = new Vector3(360, 1, 1); private static readonly Vector3 Max = new(360, 1, 1);
/// <summary>
/// Gets the hue component.
/// <remarks>A value ranging between 0 and 360.</remarks>
/// </summary>
public readonly float H;
/// <summary>
/// Gets the saturation component.
/// <remarks>A value ranging between 0 and 1.</remarks>
/// </summary>
public readonly float S;
/// <summary>
/// Gets the lightness component.
/// <remarks>A value ranging between 0 and 1.</remarks>
/// </summary>
public readonly float L;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="Hsl"/> struct. /// Initializes a new instance of the <see cref="Hsl"/> struct.
@ -58,6 +40,24 @@ namespace SixLabors.ImageSharp.ColorSpaces
this.L = vector.Z; this.L = vector.Z;
} }
/// <summary>
/// Gets the hue component.
/// <remarks>A value ranging between 0 and 360.</remarks>
/// </summary>
public readonly float H { get; }
/// <summary>
/// Gets the saturation component.
/// <remarks>A value ranging between 0 and 1.</remarks>
/// </summary>
public readonly float S { get; }
/// <summary>
/// Gets the lightness component.
/// <remarks>A value ranging between 0 and 1.</remarks>
/// </summary>
public readonly float L { get; }
/// <summary> /// <summary>
/// Compares two <see cref="Hsl"/> objects for equality. /// Compares two <see cref="Hsl"/> objects for equality.
/// </summary> /// </summary>
@ -95,10 +95,8 @@ namespace SixLabors.ImageSharp.ColorSpaces
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public bool Equals(Hsl other) public bool Equals(Hsl other)
{ => this.H.Equals(other.H)
return this.H.Equals(other.H) && this.S.Equals(other.S)
&& this.S.Equals(other.S) && this.L.Equals(other.L);
&& this.L.Equals(other.L);
}
} }
} }

48
src/ImageSharp/ColorSpaces/Hsv.cs

@ -1,4 +1,4 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Six Labors Split License. // Licensed under the Six Labors Split License.
using System; using System;
@ -13,25 +13,7 @@ namespace SixLabors.ImageSharp.ColorSpaces
public readonly struct Hsv : IEquatable<Hsv> public readonly struct Hsv : IEquatable<Hsv>
{ {
private static readonly Vector3 Min = Vector3.Zero; private static readonly Vector3 Min = Vector3.Zero;
private static readonly Vector3 Max = new Vector3(360, 1, 1); private static readonly Vector3 Max = new(360, 1, 1);
/// <summary>
/// Gets the hue component.
/// <remarks>A value ranging between 0 and 360.</remarks>
/// </summary>
public readonly float H;
/// <summary>
/// Gets the saturation component.
/// <remarks>A value ranging between 0 and 1.</remarks>
/// </summary>
public readonly float S;
/// <summary>
/// Gets the value (brightness) component.
/// <remarks>A value ranging between 0 and 1.</remarks>
/// </summary>
public readonly float V;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="Hsv"/> struct. /// Initializes a new instance of the <see cref="Hsv"/> struct.
@ -58,6 +40,24 @@ namespace SixLabors.ImageSharp.ColorSpaces
this.V = vector.Z; this.V = vector.Z;
} }
/// <summary>
/// Gets the hue component.
/// <remarks>A value ranging between 0 and 360.</remarks>
/// </summary>
public readonly float H { get; }
/// <summary>
/// Gets the saturation component.
/// <remarks>A value ranging between 0 and 1.</remarks>
/// </summary>
public readonly float S { get; }
/// <summary>
/// Gets the value (brightness) component.
/// <remarks>A value ranging between 0 and 1.</remarks>
/// </summary>
public readonly float V { get; }
/// <summary> /// <summary>
/// Compares two <see cref="Hsv"/> objects for equality. /// Compares two <see cref="Hsv"/> objects for equality.
/// </summary> /// </summary>
@ -93,10 +93,8 @@ namespace SixLabors.ImageSharp.ColorSpaces
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public bool Equals(Hsv other) public bool Equals(Hsv other)
{ => this.H.Equals(other.H)
return this.H.Equals(other.H) && this.S.Equals(other.S)
&& this.S.Equals(other.S) && this.V.Equals(other.V);
&& this.V.Equals(other.V);
}
} }
} }

58
src/ImageSharp/ColorSpaces/HunterLab.cs

@ -1,4 +1,4 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Six Labors Split License. // Licensed under the Six Labors Split License.
using System; using System;
@ -19,29 +19,6 @@ namespace SixLabors.ImageSharp.ColorSpaces
/// </summary> /// </summary>
public static readonly CieXyz DefaultWhitePoint = Illuminants.C; public static readonly CieXyz DefaultWhitePoint = Illuminants.C;
/// <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;
/// <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;
/// <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;
/// <summary>
/// Gets the reference white point of this color.
/// </summary>
public readonly CieXyz WhitePoint;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="HunterLab"/> struct. /// Initializes a new instance of the <see cref="HunterLab"/> struct.
/// </summary> /// </summary>
@ -94,6 +71,29 @@ namespace SixLabors.ImageSharp.ColorSpaces
this.WhitePoint = whitePoint; 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> /// <summary>
/// Compares two <see cref="HunterLab"/> objects for equality. /// Compares two <see cref="HunterLab"/> objects for equality.
/// </summary> /// </summary>
@ -128,11 +128,9 @@ namespace SixLabors.ImageSharp.ColorSpaces
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public bool Equals(HunterLab other) public bool Equals(HunterLab other)
{ => this.L.Equals(other.L)
return this.L.Equals(other.L) && this.A.Equals(other.A)
&& this.A.Equals(other.A) && this.B.Equals(other.B)
&& this.B.Equals(other.B) && this.WhitePoint.Equals(other.WhitePoint);
&& this.WhitePoint.Equals(other.WhitePoint);
}
} }
} }

56
src/ImageSharp/ColorSpaces/LinearRgb.cs

@ -21,29 +21,6 @@ namespace SixLabors.ImageSharp.ColorSpaces
/// </summary> /// </summary>
public static readonly RgbWorkingSpace DefaultWorkingSpace = RgbWorkingSpaces.SRgb; public static readonly RgbWorkingSpace DefaultWorkingSpace = RgbWorkingSpaces.SRgb;
/// <summary>
/// Gets the red component.
/// <remarks>A value usually ranging between 0 and 1.</remarks>
/// </summary>
public readonly float R;
/// <summary>
/// Gets the green component.
/// <remarks>A value usually ranging between 0 and 1.</remarks>
/// </summary>
public readonly float G;
/// <summary>
/// Gets the blue component.
/// <remarks>A value usually ranging between 0 and 1.</remarks>
/// </summary>
public readonly float B;
/// <summary>
/// Gets the LinearRgb color space <seealso cref="RgbWorkingSpaces"/>
/// </summary>
public readonly RgbWorkingSpace WorkingSpace;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="LinearRgb"/> struct. /// Initializes a new instance of the <see cref="LinearRgb"/> struct.
/// </summary> /// </summary>
@ -95,6 +72,29 @@ namespace SixLabors.ImageSharp.ColorSpaces
this.WorkingSpace = workingSpace; this.WorkingSpace = workingSpace;
} }
/// <summary>
/// Gets the red component.
/// <remarks>A value usually ranging between 0 and 1.</remarks>
/// </summary>
public readonly float R { get; }
/// <summary>
/// Gets the green component.
/// <remarks>A value usually ranging between 0 and 1.</remarks>
/// </summary>
public readonly float G { get; }
/// <summary>
/// Gets the blue component.
/// <remarks>A value usually ranging between 0 and 1.</remarks>
/// </summary>
public readonly float B { get; }
/// <summary>
/// Gets the LinearRgb color space <seealso cref="RgbWorkingSpaces"/>
/// </summary>
public readonly RgbWorkingSpace WorkingSpace { get; }
/// <summary> /// <summary>
/// Compares two <see cref="LinearRgb"/> objects for equality. /// Compares two <see cref="LinearRgb"/> objects for equality.
/// </summary> /// </summary>
@ -122,7 +122,7 @@ namespace SixLabors.ImageSharp.ColorSpaces
/// </summary> /// </summary>
/// <returns>The <see cref="Vector3"/>.</returns> /// <returns>The <see cref="Vector3"/>.</returns>
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public Vector3 ToVector3() => new Vector3(this.R, this.G, this.B); public Vector3 ToVector3() => new(this.R, this.G, this.B);
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
@ -137,10 +137,8 @@ namespace SixLabors.ImageSharp.ColorSpaces
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public bool Equals(LinearRgb other) public bool Equals(LinearRgb other)
{ => this.R.Equals(other.R)
return this.R.Equals(other.R) && this.G.Equals(other.G)
&& this.G.Equals(other.G) && this.B.Equals(other.B);
&& this.B.Equals(other.B);
}
} }
} }

48
src/ImageSharp/ColorSpaces/Lms.cs

@ -1,4 +1,4 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Six Labors Split License. // Licensed under the Six Labors Split License.
using System; using System;
@ -14,24 +14,6 @@ namespace SixLabors.ImageSharp.ColorSpaces
/// </summary> /// </summary>
public readonly struct Lms : IEquatable<Lms> public readonly struct Lms : IEquatable<Lms>
{ {
/// <summary>
/// Gets the L long component.
/// <remarks>A value usually ranging between -1 and 1.</remarks>
/// </summary>
public readonly float L;
/// <summary>
/// Gets the M medium component.
/// <remarks>A value usually ranging between -1 and 1.</remarks>
/// </summary>
public readonly float M;
/// <summary>
/// Gets the S short component.
/// <remarks>A value usually ranging between -1 and 1.</remarks>
/// </summary>
public readonly float S;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="Lms"/> struct. /// Initializes a new instance of the <see cref="Lms"/> struct.
/// </summary> /// </summary>
@ -57,6 +39,24 @@ namespace SixLabors.ImageSharp.ColorSpaces
this.S = vector.Z; this.S = vector.Z;
} }
/// <summary>
/// Gets the L long component.
/// <remarks>A value usually ranging between -1 and 1.</remarks>
/// </summary>
public readonly 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; }
/// <summary>
/// Gets the S short component.
/// <remarks>A value usually ranging between -1 and 1.</remarks>
/// </summary>
public readonly float S { get; }
/// <summary> /// <summary>
/// Compares two <see cref="Lms"/> objects for equality. /// Compares two <see cref="Lms"/> objects for equality.
/// </summary> /// </summary>
@ -84,7 +84,7 @@ namespace SixLabors.ImageSharp.ColorSpaces
/// </summary> /// </summary>
/// <returns>The <see cref="Vector3"/>.</returns> /// <returns>The <see cref="Vector3"/>.</returns>
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public Vector3 ToVector3() => new Vector3(this.L, this.M, this.S); public Vector3 ToVector3() => new(this.L, this.M, this.S);
/// <inheritdoc/> /// <inheritdoc/>
public override int GetHashCode() => HashCode.Combine(this.L, this.M, this.S); public override int GetHashCode() => HashCode.Combine(this.L, this.M, this.S);
@ -98,10 +98,8 @@ namespace SixLabors.ImageSharp.ColorSpaces
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public bool Equals(Lms other) public bool Equals(Lms other)
{ => this.L.Equals(other.L)
return this.L.Equals(other.L) && this.M.Equals(other.M)
&& this.M.Equals(other.M) && this.S.Equals(other.S);
&& this.S.Equals(other.S);
}
} }
} }

60
src/ImageSharp/ColorSpaces/Rgb.cs

@ -22,29 +22,6 @@ namespace SixLabors.ImageSharp.ColorSpaces
private static readonly Vector3 Min = Vector3.Zero; private static readonly Vector3 Min = Vector3.Zero;
private static readonly Vector3 Max = Vector3.One; private static readonly Vector3 Max = Vector3.One;
/// <summary>
/// Gets the red component.
/// <remarks>A value usually ranging between 0 and 1.</remarks>
/// </summary>
public readonly float R;
/// <summary>
/// Gets the green component.
/// <remarks>A value usually ranging between 0 and 1.</remarks>
/// </summary>
public readonly float G;
/// <summary>
/// Gets the blue component.
/// <remarks>A value usually ranging between 0 and 1.</remarks>
/// </summary>
public readonly float B;
/// <summary>
/// Gets the Rgb color space <seealso cref="RgbWorkingSpaces"/>
/// </summary>
public readonly RgbWorkingSpace WorkingSpace;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="Rgb"/> struct. /// Initializes a new instance of the <see cref="Rgb"/> struct.
/// </summary> /// </summary>
@ -95,6 +72,29 @@ namespace SixLabors.ImageSharp.ColorSpaces
this.WorkingSpace = workingSpace; this.WorkingSpace = workingSpace;
} }
/// <summary>
/// Gets the red component.
/// <remarks>A value usually ranging between 0 and 1.</remarks>
/// </summary>
public readonly float R { get; }
/// <summary>
/// Gets the green component.
/// <remarks>A value usually ranging between 0 and 1.</remarks>
/// </summary>
public readonly float G { get; }
/// <summary>
/// Gets the blue component.
/// <remarks>A value usually ranging between 0 and 1.</remarks>
/// </summary>
public readonly float B { get; }
/// <summary>
/// Gets the Rgb color space <seealso cref="RgbWorkingSpaces"/>
/// </summary>
public readonly RgbWorkingSpace WorkingSpace { get; }
/// <summary> /// <summary>
/// Allows the implicit conversion of an instance of <see cref="Rgb24"/> to a /// Allows the implicit conversion of an instance of <see cref="Rgb24"/> to a
/// <see cref="Rgb"/>. /// <see cref="Rgb"/>.
@ -102,7 +102,7 @@ namespace SixLabors.ImageSharp.ColorSpaces
/// <param name="color">The instance of <see cref="Rgba32"/> to convert.</param> /// <param name="color">The instance of <see cref="Rgba32"/> to convert.</param>
/// <returns>An instance of <see cref="Rgb"/>.</returns> /// <returns>An instance of <see cref="Rgb"/>.</returns>
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public static implicit operator Rgb(Rgb24 color) => new Rgb(color.R / 255F, color.G / 255F, color.B / 255F); public static implicit operator Rgb(Rgb24 color) => new(color.R / 255F, color.G / 255F, color.B / 255F);
/// <summary> /// <summary>
/// Allows the implicit conversion of an instance of <see cref="Rgba32"/> to a /// Allows the implicit conversion of an instance of <see cref="Rgba32"/> to a
@ -111,7 +111,7 @@ namespace SixLabors.ImageSharp.ColorSpaces
/// <param name="color">The instance of <see cref="Rgba32"/> to convert.</param> /// <param name="color">The instance of <see cref="Rgba32"/> to convert.</param>
/// <returns>An instance of <see cref="Rgb"/>.</returns> /// <returns>An instance of <see cref="Rgb"/>.</returns>
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public static implicit operator Rgb(Rgba32 color) => new Rgb(color.R / 255F, color.G / 255F, color.B / 255F); public static implicit operator Rgb(Rgba32 color) => new(color.R / 255F, color.G / 255F, color.B / 255F);
/// <summary> /// <summary>
/// Compares two <see cref="Rgb"/> objects for equality. /// Compares two <see cref="Rgb"/> objects for equality.
@ -144,7 +144,7 @@ namespace SixLabors.ImageSharp.ColorSpaces
/// </summary> /// </summary>
/// <returns>The <see cref="Vector3"/>.</returns> /// <returns>The <see cref="Vector3"/>.</returns>
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public Vector3 ToVector3() => new Vector3(this.R, this.G, this.B); public Vector3 ToVector3() => new(this.R, this.G, this.B);
/// <inheritdoc/> /// <inheritdoc/>
public override int GetHashCode() => HashCode.Combine(this.R, this.G, this.B); public override int GetHashCode() => HashCode.Combine(this.R, this.G, this.B);
@ -158,10 +158,8 @@ namespace SixLabors.ImageSharp.ColorSpaces
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public bool Equals(Rgb other) public bool Equals(Rgb other)
{ => this.R.Equals(other.R)
return this.R.Equals(other.R) && this.G.Equals(other.G)
&& this.G.Equals(other.G) && this.B.Equals(other.B);
&& this.B.Equals(other.B);
}
} }
} }

46
src/ImageSharp/ColorSpaces/YCbCr.cs

@ -15,25 +15,7 @@ namespace SixLabors.ImageSharp.ColorSpaces
public readonly struct YCbCr : IEquatable<YCbCr> public readonly struct YCbCr : IEquatable<YCbCr>
{ {
private static readonly Vector3 Min = Vector3.Zero; private static readonly Vector3 Min = Vector3.Zero;
private static readonly Vector3 Max = new Vector3(255); private static readonly Vector3 Max = new(255);
/// <summary>
/// Gets the Y luminance component.
/// <remarks>A value ranging between 0 and 255.</remarks>
/// </summary>
public readonly float Y;
/// <summary>
/// Gets the Cb chroma component.
/// <remarks>A value ranging between 0 and 255.</remarks>
/// </summary>
public readonly float Cb;
/// <summary>
/// Gets the Cr chroma component.
/// <remarks>A value ranging between 0 and 255.</remarks>
/// </summary>
public readonly float Cr;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="YCbCr"/> struct. /// Initializes a new instance of the <see cref="YCbCr"/> struct.
@ -60,6 +42,24 @@ namespace SixLabors.ImageSharp.ColorSpaces
this.Cr = vector.Z; this.Cr = vector.Z;
} }
/// <summary>
/// Gets the Y luminance component.
/// <remarks>A value ranging between 0 and 255.</remarks>
/// </summary>
public readonly float Y { get; }
/// <summary>
/// Gets the Cb chroma component.
/// <remarks>A value ranging between 0 and 255.</remarks>
/// </summary>
public readonly float Cb { get; }
/// <summary>
/// Gets the Cr chroma component.
/// <remarks>A value ranging between 0 and 255.</remarks>
/// </summary>
public readonly float Cr { get; }
/// <summary> /// <summary>
/// Compares two <see cref="YCbCr"/> objects for equality. /// Compares two <see cref="YCbCr"/> objects for equality.
/// </summary> /// </summary>
@ -94,10 +94,8 @@ namespace SixLabors.ImageSharp.ColorSpaces
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public bool Equals(YCbCr other) public bool Equals(YCbCr other)
{ => this.Y.Equals(other.Y)
return this.Y.Equals(other.Y) && this.Cb.Equals(other.Cb)
&& this.Cb.Equals(other.Cb) && this.Cr.Equals(other.Cr);
&& this.Cr.Equals(other.Cr);
}
} }
} }

35
src/ImageSharp/Common/Extensions/EncoderExtensions.cs

@ -1,35 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
#if !SUPPORTS_ENCODING_STRING
using System;
using System.Text;
namespace SixLabors.ImageSharp
{
/// <summary>
/// Extension methods for the <see cref="Encoder"/> type.
/// </summary>
internal static unsafe class EncoderExtensions
{
/// <summary>
/// Gets a string from the provided buffer data.
/// </summary>
/// <param name="encoding">The encoding.</param>
/// <param name="buffer">The buffer.</param>
/// <returns>The string.</returns>
public static string GetString(this Encoding encoding, ReadOnlySpan<byte> buffer)
{
if (buffer.Length == 0)
{
return string.Empty;
}
fixed (byte* bytes = buffer)
{
return encoding.GetString(bytes, buffer.Length);
}
}
}
}
#endif

46
src/ImageSharp/Common/Extensions/StreamExtensions.cs

@ -70,51 +70,5 @@ namespace SixLabors.ImageSharp
ArrayPool<byte>.Shared.Return(buffer); ArrayPool<byte>.Shared.Return(buffer);
} }
} }
#if !SUPPORTS_SPAN_STREAM
// This is a port of the CoreFX implementation and is MIT Licensed:
// https://github.com/dotnet/corefx/blob/17300169760c61a90cab8d913636c1058a30a8c1/src/Common/src/CoreLib/System/IO/Stream.cs#L742
public static int Read(this Stream stream, Span<byte> buffer)
{
// This uses ArrayPool<byte>.Shared, rather than taking a MemoryAllocator,
// in order to match the signature of the framework method that exists in
// .NET Core.
byte[] sharedBuffer = ArrayPool<byte>.Shared.Rent(buffer.Length);
try
{
int numRead = stream.Read(sharedBuffer, 0, buffer.Length);
if ((uint)numRead > (uint)buffer.Length)
{
throw new IOException("Stream was too long.");
}
new Span<byte>(sharedBuffer, 0, numRead).CopyTo(buffer);
return numRead;
}
finally
{
ArrayPool<byte>.Shared.Return(sharedBuffer);
}
}
// This is a port of the CoreFX implementation and is MIT Licensed:
// https://github.com/dotnet/corefx/blob/17300169760c61a90cab8d913636c1058a30a8c1/src/Common/src/CoreLib/System/IO/Stream.cs#L775
public static void Write(this Stream stream, ReadOnlySpan<byte> buffer)
{
// This uses ArrayPool<byte>.Shared, rather than taking a MemoryAllocator,
// in order to match the signature of the framework method that exists in
// .NET Core.
byte[] sharedBuffer = ArrayPool<byte>.Shared.Rent(buffer.Length);
try
{
buffer.CopyTo(sharedBuffer);
stream.Write(sharedBuffer, 0, buffer.Length);
}
finally
{
ArrayPool<byte>.Shared.Return(sharedBuffer);
}
}
#endif
} }
} }

2
src/ImageSharp/Common/Helpers/HexConverter.cs

@ -30,7 +30,7 @@ namespace SixLabors.ImageSharp.Common.Helpers
{ {
// Slightly better performance in the loop below, allows us to skip a bounds check // Slightly better performance in the loop below, allows us to skip a bounds check
// while still supporting output buffers that are larger than necessary // while still supporting output buffers that are larger than necessary
bytes = bytes.Slice(0, chars.Length / 2); bytes = bytes[..(chars.Length / 2)];
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]

6
src/ImageSharp/Common/Helpers/InliningOptions.cs

@ -18,13 +18,11 @@ namespace SixLabors.ImageSharp
public const MethodImplOptions AlwaysInline = MethodImplOptions.AggressiveInlining; public const MethodImplOptions AlwaysInline = MethodImplOptions.AggressiveInlining;
#if PROFILING #if PROFILING
public const MethodImplOptions HotPath = MethodImplOptions.NoInlining; public const MethodImplOptions HotPath = MethodImplOptions.NoInlining;
public const MethodImplOptions ShortMethod = MethodImplOptions.NoInlining; public const MethodImplOptions ShortMethod = MethodImplOptions.NoInlining;
#else #else
#if SUPPORTS_HOTPATH
public const MethodImplOptions HotPath = MethodImplOptions.AggressiveOptimization; public const MethodImplOptions HotPath = MethodImplOptions.AggressiveOptimization;
#else
public const MethodImplOptions HotPath = MethodImplOptions.AggressiveInlining;
#endif
public const MethodImplOptions ShortMethod = MethodImplOptions.AggressiveInlining; public const MethodImplOptions ShortMethod = MethodImplOptions.AggressiveInlining;
#endif #endif
public const MethodImplOptions ColdPath = MethodImplOptions.NoInlining; public const MethodImplOptions ColdPath = MethodImplOptions.NoInlining;

146
src/ImageSharp/Common/Helpers/Numerics.cs

@ -5,10 +5,8 @@ using System;
using System.Numerics; using System.Numerics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
#if SUPPORTS_RUNTIME_INTRINSICS
using System.Runtime.Intrinsics; using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.X86; using System.Runtime.Intrinsics.X86;
#endif
namespace SixLabors.ImageSharp namespace SixLabors.ImageSharp
{ {
@ -18,20 +16,8 @@ namespace SixLabors.ImageSharp
/// </summary> /// </summary>
internal static class Numerics internal static class Numerics
{ {
#if SUPPORTS_RUNTIME_INTRINSICS
public const int BlendAlphaControl = 0b_10_00_10_00; public const int BlendAlphaControl = 0b_10_00_10_00;
private const int ShuffleAlphaControl = 0b_11_11_11_11; private const int ShuffleAlphaControl = 0b_11_11_11_11;
#endif
#if !SUPPORTS_BITOPERATIONS
private static ReadOnlySpan<byte> Log2DeBruijn => new byte[32]
{
00, 09, 01, 10, 13, 21, 02, 29,
11, 14, 16, 18, 22, 25, 03, 30,
08, 12, 20, 28, 15, 17, 24, 07,
19, 27, 23, 06, 26, 05, 04, 31
};
#endif
/// <summary> /// <summary>
/// Determine the Greatest CommonDivisor (GCD) of two numbers. /// Determine the Greatest CommonDivisor (GCD) of two numbers.
@ -129,13 +115,13 @@ namespace SixLabors.ImageSharp
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float Gaussian(float x, float sigma) public static float Gaussian(float x, float sigma)
{ {
const float Numerator = 1.0f; const float numerator = 1.0f;
float denominator = MathF.Sqrt(2 * MathF.PI) * sigma; float denominator = MathF.Sqrt(2 * MathF.PI) * sigma;
float exponentNumerator = -x * x; float exponentNumerator = -x * x;
float exponentDenominator = 2 * Pow2(sigma); float exponentDenominator = 2 * Pow2(sigma);
float left = Numerator / denominator; float left = numerator / denominator;
float right = MathF.Exp(exponentNumerator / exponentDenominator); float right = MathF.Exp(exponentNumerator / exponentDenominator);
return left * right; return left * right;
@ -300,7 +286,7 @@ namespace SixLabors.ImageSharp
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Clamp(Span<byte> span, byte min, byte max) public static void Clamp(Span<byte> span, byte min, byte max)
{ {
Span<byte> remainder = span.Slice(ClampReduce(span, min, max)); Span<byte> remainder = span[ClampReduce(span, min, max)..];
if (remainder.Length > 0) if (remainder.Length > 0)
{ {
@ -325,7 +311,7 @@ namespace SixLabors.ImageSharp
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Clamp(Span<uint> span, uint min, uint max) public static void Clamp(Span<uint> span, uint min, uint max)
{ {
Span<uint> remainder = span.Slice(ClampReduce(span, min, max)); Span<uint> remainder = span[ClampReduce(span, min, max)..];
if (remainder.Length > 0) if (remainder.Length > 0)
{ {
@ -350,7 +336,7 @@ namespace SixLabors.ImageSharp
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Clamp(Span<int> span, int min, int max) public static void Clamp(Span<int> span, int min, int max)
{ {
Span<int> remainder = span.Slice(ClampReduce(span, min, max)); Span<int> remainder = span[ClampReduce(span, min, max)..];
if (remainder.Length > 0) if (remainder.Length > 0)
{ {
@ -375,7 +361,7 @@ namespace SixLabors.ImageSharp
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Clamp(Span<float> span, float min, float max) public static void Clamp(Span<float> span, float min, float max)
{ {
Span<float> remainder = span.Slice(ClampReduce(span, min, max)); Span<float> remainder = span[ClampReduce(span, min, max)..];
if (remainder.Length > 0) if (remainder.Length > 0)
{ {
@ -400,7 +386,7 @@ namespace SixLabors.ImageSharp
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Clamp(Span<double> span, double min, double max) public static void Clamp(Span<double> span, double min, double max)
{ {
Span<double> remainder = span.Slice(ClampReduce(span, min, max)); Span<double> remainder = span[ClampReduce(span, min, max)..];
if (remainder.Length > 0) if (remainder.Length > 0)
{ {
@ -427,7 +413,7 @@ namespace SixLabors.ImageSharp
if (adjustedCount > 0) if (adjustedCount > 0)
{ {
ClampImpl(span.Slice(0, adjustedCount), min, max); ClampImpl(span[..adjustedCount], min, max);
} }
return adjustedCount; return adjustedCount;
@ -512,7 +498,6 @@ namespace SixLabors.ImageSharp
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Premultiply(Span<Vector4> vectors) public static void Premultiply(Span<Vector4> vectors)
{ {
#if SUPPORTS_RUNTIME_INTRINSICS
if (Avx2.IsSupported && vectors.Length >= 2) if (Avx2.IsSupported && vectors.Length >= 2)
{ {
// Divide by 2 as 4 elements per Vector4 and 8 per Vector256<float> // Divide by 2 as 4 elements per Vector4 and 8 per Vector256<float>
@ -530,11 +515,10 @@ namespace SixLabors.ImageSharp
if (Modulo2(vectors.Length) != 0) if (Modulo2(vectors.Length) != 0)
{ {
// Vector4 fits neatly in pairs. Any overlap has to be equal to 1. // Vector4 fits neatly in pairs. Any overlap has to be equal to 1.
Premultiply(ref MemoryMarshal.GetReference(vectors.Slice(vectors.Length - 1))); Premultiply(ref MemoryMarshal.GetReference(vectors[^1..]));
} }
} }
else else
#endif
{ {
ref Vector4 vectorsStart = ref MemoryMarshal.GetReference(vectors); ref Vector4 vectorsStart = ref MemoryMarshal.GetReference(vectors);
ref Vector4 vectorsEnd = ref Unsafe.Add(ref vectorsStart, vectors.Length); ref Vector4 vectorsEnd = ref Unsafe.Add(ref vectorsStart, vectors.Length);
@ -555,7 +539,6 @@ namespace SixLabors.ImageSharp
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void UnPremultiply(Span<Vector4> vectors) public static void UnPremultiply(Span<Vector4> vectors)
{ {
#if SUPPORTS_RUNTIME_INTRINSICS
if (Avx2.IsSupported && vectors.Length >= 2) if (Avx2.IsSupported && vectors.Length >= 2)
{ {
// Divide by 2 as 4 elements per Vector4 and 8 per Vector256<float> // Divide by 2 as 4 elements per Vector4 and 8 per Vector256<float>
@ -573,11 +556,10 @@ namespace SixLabors.ImageSharp
if (Modulo2(vectors.Length) != 0) if (Modulo2(vectors.Length) != 0)
{ {
// Vector4 fits neatly in pairs. Any overlap has to be equal to 1. // Vector4 fits neatly in pairs. Any overlap has to be equal to 1.
UnPremultiply(ref MemoryMarshal.GetReference(vectors.Slice(vectors.Length - 1))); UnPremultiply(ref MemoryMarshal.GetReference(vectors[^1..]));
} }
} }
else else
#endif
{ {
ref Vector4 vectorsStart = ref MemoryMarshal.GetReference(vectors); ref Vector4 vectorsStart = ref MemoryMarshal.GetReference(vectors);
ref Vector4 vectorsEnd = ref Unsafe.Add(ref vectorsStart, vectors.Length); ref Vector4 vectorsEnd = ref Unsafe.Add(ref vectorsStart, vectors.Length);
@ -627,7 +609,6 @@ namespace SixLabors.ImageSharp
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe void CubeRootOnXYZ(Span<Vector4> vectors) public static unsafe void CubeRootOnXYZ(Span<Vector4> vectors)
{ {
#if SUPPORTS_RUNTIME_INTRINSICS
if (Sse41.IsSupported) if (Sse41.IsSupported)
{ {
ref Vector128<float> vectors128Ref = ref Unsafe.As<Vector4, Vector128<float>>(ref MemoryMarshal.GetReference(vectors)); ref Vector128<float> vectors128Ref = ref Unsafe.As<Vector4, Vector128<float>>(ref MemoryMarshal.GetReference(vectors));
@ -678,7 +659,6 @@ namespace SixLabors.ImageSharp
} }
} }
else else
#endif
{ {
ref Vector4 vectorsRef = ref MemoryMarshal.GetReference(vectors); ref Vector4 vectorsRef = ref MemoryMarshal.GetReference(vectors);
ref Vector4 vectorsEnd = ref Unsafe.Add(ref vectorsRef, vectors.Length); ref Vector4 vectorsEnd = ref Unsafe.Add(ref vectorsRef, vectors.Length);
@ -727,8 +707,6 @@ namespace SixLabors.ImageSharp
} }
} }
#if SUPPORTS_RUNTIME_INTRINSICS
/// <summary> /// <summary>
/// Performs a linear interpolation between two values based on the given weighting. /// Performs a linear interpolation between two values based on the given weighting.
/// </summary> /// </summary>
@ -752,7 +730,6 @@ namespace SixLabors.ImageSharp
return Avx.Add(Avx.Multiply(diff, amount), value1); return Avx.Add(Avx.Multiply(diff, amount), value1);
} }
} }
#endif
/// <summary> /// <summary>
/// Performs a linear interpolation between two values based on the given weighting. /// Performs a linear interpolation between two values based on the given weighting.
@ -765,8 +742,6 @@ namespace SixLabors.ImageSharp
public static float Lerp(float value1, float value2, float amount) public static float Lerp(float value1, float value2, float amount)
=> ((value2 - value1) * amount) + value1; => ((value2 - value1) * amount) + value1;
#if SUPPORTS_RUNTIME_INTRINSICS
/// <summary> /// <summary>
/// Accumulates 8-bit integers into <paramref name="accumulator"/> by /// Accumulates 8-bit integers into <paramref name="accumulator"/> by
/// widening them to 32-bit integers and performing four additions. /// widening them to 32-bit integers and performing four additions.
@ -860,51 +835,6 @@ namespace SixLabors.ImageSharp
// Vector128<int>.ToScalar() isn't optimized pre-net5.0 https://github.com/dotnet/runtime/pull/37882 // Vector128<int>.ToScalar() isn't optimized pre-net5.0 https://github.com/dotnet/runtime/pull/37882
return Sse2.ConvertToInt32(vsum); return Sse2.ConvertToInt32(vsum);
} }
#endif
/// <summary>
/// Calculates floored log of the specified value, base 2.
/// Note that by convention, input value 0 returns 0 since Log(0) is undefined.
/// </summary>
/// <param name="value">The value.</param>
public static int Log2(uint value)
{
#if SUPPORTS_BITOPERATIONS
return BitOperations.Log2(value);
#else
return Log2SoftwareFallback(value);
#endif
}
#if !SUPPORTS_BITOPERATIONS
/// <summary>
/// Calculates floored log of the specified value, base 2.
/// Note that by convention, input value 0 returns 0 since Log(0) is undefined.
/// Bit hacking with deBruijn sequence, extremely fast yet does not use any intrinsics so will work on every platform/runtime.
/// </summary>
/// <remarks>
/// Description of this bit hacking can be found here:
/// https://cstheory.stackexchange.com/questions/19524/using-the-de-bruijn-sequence-to-find-the-lceil-log-2-v-rceil-of-an-integer
/// </remarks>
/// <param name="value">The value.</param>
private static int Log2SoftwareFallback(uint value)
{
// No AggressiveInlining due to large method size
// Has conventional contract 0->0 (Log(0) is undefined) by default, no need for if checking
// Fill trailing zeros with ones, eg 00010010 becomes 00011111
value |= value >> 01;
value |= value >> 02;
value |= value >> 04;
value |= value >> 08;
value |= value >> 16;
// uint.MaxValue >> 27 is always in range [0 - 31] so we use Unsafe.AddByteOffset to avoid bounds check
return Unsafe.AddByteOffset(
ref MemoryMarshal.GetReference(Log2DeBruijn),
(IntPtr)(int)((value * 0x07C4ACDDu) >> 27)); // uint|long -> IntPtr cast on 32-bit platforms does expensive overflow checks not needed here
}
#endif
/// <summary> /// <summary>
/// Fast division with ceiling for <see cref="uint"/> numbers. /// Fast division with ceiling for <see cref="uint"/> numbers.
@ -914,62 +844,6 @@ namespace SixLabors.ImageSharp
/// <returns>Ceiled division result.</returns> /// <returns>Ceiled division result.</returns>
public static uint DivideCeil(uint value, uint divisor) => (value + divisor - 1) / divisor; public static uint DivideCeil(uint value, uint divisor) => (value + divisor - 1) / divisor;
/// <summary>
/// Rotates the specified value left by the specified number of bits.
/// </summary>
/// <param name="value">The value to rotate.</param>
/// <param name="offset">The number of bits to rotate with.</param>
/// <returns>The rotated value.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static uint RotateLeft(uint value, int offset)
{
#if SUPPORTS_BITOPERATIONS
return BitOperations.RotateLeft(value, offset);
#else
return RotateLeftSoftwareFallback(value, offset);
#endif
}
#if !SUPPORTS_BITOPERATIONS
/// <summary>
/// Rotates the specified value left by the specified number of bits.
/// </summary>
/// <param name="value">The value to rotate.</param>
/// <param name="offset">The number of bits to rotate with.</param>
/// <returns>The rotated value.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static uint RotateLeftSoftwareFallback(uint value, int offset)
=> (value << offset) | (value >> (32 - offset));
#endif
/// <summary>
/// Rotates the specified value right by the specified number of bits.
/// </summary>
/// <param name="value">The value to rotate.</param>
/// <param name="offset">The number of bits to rotate with.</param>
/// <returns>The rotated value.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static uint RotateRight(uint value, int offset)
{
#if SUPPORTS_BITOPERATIONS
return BitOperations.RotateRight(value, offset);
#else
return RotateRightSoftwareFallback(value, offset);
#endif
}
#if !SUPPORTS_BITOPERATIONS
/// <summary>
/// Rotates the specified value right by the specified number of bits.
/// </summary>
/// <param name="value">The value to rotate.</param>
/// <param name="offset">The number of bits to rotate with.</param>
/// <returns>The rotated value.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static uint RotateRightSoftwareFallback(uint value, int offset)
=> (value >> offset) | (value << (32 - offset));
#endif
/// <summary> /// <summary>
/// Tells whether input value is outside of the given range. /// Tells whether input value is outside of the given range.
/// </summary> /// </summary>

32
src/ImageSharp/Common/Helpers/RuntimeEnvironment.cs

@ -1,32 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System;
using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp
{
/// <summary>
/// Provides information about the .NET runtime installation.
/// Many methods defer to <see cref="RuntimeInformation"/> when available.
/// </summary>
internal static class RuntimeEnvironment
{
private static readonly Lazy<bool> IsNetCoreLazy = new Lazy<bool>(() => FrameworkDescription.StartsWith(".NET Core", StringComparison.OrdinalIgnoreCase));
/// <summary>
/// Gets a value indicating whether the .NET installation is .NET Core 3.1 or lower.
/// </summary>
public static bool IsNetCore => IsNetCoreLazy.Value;
/// <summary>
/// Gets the name of the .NET installation on which an app is running.
/// </summary>
public static string FrameworkDescription => RuntimeInformation.FrameworkDescription;
/// <summary>
/// Indicates whether the current application is running on the specified platform.
/// </summary>
public static bool IsOSPlatform(OSPlatform osPlatform) => RuntimeInformation.IsOSPlatform(osPlatform);
}
}

46
src/ImageSharp/Common/Helpers/RuntimeUtility.cs

@ -0,0 +1,46 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System;
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.Common.Helpers
{
/// <summary>
/// A helper class that with utility methods for dealing with references, and other low-level details.
/// </summary>
internal static class RuntimeUtility
{
// Tuple swap uses 2 more IL bytes
#pragma warning disable IDE0180 // Use tuple to swap values
/// <summary>
/// Swaps the two references.
/// </summary>
/// <typeparam name="T">The type to swap.</typeparam>
/// <param name="a">The first item.</param>
/// <param name="b">The second item.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Swap<T>(ref T a, ref T b)
{
T tmp = a;
a = b;
b = tmp;
}
/// <summary>
/// Swaps the two references.
/// </summary>
/// <typeparam name="T">The type to swap.</typeparam>
/// <param name="a">The first item.</param>
/// <param name="b">The second item.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Swap<T>(ref Span<T> a, ref Span<T> b)
{
// Tuple swap uses 2 more IL bytes
Span<T> tmp = a;
a = b;
b = tmp;
}
#pragma warning restore IDE0180 // Use tuple to swap values
}
}

7
src/ImageSharp/Common/Helpers/Shuffle/IComponentShuffle.cs

@ -3,6 +3,7 @@
using System; using System;
using System.Buffers.Binary; using System.Buffers.Binary;
using System.Numerics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
@ -157,7 +158,7 @@ namespace SixLabors.ImageSharp
// packed = [W Z Y X] // packed = [W Z Y X]
// ROTR(8, packedArgb) = [Y Z W X] // ROTR(8, packedArgb) = [Y Z W X]
Unsafe.Add(ref dBase, i) = Numerics.RotateRight(packed, 8); Unsafe.Add(ref dBase, i) = BitOperations.RotateRight(packed, 8);
} }
} }
} }
@ -188,7 +189,7 @@ namespace SixLabors.ImageSharp
// tmp1 + tmp3 = [W X Y Z] // tmp1 + tmp3 = [W X Y Z]
uint tmp1 = packed & 0xFF00FF00; uint tmp1 = packed & 0xFF00FF00;
uint tmp2 = packed & 0x00FF00FF; uint tmp2 = packed & 0x00FF00FF;
uint tmp3 = Numerics.RotateLeft(tmp2, 16); uint tmp3 = BitOperations.RotateLeft(tmp2, 16);
Unsafe.Add(ref dBase, i) = tmp1 + tmp3; Unsafe.Add(ref dBase, i) = tmp1 + tmp3;
} }
@ -221,7 +222,7 @@ namespace SixLabors.ImageSharp
// tmp1 + tmp3 = [Y Z W X] // tmp1 + tmp3 = [Y Z W X]
uint tmp1 = packed & 0x00FF00FF; uint tmp1 = packed & 0x00FF00FF;
uint tmp2 = packed & 0xFF00FF00; uint tmp2 = packed & 0xFF00FF00;
uint tmp3 = Numerics.RotateLeft(tmp2, 16); uint tmp3 = BitOperations.RotateLeft(tmp2, 16);
Unsafe.Add(ref dBase, i) = tmp1 + tmp3; Unsafe.Add(ref dBase, i) = tmp1 + tmp3;
} }

216
src/ImageSharp/Common/Helpers/SimdUtils.BasicIntrinsics256.cs

@ -1,216 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Tuples;
// ReSharper disable MemberHidesStaticFromOuterClass
namespace SixLabors.ImageSharp
{
internal static partial class SimdUtils
{
/// <summary>
/// Implementation with 256bit / AVX2 intrinsics NOT depending on newer API-s (Vector.Widen etc.)
/// </summary>
public static class BasicIntrinsics256
{
public static bool IsAvailable { get; } = HasVector8;
#if !SUPPORTS_EXTENDED_INTRINSICS
/// <summary>
/// <see cref="ByteToNormalizedFloat"/> as many elements as possible, slicing them down (keeping the remainder).
/// </summary>
[MethodImpl(InliningOptions.ShortMethod)]
internal static void ByteToNormalizedFloatReduce(
ref ReadOnlySpan<byte> source,
ref Span<float> dest)
{
DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!");
if (!IsAvailable)
{
return;
}
int remainder = Numerics.Modulo8(source.Length);
int adjustedCount = source.Length - remainder;
if (adjustedCount > 0)
{
ByteToNormalizedFloat(
source.Slice(0, adjustedCount),
dest.Slice(0, adjustedCount));
source = source.Slice(adjustedCount);
dest = dest.Slice(adjustedCount);
}
}
/// <summary>
/// <see cref="NormalizedFloatToByteSaturate"/> as many elements as possible, slicing them down (keeping the remainder).
/// </summary>
[MethodImpl(InliningOptions.ShortMethod)]
internal static void NormalizedFloatToByteSaturateReduce(
ref ReadOnlySpan<float> source,
ref Span<byte> dest)
{
DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!");
if (!IsAvailable)
{
return;
}
int remainder = Numerics.Modulo8(source.Length);
int adjustedCount = source.Length - remainder;
if (adjustedCount > 0)
{
NormalizedFloatToByteSaturate(source.Slice(0, adjustedCount), dest.Slice(0, adjustedCount));
source = source.Slice(adjustedCount);
dest = dest.Slice(adjustedCount);
}
}
#endif
/// <summary>
/// SIMD optimized implementation for <see cref="SimdUtils.ByteToNormalizedFloat"/>.
/// Works only with span Length divisible by 8.
/// Implementation adapted from:
/// http://lolengine.net/blog/2011/3/20/understanding-fast-float-integer-conversions
/// http://stackoverflow.com/a/536278
/// </summary>
internal static void ByteToNormalizedFloat(ReadOnlySpan<byte> source, Span<float> dest)
{
VerifyHasVector8(nameof(ByteToNormalizedFloat));
VerifySpanInput(source, dest, 8);
var bVec = new Vector<float>(256.0f / 255.0f);
var magicFloat = new Vector<float>(32768.0f);
var magicInt = new Vector<uint>(1191182336); // reinterpreted value of 32768.0f
var mask = new Vector<uint>(255);
ref Octet<byte> sourceBase = ref Unsafe.As<byte, Octet<byte>>(ref MemoryMarshal.GetReference(source));
ref Octet<uint> destBaseAsWideOctet = ref Unsafe.As<float, Octet<uint>>(ref MemoryMarshal.GetReference(dest));
ref Vector<float> destBaseAsFloat = ref Unsafe.As<Octet<uint>, Vector<float>>(ref destBaseAsWideOctet);
int n = dest.Length / 8;
for (int i = 0; i < n; i++)
{
ref Octet<byte> s = ref Unsafe.Add(ref sourceBase, i);
ref Octet<uint> d = ref Unsafe.Add(ref destBaseAsWideOctet, i);
d.LoadFrom(ref s);
}
for (int i = 0; i < n; i++)
{
ref Vector<float> df = ref Unsafe.Add(ref destBaseAsFloat, i);
var vi = Vector.AsVectorUInt32(df);
vi &= mask;
vi |= magicInt;
var vf = Vector.AsVectorSingle(vi);
vf = (vf - magicFloat) * bVec;
df = vf;
}
}
/// <summary>
/// Implementation of <see cref="SimdUtils.NormalizedFloatToByteSaturate"/> which is faster on older runtimes.
/// </summary>
internal static void NormalizedFloatToByteSaturate(ReadOnlySpan<float> source, Span<byte> dest)
{
VerifyHasVector8(nameof(NormalizedFloatToByteSaturate));
VerifySpanInput(source, dest, 8);
if (source.Length == 0)
{
return;
}
ref Vector<float> srcBase = ref Unsafe.As<float, Vector<float>>(ref MemoryMarshal.GetReference(source));
ref Octet<byte> destBase = ref Unsafe.As<byte, Octet<byte>>(ref MemoryMarshal.GetReference(dest));
int n = source.Length / 8;
var magick = new Vector<float>(32768.0f);
var scale = new Vector<float>(255f) / new Vector<float>(256f);
// need to copy to a temporary struct, because
// SimdUtils.Octet<uint> temp = Unsafe.As<Vector<float>, SimdUtils.Octet<uint>>(ref x)
// does not work. TODO: This might be a CoreClr bug, need to ask/report
var temp = default(Octet<uint>);
ref Vector<float> tempRef = ref Unsafe.As<Octet<uint>, Vector<float>>(ref temp);
for (int i = 0; i < n; i++)
{
// union { float f; uint32_t i; } u;
// u.f = 32768.0f + x * (255.0f / 256.0f);
// return (uint8_t)u.i;
Vector<float> x = Unsafe.Add(ref srcBase, i);
x = Vector.Max(x, Vector<float>.Zero);
x = Vector.Min(x, Vector<float>.One);
x = (x * scale) + magick;
tempRef = x;
ref Octet<byte> d = ref Unsafe.Add(ref destBase, i);
d.LoadFrom(ref temp);
}
}
/// <summary>
/// Convert all <see cref="float"/> values normalized into [0..1] from 'source'
/// into 'dest' buffer of <see cref="byte"/>. The values are scaled up into [0-255] and rounded.
/// This implementation is SIMD optimized and works only when span Length is divisible by 8.
/// Based on:
/// <see>
/// <cref>http://lolengine.net/blog/2011/3/20/understanding-fast-float-integer-conversions</cref>
/// </see>
/// </summary>
internal static void BulkConvertNormalizedFloatToByte(ReadOnlySpan<float> source, Span<byte> dest)
{
VerifyHasVector8(nameof(BulkConvertNormalizedFloatToByte));
VerifySpanInput(source, dest, 8);
if (source.Length == 0)
{
return;
}
ref Vector<float> srcBase = ref Unsafe.As<float, Vector<float>>(ref MemoryMarshal.GetReference(source));
ref Octet<byte> destBase = ref Unsafe.As<byte, Octet<byte>>(ref MemoryMarshal.GetReference(dest));
int n = source.Length / 8;
var magick = new Vector<float>(32768.0f);
var scale = new Vector<float>(255f) / new Vector<float>(256f);
// need to copy to a temporary struct, because
// SimdUtils.Octet<uint> temp = Unsafe.As<Vector<float>, SimdUtils.Octet<uint>>(ref x)
// does not work. TODO: This might be a CoreClr bug, need to ask/report
var temp = default(Octet<uint>);
ref Vector<float> tempRef = ref Unsafe.As<Octet<uint>, Vector<float>>(ref temp);
for (int i = 0; i < n; i++)
{
// union { float f; uint32_t i; } u;
// u.f = 32768.0f + x * (255.0f / 256.0f);
// return (uint8_t)u.i;
Vector<float> x = Unsafe.Add(ref srcBase, i);
x = (x * scale) + magick;
tempRef = x;
ref Octet<byte> d = ref Unsafe.Add(ref destBase, i);
d.LoadFrom(ref temp);
}
}
}
}
}

35
src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs

@ -21,12 +21,7 @@ namespace SixLabors.ImageSharp
/// </summary> /// </summary>
public static class ExtendedIntrinsics public static class ExtendedIntrinsics
{ {
public static bool IsAvailable { get; } = public static bool IsAvailable { get; } = Vector.IsHardwareAccelerated;
#if SUPPORTS_EXTENDED_INTRINSICS
Vector.IsHardwareAccelerated;
#else
false;
#endif
/// <summary> /// <summary>
/// Widen and convert a vector of <see cref="short"/> values into 2 vectors of <see cref="float"/>-s. /// Widen and convert a vector of <see cref="short"/> values into 2 vectors of <see cref="float"/>-s.
@ -62,10 +57,10 @@ namespace SixLabors.ImageSharp
if (adjustedCount > 0) if (adjustedCount > 0)
{ {
ByteToNormalizedFloat(source.Slice(0, adjustedCount), dest.Slice(0, adjustedCount)); ByteToNormalizedFloat(source[..adjustedCount], dest[..adjustedCount]);
source = source.Slice(adjustedCount); source = source[adjustedCount..];
dest = dest.Slice(adjustedCount); dest = dest[adjustedCount..];
} }
} }
@ -89,12 +84,10 @@ namespace SixLabors.ImageSharp
if (adjustedCount > 0) if (adjustedCount > 0)
{ {
NormalizedFloatToByteSaturate( NormalizedFloatToByteSaturate(source[..adjustedCount], dest[..adjustedCount]);
source.Slice(0, adjustedCount),
dest.Slice(0, adjustedCount));
source = source.Slice(adjustedCount); source = source[adjustedCount..];
dest = dest.Slice(adjustedCount); dest = dest[adjustedCount..];
} }
} }
@ -160,12 +153,10 @@ namespace SixLabors.ImageSharp
Vector<uint> w2 = ConvertToUInt32(f2); Vector<uint> w2 = ConvertToUInt32(f2);
Vector<uint> w3 = ConvertToUInt32(f3); Vector<uint> w3 = ConvertToUInt32(f3);
Vector<ushort> u0 = Vector.Narrow(w0, w1); var u0 = Vector.Narrow(w0, w1);
Vector<ushort> u1 = Vector.Narrow(w2, w3); var u1 = Vector.Narrow(w2, w3);
Vector<byte> b = Vector.Narrow(u0, u1); Unsafe.Add(ref destBase, i) = Vector.Narrow(u0, u1);
Unsafe.Add(ref destBase, i) = b;
} }
} }
@ -176,15 +167,15 @@ namespace SixLabors.ImageSharp
vf *= maxBytes; vf *= maxBytes;
vf += new Vector<float>(0.5f); vf += new Vector<float>(0.5f);
vf = Vector.Min(Vector.Max(vf, Vector<float>.Zero), maxBytes); vf = Vector.Min(Vector.Max(vf, Vector<float>.Zero), maxBytes);
Vector<int> vi = Vector.ConvertToInt32(vf); var vi = Vector.ConvertToInt32(vf);
return Vector.AsVectorUInt32(vi); return Vector.AsVectorUInt32(vi);
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static Vector<float> ConvertToSingle(Vector<uint> u) private static Vector<float> ConvertToSingle(Vector<uint> u)
{ {
Vector<int> vi = Vector.AsVectorInt32(u); var vi = Vector.AsVectorInt32(u);
Vector<float> v = Vector.ConvertToSingle(vi); var v = Vector.ConvertToSingle(vi);
v *= new Vector<float>(1f / 255f); v *= new Vector<float>(1f / 255f);
return v; return v;
} }

20
src/ImageSharp/Common/Helpers/SimdUtils.FallbackIntrinsics128.cs

@ -33,12 +33,10 @@ namespace SixLabors.ImageSharp
if (adjustedCount > 0) if (adjustedCount > 0)
{ {
ByteToNormalizedFloat( ByteToNormalizedFloat(source[..adjustedCount], dest[..adjustedCount]);
source.Slice(0, adjustedCount),
dest.Slice(0, adjustedCount));
source = source.Slice(adjustedCount); source = source[adjustedCount..];
dest = dest.Slice(adjustedCount); dest = dest[adjustedCount..];
} }
} }
@ -58,11 +56,11 @@ namespace SixLabors.ImageSharp
if (adjustedCount > 0) if (adjustedCount > 0)
{ {
NormalizedFloatToByteSaturate( NormalizedFloatToByteSaturate(
source.Slice(0, adjustedCount), source[..adjustedCount],
dest.Slice(0, adjustedCount)); dest[..adjustedCount]);
source = source.Slice(adjustedCount); source = source[adjustedCount..];
dest = dest.Slice(adjustedCount); dest = dest[adjustedCount..];
} }
} }
@ -83,7 +81,7 @@ namespace SixLabors.ImageSharp
ref ByteVector4 sBase = ref Unsafe.As<byte, ByteVector4>(ref MemoryMarshal.GetReference(source)); ref ByteVector4 sBase = ref Unsafe.As<byte, ByteVector4>(ref MemoryMarshal.GetReference(source));
ref Vector4 dBase = ref Unsafe.As<float, Vector4>(ref MemoryMarshal.GetReference(dest)); ref Vector4 dBase = ref Unsafe.As<float, Vector4>(ref MemoryMarshal.GetReference(dest));
const float Scale = 1f / 255f; const float scale = 1f / 255f;
Vector4 d = default; Vector4 d = default;
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
@ -93,7 +91,7 @@ namespace SixLabors.ImageSharp
d.Y = s.Y; d.Y = s.Y;
d.Z = s.Z; d.Z = s.Z;
d.W = s.W; d.W = s.W;
d *= Scale; d *= scale;
Unsafe.Add(ref dBase, i) = d; Unsafe.Add(ref dBase, i) = d;
} }
} }

88
src/ImageSharp/Common/Helpers/SimdUtils.HwIntrinsics.cs

@ -1,7 +1,6 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Six Labors Split License. // Licensed under the Six Labors Split License.
#if SUPPORTS_RUNTIME_INTRINSICS
using System; using System;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
@ -67,12 +66,12 @@ namespace SixLabors.ImageSharp
if (adjustedCount > 0) if (adjustedCount > 0)
{ {
Shuffle4( Shuffle4(
source.Slice(0, adjustedCount), source[..adjustedCount],
dest.Slice(0, adjustedCount), dest[..adjustedCount],
control); control);
source = source.Slice(adjustedCount); source = source[adjustedCount..];
dest = dest.Slice(adjustedCount); dest = dest[adjustedCount..];
} }
} }
} }
@ -101,12 +100,12 @@ namespace SixLabors.ImageSharp
if (adjustedCount > 0) if (adjustedCount > 0)
{ {
Shuffle4( Shuffle4(
source.Slice(0, adjustedCount), source[..adjustedCount],
dest.Slice(0, adjustedCount), dest[..adjustedCount],
control); control);
source = source.Slice(adjustedCount); source = source[adjustedCount..];
dest = dest.Slice(adjustedCount); dest = dest[adjustedCount..];
} }
} }
} }
@ -133,12 +132,12 @@ namespace SixLabors.ImageSharp
if (adjustedCount > 0) if (adjustedCount > 0)
{ {
Shuffle3( Shuffle3(
source.Slice(0, adjustedCount), source[..adjustedCount],
dest.Slice(0, adjustedCount), dest[..adjustedCount],
control); control);
source = source.Slice(adjustedCount); source = source[adjustedCount..];
dest = dest.Slice(adjustedCount); dest = dest[adjustedCount..];
} }
} }
} }
@ -166,12 +165,12 @@ namespace SixLabors.ImageSharp
if (sourceCount > 0) if (sourceCount > 0)
{ {
Pad3Shuffle4( Pad3Shuffle4(
source.Slice(0, sourceCount), source[..sourceCount],
dest.Slice(0, destCount), dest[..destCount],
control); control);
source = source.Slice(sourceCount); source = source[sourceCount..];
dest = dest.Slice(destCount); dest = dest[destCount..];
} }
} }
} }
@ -199,12 +198,12 @@ namespace SixLabors.ImageSharp
if (sourceCount > 0) if (sourceCount > 0)
{ {
Shuffle4Slice3( Shuffle4Slice3(
source.Slice(0, sourceCount), source[..sourceCount],
dest.Slice(0, destCount), dest[..destCount],
control); control);
source = source.Slice(sourceCount); source = source[sourceCount..];
dest = dest.Slice(destCount); dest = dest[destCount..];
} }
} }
} }
@ -607,10 +606,10 @@ namespace SixLabors.ImageSharp
if (adjustedCount > 0) if (adjustedCount > 0)
{ {
ByteToNormalizedFloat(source.Slice(0, adjustedCount), dest.Slice(0, adjustedCount)); ByteToNormalizedFloat(source[..adjustedCount], dest[..adjustedCount]);
source = source.Slice(adjustedCount); source = source[adjustedCount..];
dest = dest.Slice(adjustedCount); dest = dest[adjustedCount..];
} }
} }
} }
@ -740,11 +739,11 @@ namespace SixLabors.ImageSharp
if (adjustedCount > 0) if (adjustedCount > 0)
{ {
NormalizedFloatToByteSaturate( NormalizedFloatToByteSaturate(
source.Slice(0, adjustedCount), source[..adjustedCount],
dest.Slice(0, adjustedCount)); dest[..adjustedCount]);
source = source.Slice(adjustedCount); source = source[adjustedCount..];
dest = dest.Slice(adjustedCount); dest = dest[adjustedCount..];
} }
} }
} }
@ -848,13 +847,12 @@ namespace SixLabors.ImageSharp
int count = redChannel.Length / Vector256<byte>.Count; int count = redChannel.Length / Vector256<byte>.Count;
ref byte control1Bytes = ref MemoryMarshal.GetReference(SimdUtils.HwIntrinsics.PermuteMaskEvenOdd8x32); ref byte control1Bytes = ref MemoryMarshal.GetReference(PermuteMaskEvenOdd8x32);
Vector256<uint> control1 = Unsafe.As<byte, Vector256<uint>>(ref control1Bytes); Vector256<uint> control1 = Unsafe.As<byte, Vector256<uint>>(ref control1Bytes);
ref byte control2Bytes = ref MemoryMarshal.GetReference(PermuteMaskShiftAlpha8x32); ref byte control2Bytes = ref MemoryMarshal.GetReference(PermuteMaskShiftAlpha8x32);
Vector256<uint> control2 = Unsafe.As<byte, Vector256<uint>>(ref control2Bytes); Vector256<uint> control2 = Unsafe.As<byte, Vector256<uint>>(ref control2Bytes);
var a = Vector256.Create((byte)255);
Vector256<byte> a = Vector256.Create((byte)255);
Vector256<byte> shuffleAlpha = Unsafe.As<byte, Vector256<byte>>(ref MemoryMarshal.GetReference(ShuffleMaskShiftAlpha)); Vector256<byte> shuffleAlpha = Unsafe.As<byte, Vector256<byte>>(ref MemoryMarshal.GetReference(ShuffleMaskShiftAlpha));
@ -902,10 +900,10 @@ namespace SixLabors.ImageSharp
} }
int slice = count * Vector256<byte>.Count; int slice = count * Vector256<byte>.Count;
redChannel = redChannel.Slice(slice); redChannel = redChannel[slice..];
greenChannel = greenChannel.Slice(slice); greenChannel = greenChannel[slice..];
blueChannel = blueChannel.Slice(slice); blueChannel = blueChannel[slice..];
destination = destination.Slice(slice); destination = destination[slice..];
} }
internal static void PackFromRgbPlanesAvx2Reduce( internal static void PackFromRgbPlanesAvx2Reduce(
@ -920,16 +918,9 @@ namespace SixLabors.ImageSharp
ref Vector256<byte> dBase = ref Unsafe.As<Rgba32, Vector256<byte>>(ref MemoryMarshal.GetReference(destination)); ref Vector256<byte> dBase = ref Unsafe.As<Rgba32, Vector256<byte>>(ref MemoryMarshal.GetReference(destination));
int count = redChannel.Length / Vector256<byte>.Count; int count = redChannel.Length / Vector256<byte>.Count;
ref byte control1Bytes = ref MemoryMarshal.GetReference(PermuteMaskEvenOdd8x32);
ref byte control1Bytes = ref MemoryMarshal.GetReference(SimdUtils.HwIntrinsics.PermuteMaskEvenOdd8x32);
Vector256<uint> control1 = Unsafe.As<byte, Vector256<uint>>(ref control1Bytes); Vector256<uint> control1 = Unsafe.As<byte, Vector256<uint>>(ref control1Bytes);
var a = Vector256.Create((byte)255);
ref byte control2Bytes = ref MemoryMarshal.GetReference(PermuteMaskShiftAlpha8x32);
Vector256<uint> control2 = Unsafe.As<byte, Vector256<uint>>(ref control2Bytes);
Vector256<byte> a = Vector256.Create((byte)255);
Vector256<byte> shuffleAlpha = Unsafe.As<byte, Vector256<byte>>(ref MemoryMarshal.GetReference(ShuffleMaskShiftAlpha));
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
{ {
@ -961,10 +952,10 @@ namespace SixLabors.ImageSharp
} }
int slice = count * Vector256<byte>.Count; int slice = count * Vector256<byte>.Count;
redChannel = redChannel.Slice(slice); redChannel = redChannel[slice..];
greenChannel = greenChannel.Slice(slice); greenChannel = greenChannel[slice..];
blueChannel = blueChannel.Slice(slice); blueChannel = blueChannel[slice..];
destination = destination.Slice(slice); destination = destination[slice..];
} }
internal static void UnpackToRgbPlanesAvx2Reduce( internal static void UnpackToRgbPlanesAvx2Reduce(
@ -1012,4 +1003,3 @@ namespace SixLabors.ImageSharp
} }
} }
} }
#endif

26
src/ImageSharp/Common/Helpers/SimdUtils.Pack.cs

@ -4,10 +4,8 @@
using System; using System;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using SixLabors.ImageSharp.PixelFormats;
#if SUPPORTS_RUNTIME_INTRINSICS
using System.Runtime.Intrinsics.X86; using System.Runtime.Intrinsics.X86;
#endif using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp namespace SixLabors.ImageSharp
{ {
@ -15,7 +13,6 @@ namespace SixLabors.ImageSharp
{ {
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
internal static void PackFromRgbPlanes( internal static void PackFromRgbPlanes(
Configuration configuration,
ReadOnlySpan<byte> redChannel, ReadOnlySpan<byte> redChannel,
ReadOnlySpan<byte> greenChannel, ReadOnlySpan<byte> greenChannel,
ReadOnlySpan<byte> blueChannel, ReadOnlySpan<byte> blueChannel,
@ -25,13 +22,11 @@ namespace SixLabors.ImageSharp
DebugGuard.IsTrue(blueChannel.Length == redChannel.Length, nameof(blueChannel), "Channels must be of same size!"); DebugGuard.IsTrue(blueChannel.Length == redChannel.Length, nameof(blueChannel), "Channels must be of same size!");
DebugGuard.IsTrue(destination.Length > redChannel.Length + 2, nameof(destination), "'destination' must contain a padding of 3 elements!"); DebugGuard.IsTrue(destination.Length > redChannel.Length + 2, nameof(destination), "'destination' must contain a padding of 3 elements!");
#if SUPPORTS_RUNTIME_INTRINSICS
if (Avx2.IsSupported) if (Avx2.IsSupported)
{ {
HwIntrinsics.PackFromRgbPlanesAvx2Reduce(ref redChannel, ref greenChannel, ref blueChannel, ref destination); HwIntrinsics.PackFromRgbPlanesAvx2Reduce(ref redChannel, ref greenChannel, ref blueChannel, ref destination);
} }
else else
#endif
{ {
PackFromRgbPlanesScalarBatchedReduce(ref redChannel, ref greenChannel, ref blueChannel, ref destination); PackFromRgbPlanesScalarBatchedReduce(ref redChannel, ref greenChannel, ref blueChannel, ref destination);
} }
@ -41,7 +36,6 @@ namespace SixLabors.ImageSharp
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
internal static void PackFromRgbPlanes( internal static void PackFromRgbPlanes(
Configuration configuration,
ReadOnlySpan<byte> redChannel, ReadOnlySpan<byte> redChannel,
ReadOnlySpan<byte> greenChannel, ReadOnlySpan<byte> greenChannel,
ReadOnlySpan<byte> blueChannel, ReadOnlySpan<byte> blueChannel,
@ -51,13 +45,11 @@ namespace SixLabors.ImageSharp
DebugGuard.IsTrue(blueChannel.Length == redChannel.Length, nameof(blueChannel), "Channels must be of same size!"); DebugGuard.IsTrue(blueChannel.Length == redChannel.Length, nameof(blueChannel), "Channels must be of same size!");
DebugGuard.IsTrue(destination.Length > redChannel.Length, nameof(destination), "'destination' span should not be shorter than the source channels!"); DebugGuard.IsTrue(destination.Length > redChannel.Length, nameof(destination), "'destination' span should not be shorter than the source channels!");
#if SUPPORTS_RUNTIME_INTRINSICS
if (Avx2.IsSupported) if (Avx2.IsSupported)
{ {
HwIntrinsics.PackFromRgbPlanesAvx2Reduce(ref redChannel, ref greenChannel, ref blueChannel, ref destination); HwIntrinsics.PackFromRgbPlanesAvx2Reduce(ref redChannel, ref greenChannel, ref blueChannel, ref destination);
} }
else else
#endif
{ {
PackFromRgbPlanesScalarBatchedReduce(ref redChannel, ref greenChannel, ref blueChannel, ref destination); PackFromRgbPlanesScalarBatchedReduce(ref redChannel, ref greenChannel, ref blueChannel, ref destination);
} }
@ -125,10 +117,10 @@ namespace SixLabors.ImageSharp
} }
int finished = count * 4; int finished = count * 4;
redChannel = redChannel.Slice(finished); redChannel = redChannel[finished..];
greenChannel = greenChannel.Slice(finished); greenChannel = greenChannel[finished..];
blueChannel = blueChannel.Slice(finished); blueChannel = blueChannel[finished..];
destination = destination.Slice(finished); destination = destination[finished..];
} }
private static void PackFromRgbPlanesScalarBatchedReduce( private static void PackFromRgbPlanesScalarBatchedReduce(
@ -173,10 +165,10 @@ namespace SixLabors.ImageSharp
} }
int finished = count * 4; int finished = count * 4;
redChannel = redChannel.Slice(finished); redChannel = redChannel[finished..];
greenChannel = greenChannel.Slice(finished); greenChannel = greenChannel[finished..];
blueChannel = blueChannel.Slice(finished); blueChannel = blueChannel[finished..];
destination = destination.Slice(finished); destination = destination[finished..];
} }
private static void PackFromRgbPlanesRemainder( private static void PackFromRgbPlanesRemainder(

18
src/ImageSharp/Common/Helpers/SimdUtils.Shuffle.cs

@ -25,9 +25,7 @@ namespace SixLabors.ImageSharp
{ {
VerifyShuffle4SpanInput(source, dest); VerifyShuffle4SpanInput(source, dest);
#if SUPPORTS_RUNTIME_INTRINSICS
HwIntrinsics.Shuffle4Reduce(ref source, ref dest, control); HwIntrinsics.Shuffle4Reduce(ref source, ref dest, control);
#endif
// Deal with the remainder: // Deal with the remainder:
if (source.Length > 0) if (source.Length > 0)
@ -52,9 +50,7 @@ namespace SixLabors.ImageSharp
{ {
VerifyShuffle4SpanInput(source, dest); VerifyShuffle4SpanInput(source, dest);
#if SUPPORTS_RUNTIME_INTRINSICS
HwIntrinsics.Shuffle4Reduce(ref source, ref dest, shuffle.Control); HwIntrinsics.Shuffle4Reduce(ref source, ref dest, shuffle.Control);
#endif
// Deal with the remainder: // Deal with the remainder:
if (source.Length > 0) if (source.Length > 0)
@ -80,9 +76,7 @@ namespace SixLabors.ImageSharp
// Source length should be smaller than dest length, and divisible by 3. // Source length should be smaller than dest length, and divisible by 3.
VerifyShuffle3SpanInput(source, dest); VerifyShuffle3SpanInput(source, dest);
#if SUPPORTS_RUNTIME_INTRINSICS
HwIntrinsics.Shuffle3Reduce(ref source, ref dest, shuffle.Control); HwIntrinsics.Shuffle3Reduce(ref source, ref dest, shuffle.Control);
#endif
// Deal with the remainder: // Deal with the remainder:
if (source.Length > 0) if (source.Length > 0)
@ -107,9 +101,7 @@ namespace SixLabors.ImageSharp
{ {
VerifyPad3Shuffle4SpanInput(source, dest); VerifyPad3Shuffle4SpanInput(source, dest);
#if SUPPORTS_RUNTIME_INTRINSICS
HwIntrinsics.Pad3Shuffle4Reduce(ref source, ref dest, shuffle.Control); HwIntrinsics.Pad3Shuffle4Reduce(ref source, ref dest, shuffle.Control);
#endif
// Deal with the remainder: // Deal with the remainder:
if (source.Length > 0) if (source.Length > 0)
@ -134,9 +126,7 @@ namespace SixLabors.ImageSharp
{ {
VerifyShuffle4Slice3SpanInput(source, dest); VerifyShuffle4Slice3SpanInput(source, dest);
#if SUPPORTS_RUNTIME_INTRINSICS
HwIntrinsics.Shuffle4Slice3Reduce(ref source, ref dest, shuffle.Control); HwIntrinsics.Shuffle4Slice3Reduce(ref source, ref dest, shuffle.Control);
#endif
// Deal with the remainder: // Deal with the remainder:
if (source.Length > 0) if (source.Length > 0)
@ -266,10 +256,10 @@ namespace SixLabors.ImageSharp
out int p1, out int p1,
out int p0) out int p0)
{ {
p3 = control >> 6 & 0x3; p3 = (control >> 6) & 0x3;
p2 = control >> 4 & 0x3; p2 = (control >> 4) & 0x3;
p1 = control >> 2 & 0x3; p1 = (control >> 2) & 0x3;
p0 = control >> 0 & 0x3; p0 = (control >> 0) & 0x3;
} }
} }
} }

19
src/ImageSharp/Common/Helpers/SimdUtils.cs

@ -6,11 +6,8 @@ using System.Diagnostics;
using System.Numerics; using System.Numerics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using SixLabors.ImageSharp.PixelFormats;
#if SUPPORTS_RUNTIME_INTRINSICS
using System.Runtime.Intrinsics; using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.X86; using System.Runtime.Intrinsics.X86;
#endif
namespace SixLabors.ImageSharp namespace SixLabors.ImageSharp
{ {
@ -56,8 +53,6 @@ namespace SixLabors.ImageSharp
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static Vector<float> FastRound(this Vector<float> v) internal static Vector<float> FastRound(this Vector<float> v)
{ {
#if SUPPORTS_RUNTIME_INTRINSICS
if (Avx2.IsSupported) if (Avx2.IsSupported)
{ {
ref Vector256<float> v256 = ref Unsafe.As<Vector<float>, Vector256<float>>(ref v); ref Vector256<float> v256 = ref Unsafe.As<Vector<float>, Vector256<float>>(ref v);
@ -65,7 +60,6 @@ namespace SixLabors.ImageSharp
return Unsafe.As<Vector256<float>, Vector<float>>(ref vRound); return Unsafe.As<Vector256<float>, Vector<float>>(ref vRound);
} }
else else
#endif
{ {
var magic0 = new Vector<int>(int.MinValue); // 0x80000000 var magic0 = new Vector<int>(int.MinValue); // 0x80000000
var sgn0 = Vector.AsVectorSingle(magic0); var sgn0 = Vector.AsVectorSingle(magic0);
@ -87,13 +81,8 @@ namespace SixLabors.ImageSharp
internal static void ByteToNormalizedFloat(ReadOnlySpan<byte> source, Span<float> dest) internal static void ByteToNormalizedFloat(ReadOnlySpan<byte> source, Span<float> dest)
{ {
DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!"); DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!");
#if SUPPORTS_RUNTIME_INTRINSICS
HwIntrinsics.ByteToNormalizedFloatReduce(ref source, ref dest); HwIntrinsics.ByteToNormalizedFloatReduce(ref source, ref dest);
#elif SUPPORTS_EXTENDED_INTRINSICS
ExtendedIntrinsics.ByteToNormalizedFloatReduce(ref source, ref dest);
#else
BasicIntrinsics256.ByteToNormalizedFloatReduce(ref source, ref dest);
#endif
// Also deals with the remainder from previous conversions: // Also deals with the remainder from previous conversions:
FallbackIntrinsics128.ByteToNormalizedFloatReduce(ref source, ref dest); FallbackIntrinsics128.ByteToNormalizedFloatReduce(ref source, ref dest);
@ -118,13 +107,7 @@ namespace SixLabors.ImageSharp
{ {
DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!"); DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!");
#if SUPPORTS_RUNTIME_INTRINSICS
HwIntrinsics.NormalizedFloatToByteSaturateReduce(ref source, ref dest); HwIntrinsics.NormalizedFloatToByteSaturateReduce(ref source, ref dest);
#elif SUPPORTS_EXTENDED_INTRINSICS
ExtendedIntrinsics.NormalizedFloatToByteSaturateReduce(ref source, ref dest);
#else
BasicIntrinsics256.NormalizedFloatToByteSaturateReduce(ref source, ref dest);
#endif
// Also deals with the remainder from previous conversions: // Also deals with the remainder from previous conversions:
FallbackIntrinsics128.NormalizedFloatToByteSaturateReduce(ref source, ref dest); FallbackIntrinsics128.NormalizedFloatToByteSaturateReduce(ref source, ref dest);

3
src/ImageSharp/Common/Helpers/UnitConverter.cs

@ -114,11 +114,10 @@ namespace SixLabors.ImageSharp.Common.Helpers
case PixelResolutionUnit.PixelsPerCentimeter: case PixelResolutionUnit.PixelsPerCentimeter:
break; break;
case PixelResolutionUnit.PixelsPerMeter: case PixelResolutionUnit.PixelsPerMeter:
{
unit = PixelResolutionUnit.PixelsPerCentimeter; unit = PixelResolutionUnit.PixelsPerCentimeter;
horizontal = MeterToCm(horizontal); horizontal = MeterToCm(horizontal);
vertical = MeterToCm(vertical); vertical = MeterToCm(vertical);
}
break; break;
default: default:

22
src/ImageSharp/Compression/Zlib/Adler32.cs

@ -4,10 +4,8 @@
using System; using System;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
#if SUPPORTS_RUNTIME_INTRINSICS
using System.Runtime.Intrinsics; using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.X86; using System.Runtime.Intrinsics.X86;
#endif
#pragma warning disable IDE0007 // Use implicit type #pragma warning disable IDE0007 // Use implicit type
namespace SixLabors.ImageSharp.Compression.Zlib namespace SixLabors.ImageSharp.Compression.Zlib
@ -29,7 +27,6 @@ namespace SixLabors.ImageSharp.Compression.Zlib
// NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 // NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1
private const uint NMAX = 5552; private const uint NMAX = 5552;
#if SUPPORTS_RUNTIME_INTRINSICS
private const int MinBufferSize = 64; private const int MinBufferSize = 64;
private const int BlockSize = 1 << 5; private const int BlockSize = 1 << 5;
@ -40,7 +37,6 @@ namespace SixLabors.ImageSharp.Compression.Zlib
32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, // tap1 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, // tap1
16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 // tap2 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 // tap2
}; };
#endif
/// <summary> /// <summary>
/// Calculates the Adler32 checksum with the bytes taken from the span. /// Calculates the Adler32 checksum with the bytes taken from the span.
@ -65,7 +61,6 @@ namespace SixLabors.ImageSharp.Compression.Zlib
return adler; return adler;
} }
#if SUPPORTS_RUNTIME_INTRINSICS
if (Avx2.IsSupported && buffer.Length >= MinBufferSize) if (Avx2.IsSupported && buffer.Length >= MinBufferSize)
{ {
return CalculateAvx2(adler, buffer); return CalculateAvx2(adler, buffer);
@ -77,13 +72,9 @@ namespace SixLabors.ImageSharp.Compression.Zlib
} }
return CalculateScalar(adler, buffer); return CalculateScalar(adler, buffer);
#else
return CalculateScalar(adler, buffer);
#endif
} }
// Based on https://github.com/chromium/chromium/blob/master/third_party/zlib/adler32_simd.c // Based on https://github.com/chromium/chromium/blob/master/third_party/zlib/adler32_simd.c
#if SUPPORTS_RUNTIME_INTRINSICS
[MethodImpl(InliningOptions.HotPath | InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.HotPath | InliningOptions.ShortMethod)]
private static unsafe uint CalculateSse(uint adler, ReadOnlySpan<byte> buffer) private static unsafe uint CalculateSse(uint adler, ReadOnlySpan<byte> buffer)
{ {
@ -149,15 +140,15 @@ namespace SixLabors.ImageSharp.Compression.Zlib
v_s2 = Sse2.Add(v_s2, Sse2.ShiftLeftLogical(v_ps, 5)); v_s2 = Sse2.Add(v_s2, Sse2.ShiftLeftLogical(v_ps, 5));
// Sum epi32 ints v_s1(s2) and accumulate in s1(s2). // Sum epi32 ints v_s1(s2) and accumulate in s1(s2).
const byte S2301 = 0b1011_0001; // A B C D -> B A D C const byte s2301 = 0b1011_0001; // A B C D -> B A D C
const byte S1032 = 0b0100_1110; // A B C D -> C D A B const byte s1032 = 0b0100_1110; // A B C D -> C D A B
v_s1 = Sse2.Add(v_s1, Sse2.Shuffle(v_s1, S1032)); v_s1 = Sse2.Add(v_s1, Sse2.Shuffle(v_s1, s1032));
s1 += v_s1.ToScalar(); s1 += v_s1.ToScalar();
v_s2 = Sse2.Add(v_s2, Sse2.Shuffle(v_s2, S2301)); v_s2 = Sse2.Add(v_s2, Sse2.Shuffle(v_s2, s2301));
v_s2 = Sse2.Add(v_s2, Sse2.Shuffle(v_s2, S1032)); v_s2 = Sse2.Add(v_s2, Sse2.Shuffle(v_s2, s1032));
s2 = v_s2.ToScalar(); s2 = v_s2.ToScalar();
@ -290,7 +281,6 @@ namespace SixLabors.ImageSharp.Compression.Zlib
s2 %= BASE; s2 %= BASE;
} }
#endif
[MethodImpl(InliningOptions.HotPath | InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.HotPath | InliningOptions.ShortMethod)]
private static unsafe uint CalculateScalar(uint adler, ReadOnlySpan<byte> buffer) private static unsafe uint CalculateScalar(uint adler, ReadOnlySpan<byte> buffer)
@ -301,7 +291,7 @@ namespace SixLabors.ImageSharp.Compression.Zlib
fixed (byte* bufferPtr = buffer) fixed (byte* bufferPtr = buffer)
{ {
var localBufferPtr = bufferPtr; byte* localBufferPtr = bufferPtr;
uint length = (uint)buffer.Length; uint length = (uint)buffer.Length;
while (length > 0) while (length > 0)

16
src/ImageSharp/Compression/Zlib/Crc32.cs

@ -4,10 +4,8 @@
using System; using System;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
#if SUPPORTS_RUNTIME_INTRINSICS
using System.Runtime.Intrinsics; using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.X86; using System.Runtime.Intrinsics.X86;
#endif
namespace SixLabors.ImageSharp.Compression.Zlib namespace SixLabors.ImageSharp.Compression.Zlib
{ {
@ -22,7 +20,6 @@ namespace SixLabors.ImageSharp.Compression.Zlib
/// </summary> /// </summary>
public const uint SeedValue = 0U; public const uint SeedValue = 0U;
#if SUPPORTS_RUNTIME_INTRINSICS
private const int MinBufferSize = 64; private const int MinBufferSize = 64;
private const int ChunksizeMask = 15; private const int ChunksizeMask = 15;
@ -35,7 +32,6 @@ namespace SixLabors.ImageSharp.Compression.Zlib
0x0163cd6124, 0x0000000000, // k5, k0 0x0163cd6124, 0x0000000000, // k5, k0
0x01db710641, 0x01f7011641 // polynomial 0x01db710641, 0x01f7011641 // polynomial
}; };
#endif
/// <summary> /// <summary>
/// Calculates the CRC checksum with the bytes taken from the span. /// Calculates the CRC checksum with the bytes taken from the span.
@ -60,21 +56,14 @@ namespace SixLabors.ImageSharp.Compression.Zlib
return crc; return crc;
} }
#if SUPPORTS_RUNTIME_INTRINSICS
if (Sse41.IsSupported && Pclmulqdq.IsSupported && buffer.Length >= MinBufferSize) if (Sse41.IsSupported && Pclmulqdq.IsSupported && buffer.Length >= MinBufferSize)
{ {
return ~CalculateSse(~crc, buffer); return ~CalculateSse(~crc, buffer);
} }
else
{
return ~CalculateScalar(~crc, buffer);
}
#else
return ~CalculateScalar(~crc, buffer); return ~CalculateScalar(~crc, buffer);
#endif
} }
#if SUPPORTS_RUNTIME_INTRINSICS
// Based on https://github.com/chromium/chromium/blob/master/third_party/zlib/crc32_simd.c // Based on https://github.com/chromium/chromium/blob/master/third_party/zlib/crc32_simd.c
[MethodImpl(InliningOptions.HotPath | InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.HotPath | InliningOptions.ShortMethod)]
private static unsafe uint CalculateSse(uint crc, ReadOnlySpan<byte> buffer) private static unsafe uint CalculateSse(uint crc, ReadOnlySpan<byte> buffer)
@ -194,11 +183,10 @@ namespace SixLabors.ImageSharp.Compression.Zlib
x1 = Sse2.Xor(x1, x2); x1 = Sse2.Xor(x1, x2);
crc = (uint)Sse41.Extract(x1.AsInt32(), 1); crc = (uint)Sse41.Extract(x1.AsInt32(), 1);
return buffer.Length - chunksize == 0 ? crc : CalculateScalar(crc, buffer.Slice(chunksize)); return buffer.Length - chunksize == 0 ? crc : CalculateScalar(crc, buffer[chunksize..]);
} }
} }
} }
#endif
[MethodImpl(InliningOptions.HotPath | InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.HotPath | InliningOptions.ShortMethod)]
private static uint CalculateScalar(uint crc, ReadOnlySpan<byte> buffer) private static uint CalculateScalar(uint crc, ReadOnlySpan<byte> buffer)

6
src/ImageSharp/Compression/Zlib/DeflaterEngine.cs

@ -276,8 +276,8 @@ namespace SixLabors.ImageSharp.Compression.Zlib
this.lookahead = 0; this.lookahead = 0;
this.prevAvailable = false; this.prevAvailable = false;
this.matchLen = DeflaterConstants.MIN_MATCH - 1; this.matchLen = DeflaterConstants.MIN_MATCH - 1;
this.head.Span.Slice(0, DeflaterConstants.HASH_SIZE).Clear(); this.head.Span[..DeflaterConstants.HASH_SIZE].Clear();
this.prev.Span.Slice(0, DeflaterConstants.WSIZE).Clear(); this.prev.Span[..DeflaterConstants.WSIZE].Clear();
} }
/// <summary> /// <summary>
@ -286,7 +286,7 @@ namespace SixLabors.ImageSharp.Compression.Zlib
/// <param name="level">The value to set the level to.</param> /// <param name="level">The value to set the level to.</param>
public void SetLevel(int level) public void SetLevel(int level)
{ {
if ((level < 0) || (level > 9)) if (level is < 0 or > 9)
{ {
DeflateThrowHelper.ThrowOutOfRange(nameof(level)); DeflateThrowHelper.ThrowOutOfRange(nameof(level));
} }

4
src/ImageSharp/Compression/Zlib/DeflaterOutputStream.cs

@ -95,7 +95,7 @@ namespace SixLabors.ImageSharp.Compression.Zlib
break; break;
} }
this.rawStream.Write(this.buffer.Span.Slice(0, deflateCount)); this.rawStream.Write(this.buffer.Span[..deflateCount]);
} }
if (!this.deflater.IsNeedingInput) if (!this.deflater.IsNeedingInput)
@ -115,7 +115,7 @@ namespace SixLabors.ImageSharp.Compression.Zlib
break; break;
} }
this.rawStream.Write(this.buffer.Span.Slice(0, len)); this.rawStream.Write(this.buffer.Span[..len]);
} }
if (!this.deflater.IsFinished) if (!this.deflater.IsFinished)

2
src/ImageSharp/Compression/Zlib/DeflaterPendingBuffer.cs

@ -75,7 +75,7 @@ namespace SixLabors.ImageSharp.Compression.Zlib
{ {
Unsafe.CopyBlockUnaligned( Unsafe.CopyBlockUnaligned(
ref this.buffer.Span[this.end], ref this.buffer.Span[this.end],
ref MemoryMarshal.GetReference(block.Slice(offset)), ref MemoryMarshal.GetReference(block[offset..]),
unchecked((uint)length)); unchecked((uint)length));
this.end += length; this.end += length;

2
src/ImageSharp/Configuration.cs

@ -70,7 +70,7 @@ namespace SixLabors.ImageSharp
get => this.maxDegreeOfParallelism; get => this.maxDegreeOfParallelism;
set set
{ {
if (value == 0 || value < -1) if (value is 0 or < -1)
{ {
throw new ArgumentOutOfRangeException(nameof(this.MaxDegreeOfParallelism)); throw new ArgumentOutOfRangeException(nameof(this.MaxDegreeOfParallelism));
} }

7
src/ImageSharp/Diagnostics/MemoryDiagnostics.cs

@ -9,6 +9,7 @@ namespace SixLabors.ImageSharp.Diagnostics
/// <summary> /// <summary>
/// Represents the method to handle <see cref="MemoryDiagnostics.UndisposedAllocation"/>. /// Represents the method to handle <see cref="MemoryDiagnostics.UndisposedAllocation"/>.
/// </summary> /// </summary>
/// <param name="allocationStackTrace">The allocation stack trace.</param>
public delegate void UndisposedAllocationDelegate(string allocationStackTrace); public delegate void UndisposedAllocationDelegate(string allocationStackTrace);
/// <summary> /// <summary>
@ -85,16 +86,10 @@ namespace SixLabors.ImageSharp.Diagnostics
} }
// Schedule on the ThreadPool, to avoid user callback messing up the finalizer thread. // Schedule on the ThreadPool, to avoid user callback messing up the finalizer thread.
#if NETSTANDARD2_1 || NETCOREAPP2_1_OR_GREATER
ThreadPool.QueueUserWorkItem( ThreadPool.QueueUserWorkItem(
stackTrace => undisposedAllocation?.Invoke(stackTrace), stackTrace => undisposedAllocation?.Invoke(stackTrace),
allocationStackTrace, allocationStackTrace,
preferLocal: false); preferLocal: false);
#else
ThreadPool.QueueUserWorkItem(
stackTrace => undisposedAllocation?.Invoke((string)stackTrace),
allocationStackTrace);
#endif
} }
} }
} }

37
src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs

@ -491,7 +491,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
int max = cmd[1]; int max = cmd[1];
int bytesToRead = (max + 1) / 2; int bytesToRead = (max + 1) / 2;
var run = new byte[bytesToRead]; byte[] run = new byte[bytesToRead];
this.stream.Read(run, 0, run.Length); this.stream.Read(run, 0, run.Length);
@ -501,13 +501,11 @@ namespace SixLabors.ImageSharp.Formats.Bmp
byte twoPixels = run[idx]; byte twoPixels = run[idx];
if (i % 2 == 0) if (i % 2 == 0)
{ {
byte leftPixel = (byte)((twoPixels >> 4) & 0xF); buffer[count++] = (byte)((twoPixels >> 4) & 0xF);
buffer[count++] = leftPixel;
} }
else else
{ {
byte rightPixel = (byte)(twoPixels & 0xF); buffer[count++] = (byte)(twoPixels & 0xF);
buffer[count++] = rightPixel;
idx++; idx++;
} }
} }
@ -597,11 +595,11 @@ namespace SixLabors.ImageSharp.Formats.Bmp
// Take this number of bytes from the stream as uncompressed data. // Take this number of bytes from the stream as uncompressed data.
int length = cmd[1]; int length = cmd[1];
var run = new byte[length]; byte[] run = new byte[length];
this.stream.Read(run, 0, run.Length); this.stream.Read(run, 0, run.Length);
run.AsSpan().CopyTo(buffer.Slice(count)); run.AsSpan().CopyTo(buffer[count..]);
count += run.Length; count += run.Length;
@ -676,11 +674,11 @@ namespace SixLabors.ImageSharp.Formats.Bmp
// Take this number of bytes from the stream as uncompressed data. // Take this number of bytes from the stream as uncompressed data.
int length = cmd[1]; int length = cmd[1];
var run = new byte[length * 3]; byte[] run = new byte[length * 3];
this.stream.Read(run, 0, run.Length); this.stream.Read(run, 0, run.Length);
run.AsSpan().CopyTo(buffer.Slice(start: uncompressedPixels * 3)); run.AsSpan().CopyTo(buffer[(uncompressedPixels * 3)..]);
uncompressedPixels += length; uncompressedPixels += length;
@ -903,13 +901,13 @@ namespace SixLabors.ImageSharp.Formats.Bmp
int offset = 0; int offset = 0;
for (int x = 0; x < width; x++) for (int x = 0; x < width; x++)
{ {
short temp = BinaryPrimitives.ReadInt16LittleEndian(bufferSpan.Slice(offset)); short temp = BinaryPrimitives.ReadInt16LittleEndian(bufferSpan[offset..]);
// Rescale values, so the values range from 0 to 255. // Rescale values, so the values range from 0 to 255.
int r = (redMaskBits == 5) ? GetBytesFrom5BitValue((temp & redMask) >> rightShiftRedMask) : GetBytesFrom6BitValue((temp & redMask) >> rightShiftRedMask); int r = (redMaskBits == 5) ? GetBytesFrom5BitValue((temp & redMask) >> rightShiftRedMask) : GetBytesFrom6BitValue((temp & redMask) >> rightShiftRedMask);
int g = (greenMaskBits == 5) ? GetBytesFrom5BitValue((temp & greenMask) >> rightShiftGreenMask) : GetBytesFrom6BitValue((temp & greenMask) >> rightShiftGreenMask); int g = (greenMaskBits == 5) ? GetBytesFrom5BitValue((temp & greenMask) >> rightShiftGreenMask) : GetBytesFrom6BitValue((temp & greenMask) >> rightShiftGreenMask);
int b = (blueMaskBits == 5) ? GetBytesFrom5BitValue((temp & blueMask) >> rightShiftBlueMask) : GetBytesFrom6BitValue((temp & blueMask) >> rightShiftBlueMask); int b = (blueMaskBits == 5) ? GetBytesFrom5BitValue((temp & blueMask) >> rightShiftBlueMask) : GetBytesFrom6BitValue((temp & blueMask) >> rightShiftBlueMask);
var rgb = new Rgb24((byte)r, (byte)g, (byte)b); Rgb24 rgb = new((byte)r, (byte)g, (byte)b);
color.FromRgb24(rgb); color.FromRgb24(rgb);
pixelRow[x] = color; pixelRow[x] = color;
@ -1156,7 +1154,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
int offset = 0; int offset = 0;
for (int x = 0; x < width; x++) for (int x = 0; x < width; x++)
{ {
uint temp = BinaryPrimitives.ReadUInt32LittleEndian(bufferSpan.Slice(offset)); uint temp = BinaryPrimitives.ReadUInt32LittleEndian(bufferSpan[offset..]);
if (unusualBitMask) if (unusualBitMask)
{ {
@ -1164,7 +1162,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
uint g = (uint)(temp & greenMask) >> rightShiftGreenMask; uint g = (uint)(temp & greenMask) >> rightShiftGreenMask;
uint b = (uint)(temp & blueMask) >> rightShiftBlueMask; uint b = (uint)(temp & blueMask) >> rightShiftBlueMask;
float alpha = alphaMask != 0 ? invMaxValueAlpha * ((uint)(temp & alphaMask) >> rightShiftAlphaMask) : 1.0f; float alpha = alphaMask != 0 ? invMaxValueAlpha * ((uint)(temp & alphaMask) >> rightShiftAlphaMask) : 1.0f;
var vector4 = new Vector4( Vector4 vector4 = new(
r * invMaxValueRed, r * invMaxValueRed,
g * invMaxValueGreen, g * invMaxValueGreen,
b * invMaxValueBlue, b * invMaxValueBlue,
@ -1246,7 +1244,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
this.stream.Read(buffer, 0, BmpInfoHeader.HeaderSizeSize); this.stream.Read(buffer, 0, BmpInfoHeader.HeaderSizeSize);
int headerSize = BinaryPrimitives.ReadInt32LittleEndian(buffer); int headerSize = BinaryPrimitives.ReadInt32LittleEndian(buffer);
if (headerSize < BmpInfoHeader.CoreSize || headerSize > BmpInfoHeader.MaxHeaderSize) if (headerSize is < BmpInfoHeader.CoreSize or > BmpInfoHeader.MaxHeaderSize)
{ {
BmpThrowHelper.ThrowNotSupportedException($"ImageSharp does not support this BMP file. HeaderSize is '{headerSize}'."); BmpThrowHelper.ThrowNotSupportedException($"ImageSharp does not support this BMP file. HeaderSize is '{headerSize}'.");
} }
@ -1277,19 +1275,19 @@ namespace SixLabors.ImageSharp.Formats.Bmp
// color masks for each color channel follow the info header. // color masks for each color channel follow the info header.
if (this.infoHeader.Compression == BmpCompression.BitFields) if (this.infoHeader.Compression == BmpCompression.BitFields)
{ {
var bitfieldsBuffer = new byte[12]; byte[] bitfieldsBuffer = new byte[12];
this.stream.Read(bitfieldsBuffer, 0, 12); this.stream.Read(bitfieldsBuffer, 0, 12);
Span<byte> data = bitfieldsBuffer.AsSpan(); Span<byte> data = bitfieldsBuffer.AsSpan();
this.infoHeader.RedMask = BinaryPrimitives.ReadInt32LittleEndian(data.Slice(0, 4)); this.infoHeader.RedMask = BinaryPrimitives.ReadInt32LittleEndian(data[..4]);
this.infoHeader.GreenMask = BinaryPrimitives.ReadInt32LittleEndian(data.Slice(4, 4)); this.infoHeader.GreenMask = BinaryPrimitives.ReadInt32LittleEndian(data.Slice(4, 4));
this.infoHeader.BlueMask = BinaryPrimitives.ReadInt32LittleEndian(data.Slice(8, 4)); this.infoHeader.BlueMask = BinaryPrimitives.ReadInt32LittleEndian(data.Slice(8, 4));
} }
else if (this.infoHeader.Compression == BmpCompression.BI_ALPHABITFIELDS) else if (this.infoHeader.Compression == BmpCompression.BI_ALPHABITFIELDS)
{ {
var bitfieldsBuffer = new byte[16]; byte[] bitfieldsBuffer = new byte[16];
this.stream.Read(bitfieldsBuffer, 0, 16); this.stream.Read(bitfieldsBuffer, 0, 16);
Span<byte> data = bitfieldsBuffer.AsSpan(); Span<byte> data = bitfieldsBuffer.AsSpan();
this.infoHeader.RedMask = BinaryPrimitives.ReadInt32LittleEndian(data.Slice(0, 4)); this.infoHeader.RedMask = BinaryPrimitives.ReadInt32LittleEndian(data[..4]);
this.infoHeader.GreenMask = BinaryPrimitives.ReadInt32LittleEndian(data.Slice(4, 4)); this.infoHeader.GreenMask = BinaryPrimitives.ReadInt32LittleEndian(data.Slice(4, 4));
this.infoHeader.BlueMask = BinaryPrimitives.ReadInt32LittleEndian(data.Slice(8, 4)); this.infoHeader.BlueMask = BinaryPrimitives.ReadInt32LittleEndian(data.Slice(8, 4));
this.infoHeader.AlphaMask = BinaryPrimitives.ReadInt32LittleEndian(data.Slice(12, 4)); this.infoHeader.AlphaMask = BinaryPrimitives.ReadInt32LittleEndian(data.Slice(12, 4));
@ -1396,6 +1394,9 @@ namespace SixLabors.ImageSharp.Formats.Bmp
/// <summary> /// <summary>
/// Reads the <see cref="BmpFileHeader"/> and <see cref="BmpInfoHeader"/> from the stream and sets the corresponding fields. /// Reads the <see cref="BmpFileHeader"/> and <see cref="BmpInfoHeader"/> from the stream and sets the corresponding fields.
/// </summary> /// </summary>
/// <param name="stream">The input stream.</param>
/// <param name="inverted">Whether the image orientation is inverted.</param>
/// <param name="palette">The color palette.</param>
/// <returns>Bytes per color palette entry. Usually 4 bytes, but in case of Windows 2.x bitmaps or OS/2 1.x bitmaps /// <returns>Bytes per color palette entry. Usually 4 bytes, but in case of Windows 2.x bitmaps or OS/2 1.x bitmaps
/// the bytes per color palette entry's can be 3 bytes instead of 4.</returns> /// the bytes per color palette entry's can be 3 bytes instead of 4.</returns>
private int ReadImageHeaders(BufferedReadStream stream, out bool inverted, out byte[] palette) private int ReadImageHeaders(BufferedReadStream stream, out bool inverted, out byte[] palette)

51
src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs

@ -160,10 +160,10 @@ namespace SixLabors.ImageSharp.Formats.Bmp
Span<byte> buffer = stackalloc byte[infoHeaderSize]; Span<byte> buffer = stackalloc byte[infoHeaderSize];
this.WriteBitmapFileHeader(stream, infoHeaderSize, colorPaletteSize, iccProfileSize, infoHeader, buffer); WriteBitmapFileHeader(stream, infoHeaderSize, colorPaletteSize, iccProfileSize, infoHeader, buffer);
this.WriteBitmapInfoHeader(stream, infoHeader, buffer, infoHeaderSize); this.WriteBitmapInfoHeader(stream, infoHeader, buffer, infoHeaderSize);
this.WriteImage(stream, image.Frames.RootFrame); this.WriteImage(stream, image.Frames.RootFrame);
this.WriteColorProfile(stream, iccProfileData, buffer); WriteColorProfile(stream, iccProfileData, buffer);
stream.Flush(); stream.Flush();
} }
@ -184,34 +184,33 @@ namespace SixLabors.ImageSharp.Formats.Bmp
int hResolution = 0; int hResolution = 0;
int vResolution = 0; int vResolution = 0;
if (metadata.ResolutionUnits != PixelResolutionUnit.AspectRatio) if (metadata.ResolutionUnits != PixelResolutionUnit.AspectRatio
&& metadata.HorizontalResolution > 0
&& metadata.VerticalResolution > 0)
{ {
if (metadata.HorizontalResolution > 0 && metadata.VerticalResolution > 0) switch (metadata.ResolutionUnits)
{ {
switch (metadata.ResolutionUnits) case PixelResolutionUnit.PixelsPerInch:
{
case PixelResolutionUnit.PixelsPerInch:
hResolution = (int)Math.Round(UnitConverter.InchToMeter(metadata.HorizontalResolution)); hResolution = (int)Math.Round(UnitConverter.InchToMeter(metadata.HorizontalResolution));
vResolution = (int)Math.Round(UnitConverter.InchToMeter(metadata.VerticalResolution)); vResolution = (int)Math.Round(UnitConverter.InchToMeter(metadata.VerticalResolution));
break; break;
case PixelResolutionUnit.PixelsPerCentimeter: case PixelResolutionUnit.PixelsPerCentimeter:
hResolution = (int)Math.Round(UnitConverter.CmToMeter(metadata.HorizontalResolution)); hResolution = (int)Math.Round(UnitConverter.CmToMeter(metadata.HorizontalResolution));
vResolution = (int)Math.Round(UnitConverter.CmToMeter(metadata.VerticalResolution)); vResolution = (int)Math.Round(UnitConverter.CmToMeter(metadata.VerticalResolution));
break; break;
case PixelResolutionUnit.PixelsPerMeter: case PixelResolutionUnit.PixelsPerMeter:
hResolution = (int)Math.Round(metadata.HorizontalResolution); hResolution = (int)Math.Round(metadata.HorizontalResolution);
vResolution = (int)Math.Round(metadata.VerticalResolution); vResolution = (int)Math.Round(metadata.VerticalResolution);
break; break;
}
} }
} }
var infoHeader = new BmpInfoHeader( BmpInfoHeader infoHeader = new(
headerSize: infoHeaderSize, headerSize: infoHeaderSize,
height: height, height: height,
width: width, width: width,
@ -248,7 +247,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
/// <param name="stream">The stream to write to.</param> /// <param name="stream">The stream to write to.</param>
/// <param name="iccProfileData">The color profile data.</param> /// <param name="iccProfileData">The color profile data.</param>
/// <param name="buffer">The buffer.</param> /// <param name="buffer">The buffer.</param>
private void WriteColorProfile(Stream stream, byte[] iccProfileData, Span<byte> buffer) private static void WriteColorProfile(Stream stream, byte[] iccProfileData, Span<byte> buffer)
{ {
if (iccProfileData != null) if (iccProfileData != null)
{ {
@ -257,7 +256,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
stream.Write(iccProfileData); stream.Write(iccProfileData);
BinaryPrimitives.WriteInt32LittleEndian(buffer, streamPositionAfterImageData); BinaryPrimitives.WriteInt32LittleEndian(buffer, streamPositionAfterImageData);
stream.Position = BmpFileHeader.Size + 112; stream.Position = BmpFileHeader.Size + 112;
stream.Write(buffer.Slice(0, 4)); stream.Write(buffer[..4]);
} }
} }
@ -270,9 +269,9 @@ namespace SixLabors.ImageSharp.Formats.Bmp
/// <param name="iccProfileSize">The size in bytes of the color profile.</param> /// <param name="iccProfileSize">The size in bytes of the color profile.</param>
/// <param name="infoHeader">The information header to write.</param> /// <param name="infoHeader">The information header to write.</param>
/// <param name="buffer">The buffer to write to.</param> /// <param name="buffer">The buffer to write to.</param>
private void WriteBitmapFileHeader(Stream stream, int infoHeaderSize, int colorPaletteSize, int iccProfileSize, BmpInfoHeader infoHeader, Span<byte> buffer) private static void WriteBitmapFileHeader(Stream stream, int infoHeaderSize, int colorPaletteSize, int iccProfileSize, BmpInfoHeader infoHeader, Span<byte> buffer)
{ {
var fileHeader = new BmpFileHeader( BmpFileHeader fileHeader = new(
type: BmpConstants.TypeMarkers.Bitmap, type: BmpConstants.TypeMarkers.Bitmap,
fileSize: BmpFileHeader.Size + infoHeaderSize + colorPaletteSize + iccProfileSize + infoHeader.ImageSize, fileSize: BmpFileHeader.Size + infoHeaderSize + colorPaletteSize + iccProfileSize + infoHeader.ImageSize,
reserved: 0, reserved: 0,
@ -555,7 +554,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
if (pixelRowSpan.Length % 2 != 0) if (pixelRowSpan.Length % 2 != 0)
{ {
stream.WriteByte((byte)((pixelRowSpan[pixelRowSpan.Length - 1] << 4) | 0)); stream.WriteByte((byte)((pixelRowSpan[^1] << 4) | 0));
} }
for (int i = 0; i < rowPadding; i++) for (int i = 0; i < rowPadding; i++)
@ -675,7 +674,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
int quantizedColorBytes = quantizedColorPalette.Length * 4; int quantizedColorBytes = quantizedColorPalette.Length * 4;
PixelOperations<TPixel>.Instance.ToBgra32(this.configuration, quantizedColorPalette, MemoryMarshal.Cast<byte, Bgra32>(colorPalette.Slice(0, quantizedColorBytes))); PixelOperations<TPixel>.Instance.ToBgra32(this.configuration, quantizedColorPalette, MemoryMarshal.Cast<byte, Bgra32>(colorPalette[..quantizedColorBytes]));
Span<uint> colorPaletteAsUInt = MemoryMarshal.Cast<byte, uint>(colorPalette); Span<uint> colorPaletteAsUInt = MemoryMarshal.Cast<byte, uint>(colorPalette);
for (int i = 0; i < colorPaletteAsUInt.Length; i++) for (int i = 0; i < colorPaletteAsUInt.Length; i++)
{ {

25
src/ImageSharp/Formats/Bmp/BmpInfoHeader.cs

@ -308,7 +308,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
/// <returns>The parsed header.</returns> /// <returns>The parsed header.</returns>
/// <seealso href="https://msdn.microsoft.com/en-us/library/windows/desktop/dd183372.aspx"/> /// <seealso href="https://msdn.microsoft.com/en-us/library/windows/desktop/dd183372.aspx"/>
public static BmpInfoHeader ParseCore(ReadOnlySpan<byte> data) => new( public static BmpInfoHeader ParseCore(ReadOnlySpan<byte> data) => new(
headerSize: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(0, 4)), headerSize: BinaryPrimitives.ReadInt32LittleEndian(data[..4]),
width: BinaryPrimitives.ReadUInt16LittleEndian(data.Slice(4, 2)), width: BinaryPrimitives.ReadUInt16LittleEndian(data.Slice(4, 2)),
height: BinaryPrimitives.ReadUInt16LittleEndian(data.Slice(6, 2)), height: BinaryPrimitives.ReadUInt16LittleEndian(data.Slice(6, 2)),
planes: BinaryPrimitives.ReadInt16LittleEndian(data.Slice(8, 2)), planes: BinaryPrimitives.ReadInt16LittleEndian(data.Slice(8, 2)),
@ -322,7 +322,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
/// <returns>The parsed header.</returns> /// <returns>The parsed header.</returns>
/// <seealso href="https://www.fileformat.info/format/os2bmp/egff.htm"/> /// <seealso href="https://www.fileformat.info/format/os2bmp/egff.htm"/>
public static BmpInfoHeader ParseOs22Short(ReadOnlySpan<byte> data) => new( public static BmpInfoHeader ParseOs22Short(ReadOnlySpan<byte> data) => new(
headerSize: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(0, 4)), headerSize: BinaryPrimitives.ReadInt32LittleEndian(data[..4]),
width: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(4, 4)), width: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(4, 4)),
height: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(8, 4)), height: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(8, 4)),
planes: BinaryPrimitives.ReadInt16LittleEndian(data.Slice(12, 2)), planes: BinaryPrimitives.ReadInt16LittleEndian(data.Slice(12, 2)),
@ -335,7 +335,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
/// <returns>The parsed header.</returns> /// <returns>The parsed header.</returns>
/// <seealso href="http://www.fileformat.info/format/bmp/egff.htm"/> /// <seealso href="http://www.fileformat.info/format/bmp/egff.htm"/>
public static BmpInfoHeader ParseV3(ReadOnlySpan<byte> data) => new( public static BmpInfoHeader ParseV3(ReadOnlySpan<byte> data) => new(
headerSize: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(0, 4)), headerSize: BinaryPrimitives.ReadInt32LittleEndian(data[..4]),
width: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(4, 4)), width: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(4, 4)),
height: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(8, 4)), height: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(8, 4)),
planes: BinaryPrimitives.ReadInt16LittleEndian(data.Slice(12, 2)), planes: BinaryPrimitives.ReadInt16LittleEndian(data.Slice(12, 2)),
@ -356,7 +356,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
/// <returns>The parsed header.</returns> /// <returns>The parsed header.</returns>
/// <seealso href="https://forums.adobe.com/message/3272950#3272950"/> /// <seealso href="https://forums.adobe.com/message/3272950#3272950"/>
public static BmpInfoHeader ParseAdobeV3(ReadOnlySpan<byte> data, bool withAlpha = true) => new( public static BmpInfoHeader ParseAdobeV3(ReadOnlySpan<byte> data, bool withAlpha = true) => new(
headerSize: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(0, 4)), headerSize: BinaryPrimitives.ReadInt32LittleEndian(data[..4]),
width: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(4, 4)), width: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(4, 4)),
height: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(8, 4)), height: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(8, 4)),
planes: BinaryPrimitives.ReadInt16LittleEndian(data.Slice(12, 2)), planes: BinaryPrimitives.ReadInt16LittleEndian(data.Slice(12, 2)),
@ -382,18 +382,16 @@ namespace SixLabors.ImageSharp.Formats.Bmp
/// <seealso href="https://www.fileformat.info/format/os2bmp/egff.htm"/> /// <seealso href="https://www.fileformat.info/format/os2bmp/egff.htm"/>
public static BmpInfoHeader ParseOs2Version2(ReadOnlySpan<byte> data) public static BmpInfoHeader ParseOs2Version2(ReadOnlySpan<byte> data)
{ {
var infoHeader = new BmpInfoHeader( BmpInfoHeader infoHeader = new(
headerSize: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(0, 4)), headerSize: BinaryPrimitives.ReadInt32LittleEndian(data[..4]),
width: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(4, 4)), width: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(4, 4)),
height: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(8, 4)), height: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(8, 4)),
planes: BinaryPrimitives.ReadInt16LittleEndian(data.Slice(12, 2)), planes: BinaryPrimitives.ReadInt16LittleEndian(data.Slice(12, 2)),
bitsPerPixel: BinaryPrimitives.ReadInt16LittleEndian(data.Slice(14, 2))); bitsPerPixel: BinaryPrimitives.ReadInt16LittleEndian(data.Slice(14, 2)));
int compression = BinaryPrimitives.ReadInt32LittleEndian(data.Slice(16, 4));
// The compression value in OS/2 bitmap has a different meaning than in windows bitmaps. // The compression value in OS/2 bitmap has a different meaning than in windows bitmaps.
// Map the OS/2 value to the windows values. // Map the OS/2 value to the windows values.
switch (compression) switch (BinaryPrimitives.ReadInt32LittleEndian(data.Slice(16, 4)))
{ {
case 0: case 0:
infoHeader.Compression = BmpCompression.RGB; infoHeader.Compression = BmpCompression.RGB;
@ -430,7 +428,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
/// <returns>The parsed header.</returns> /// <returns>The parsed header.</returns>
/// <seealso href="http://www.fileformat.info/format/bmp/egff.htm"/> /// <seealso href="http://www.fileformat.info/format/bmp/egff.htm"/>
public static BmpInfoHeader ParseV4(ReadOnlySpan<byte> data) => new( public static BmpInfoHeader ParseV4(ReadOnlySpan<byte> data) => new(
headerSize: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(0, 4)), headerSize: BinaryPrimitives.ReadInt32LittleEndian(data[..4]),
width: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(4, 4)), width: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(4, 4)),
height: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(8, 4)), height: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(8, 4)),
planes: BinaryPrimitives.ReadInt16LittleEndian(data.Slice(12, 2)), planes: BinaryPrimitives.ReadInt16LittleEndian(data.Slice(12, 2)),
@ -465,11 +463,12 @@ namespace SixLabors.ImageSharp.Formats.Bmp
/// <param name="data">The data to parse.</param> /// <param name="data">The data to parse.</param>
/// <returns>The parsed header.</returns> /// <returns>The parsed header.</returns>
/// <seealso href="https://docs.microsoft.com/de-de/windows/win32/api/wingdi/ns-wingdi-bitmapv5header?redirectedfrom=MSDN"/> /// <seealso href="https://docs.microsoft.com/de-de/windows/win32/api/wingdi/ns-wingdi-bitmapv5header?redirectedfrom=MSDN"/>
/// <exception cref="ArgumentException">Invalid size.</exception>
public static BmpInfoHeader ParseV5(ReadOnlySpan<byte> data) public static BmpInfoHeader ParseV5(ReadOnlySpan<byte> data)
{ {
if (data.Length < SizeV5) if (data.Length < SizeV5)
{ {
throw new ArgumentException(nameof(data), $"Must be {SizeV5} bytes. Was {data.Length} bytes."); throw new ArgumentException($"Must be {SizeV5} bytes. Was {data.Length} bytes.", nameof(data));
} }
return MemoryMarshal.Cast<byte, BmpInfoHeader>(data)[0]; return MemoryMarshal.Cast<byte, BmpInfoHeader>(data)[0];
@ -482,7 +481,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
public void WriteV3Header(Span<byte> buffer) public void WriteV3Header(Span<byte> buffer)
{ {
buffer.Clear(); buffer.Clear();
BinaryPrimitives.WriteInt32LittleEndian(buffer.Slice(0, 4), SizeV3); BinaryPrimitives.WriteInt32LittleEndian(buffer[..4], SizeV3);
BinaryPrimitives.WriteInt32LittleEndian(buffer.Slice(4, 4), this.Width); BinaryPrimitives.WriteInt32LittleEndian(buffer.Slice(4, 4), this.Width);
BinaryPrimitives.WriteInt32LittleEndian(buffer.Slice(8, 4), this.Height); BinaryPrimitives.WriteInt32LittleEndian(buffer.Slice(8, 4), this.Height);
BinaryPrimitives.WriteInt16LittleEndian(buffer.Slice(12, 2), this.Planes); BinaryPrimitives.WriteInt16LittleEndian(buffer.Slice(12, 2), this.Planes);
@ -502,7 +501,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
public void WriteV4Header(Span<byte> buffer) public void WriteV4Header(Span<byte> buffer)
{ {
buffer.Clear(); buffer.Clear();
BinaryPrimitives.WriteInt32LittleEndian(buffer.Slice(0, 4), SizeV4); BinaryPrimitives.WriteInt32LittleEndian(buffer[..4], SizeV4);
BinaryPrimitives.WriteInt32LittleEndian(buffer.Slice(4, 4), this.Width); BinaryPrimitives.WriteInt32LittleEndian(buffer.Slice(4, 4), this.Width);
BinaryPrimitives.WriteInt32LittleEndian(buffer.Slice(8, 4), this.Height); BinaryPrimitives.WriteInt32LittleEndian(buffer.Slice(8, 4), this.Height);
BinaryPrimitives.WriteInt16LittleEndian(buffer.Slice(12, 2), this.Planes); BinaryPrimitives.WriteInt16LittleEndian(buffer.Slice(12, 2), this.Planes);

4
src/ImageSharp/Formats/DecoderOptions.cs

@ -29,7 +29,7 @@ namespace SixLabors.ImageSharp.Formats
/// <summary> /// <summary>
/// Gets or sets the target size to decode the image into. /// Gets or sets the target size to decode the image into.
/// </summary> /// </summary>
public Size? TargetSize { get; set; } = null; public Size? TargetSize { get; set; }
/// <summary> /// <summary>
/// Gets or sets the sampler to use when resizing during decoding. /// Gets or sets the sampler to use when resizing during decoding.
@ -39,7 +39,7 @@ namespace SixLabors.ImageSharp.Formats
/// <summary> /// <summary>
/// Gets or sets a value indicating whether to ignore encoded metadata when decoding. /// Gets or sets a value indicating whether to ignore encoded metadata when decoding.
/// </summary> /// </summary>
public bool SkipMetadata { get; set; } = false; public bool SkipMetadata { get; set; }
/// <summary> /// <summary>
/// Gets or sets the maximum number of image frames to decode, inclusive. /// Gets or sets the maximum number of image frames to decode, inclusive.

27
src/ImageSharp/Formats/Gif/GifEncoderCore.cs

@ -108,10 +108,10 @@ namespace SixLabors.ImageSharp.Formats.Gif
this.bitDepth = ColorNumerics.GetBitsNeededForColorDepth(quantized.Palette.Length); this.bitDepth = ColorNumerics.GetBitsNeededForColorDepth(quantized.Palette.Length);
// Write the header. // Write the header.
this.WriteHeader(stream); WriteHeader(stream);
// Write the LSD. // Write the LSD.
int index = this.GetTransparentIndex(quantized); int index = GetTransparentIndex(quantized);
this.WriteLogicalScreenDescriptor(metadata, image.Width, image.Height, index, useGlobalTable, stream); this.WriteLogicalScreenDescriptor(metadata, image.Width, image.Height, index, useGlobalTable, stream);
if (useGlobalTable) if (useGlobalTable)
@ -193,7 +193,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
if (previousFrame != null && previousMeta.ColorTableLength != frameMetadata.ColorTableLength if (previousFrame != null && previousMeta.ColorTableLength != frameMetadata.ColorTableLength
&& frameMetadata.ColorTableLength > 0) && frameMetadata.ColorTableLength > 0)
{ {
var options = new QuantizerOptions QuantizerOptions options = new()
{ {
Dither = this.quantizer.Options.Dither, Dither = this.quantizer.Options.Dither,
DitherScale = this.quantizer.Options.DitherScale, DitherScale = this.quantizer.Options.DitherScale,
@ -211,7 +211,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
} }
this.bitDepth = ColorNumerics.GetBitsNeededForColorDepth(quantized.Palette.Length); this.bitDepth = ColorNumerics.GetBitsNeededForColorDepth(quantized.Palette.Length);
this.WriteGraphicalControlExtension(frameMetadata, this.GetTransparentIndex(quantized), stream); this.WriteGraphicalControlExtension(frameMetadata, GetTransparentIndex(quantized), stream);
this.WriteImageDescriptor(frame, true, stream); this.WriteImageDescriptor(frame, true, stream);
this.WriteColorTable(quantized, stream); this.WriteColorTable(quantized, stream);
this.WriteImageData(quantized, stream); this.WriteImageData(quantized, stream);
@ -231,7 +231,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
/// <returns> /// <returns>
/// The <see cref="int"/>. /// The <see cref="int"/>.
/// </returns> /// </returns>
private int GetTransparentIndex<TPixel>(IndexedImageFrame<TPixel> quantized) private static int GetTransparentIndex<TPixel>(IndexedImageFrame<TPixel> quantized)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
// Transparent pixels are much more likely to be found at the end of a palette. // Transparent pixels are much more likely to be found at the end of a palette.
@ -259,7 +259,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
/// </summary> /// </summary>
/// <param name="stream">The stream to write to.</param> /// <param name="stream">The stream to write to.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private void WriteHeader(Stream stream) => stream.Write(GifConstants.MagicNumber); private static void WriteHeader(Stream stream) => stream.Write(GifConstants.MagicNumber);
/// <summary> /// <summary>
/// Writes the logical screen descriptor to the stream. /// Writes the logical screen descriptor to the stream.
@ -308,7 +308,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
} }
} }
var descriptor = new GifLogicalScreenDescriptor( GifLogicalScreenDescriptor descriptor = new(
width: (ushort)width, width: (ushort)width,
height: (ushort)height, height: (ushort)height,
packed: packedValue, packed: packedValue,
@ -332,14 +332,14 @@ namespace SixLabors.ImageSharp.Formats.Gif
// Application Extension: Loop repeat count. // Application Extension: Loop repeat count.
if (frameCount > 1 && repeatCount != 1) if (frameCount > 1 && repeatCount != 1)
{ {
var loopingExtension = new GifNetscapeLoopingApplicationExtension(repeatCount); GifNetscapeLoopingApplicationExtension loopingExtension = new(repeatCount);
this.WriteExtension(loopingExtension, stream); this.WriteExtension(loopingExtension, stream);
} }
// Application Extension: XMP Profile. // Application Extension: XMP Profile.
if (xmpProfile != null) if (xmpProfile != null)
{ {
var xmpExtension = new GifXmpApplicationExtension(xmpProfile.Data); GifXmpApplicationExtension xmpExtension = new(xmpProfile.Data);
this.WriteExtension(xmpExtension, stream); this.WriteExtension(xmpExtension, stream);
} }
} }
@ -411,7 +411,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
disposalMethod: metadata.DisposalMethod, disposalMethod: metadata.DisposalMethod,
transparencyFlag: transparencyIndex > -1); transparencyFlag: transparencyIndex > -1);
var extension = new GifGraphicControlExtension( GifGraphicControlExtension extension = new(
packed: packedValue, packed: packedValue,
delayTime: (ushort)metadata.FrameDelay, delayTime: (ushort)metadata.FrameDelay,
transparencyIndex: unchecked((byte)transparencyIndex)); transparencyIndex: unchecked((byte)transparencyIndex));
@ -422,6 +422,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
/// <summary> /// <summary>
/// Writes the provided extension to the stream. /// Writes the provided extension to the stream.
/// </summary> /// </summary>
/// <typeparam name="TGifExtension">The type of gif extension.</typeparam>
/// <param name="extension">The extension to write to the stream.</param> /// <param name="extension">The extension to write to the stream.</param>
/// <param name="stream">The stream to write to.</param> /// <param name="stream">The stream to write to.</param>
private void WriteExtension<TGifExtension>(TGifExtension extension, Stream stream) private void WriteExtension<TGifExtension>(TGifExtension extension, Stream stream)
@ -448,7 +449,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
extensionBuffer[0] = GifConstants.ExtensionIntroducer; extensionBuffer[0] = GifConstants.ExtensionIntroducer;
extensionBuffer[1] = extension.Label; extensionBuffer[1] = extension.Label;
extension.WriteTo(extensionBuffer.Slice(2)); extension.WriteTo(extensionBuffer[2..]);
extensionBuffer[extensionSize + 2] = GifConstants.Terminator; extensionBuffer[extensionSize + 2] = GifConstants.Terminator;
@ -472,7 +473,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
sortFlag: false, sortFlag: false,
localColorTableSize: this.bitDepth - 1); localColorTableSize: this.bitDepth - 1);
var descriptor = new GifImageDescriptor( GifImageDescriptor descriptor = new(
left: 0, left: 0,
top: 0, top: 0,
width: (ushort)image.Width, width: (ushort)image.Width,
@ -517,7 +518,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
private void WriteImageData<TPixel>(IndexedImageFrame<TPixel> image, Stream stream) private void WriteImageData<TPixel>(IndexedImageFrame<TPixel> image, Stream stream)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
using var encoder = new LzwEncoder(this.memoryAllocator, (byte)this.bitDepth); using LzwEncoder encoder = new(this.memoryAllocator, (byte)this.bitDepth);
encoder.Encode(((IPixelSource)image).PixelBuffer, stream); encoder.Encode(((IPixelSource)image).PixelBuffer, stream);
} }
} }

2
src/ImageSharp/Formats/Gif/Sections/GifImageDescriptor.cs

@ -71,7 +71,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
{ {
buffer[0] = GifConstants.ImageDescriptorLabel; buffer[0] = GifConstants.ImageDescriptorLabel;
ref GifImageDescriptor dest = ref Unsafe.As<byte, GifImageDescriptor>(ref MemoryMarshal.GetReference(buffer.Slice(1))); ref GifImageDescriptor dest = ref Unsafe.As<byte, GifImageDescriptor>(ref MemoryMarshal.GetReference(buffer[1..]));
dest = this; dest = this;
} }

2
src/ImageSharp/Formats/Gif/Sections/GifNetscapeLoopingApplicationExtension.cs

@ -22,7 +22,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
public static GifNetscapeLoopingApplicationExtension Parse(ReadOnlySpan<byte> buffer) public static GifNetscapeLoopingApplicationExtension Parse(ReadOnlySpan<byte> buffer)
{ {
ushort repeatCount = BinaryPrimitives.ReadUInt16LittleEndian(buffer.Slice(0, 2)); ushort repeatCount = BinaryPrimitives.ReadUInt16LittleEndian(buffer[..2]);
return new GifNetscapeLoopingApplicationExtension(repeatCount); return new GifNetscapeLoopingApplicationExtension(repeatCount);
} }

4
src/ImageSharp/Formats/Gif/Sections/GifXmpApplicationExtension.cs

@ -55,11 +55,11 @@ namespace SixLabors.ImageSharp.Formats.Gif
// Write "XMP DataXMP" // Write "XMP DataXMP"
ReadOnlySpan<byte> idBytes = GifConstants.XmpApplicationIdentificationBytes; ReadOnlySpan<byte> idBytes = GifConstants.XmpApplicationIdentificationBytes;
idBytes.CopyTo(buffer.Slice(bytesWritten)); idBytes.CopyTo(buffer[bytesWritten..]);
bytesWritten += idBytes.Length; bytesWritten += idBytes.Length;
// XMP Data itself // XMP Data itself
this.Data.CopyTo(buffer.Slice(bytesWritten)); this.Data.CopyTo(buffer[bytesWritten..]);
bytesWritten += this.Data.Length; bytesWritten += this.Data.Length;
// Write the Magic Trailer // Write the Magic Trailer

2
src/ImageSharp/Formats/ImageFormatManager.cs

@ -101,7 +101,7 @@ namespace SixLabors.ImageSharp.Formats
if (extension[0] == '.') if (extension[0] == '.')
{ {
extension = extension.Substring(1); extension = extension[1..];
} }
return this.imageFormats.FirstOrDefault(x => x.FileExtensions.Contains(extension, StringComparer.OrdinalIgnoreCase)); return this.imageFormats.FirstOrDefault(x => x.FileExtensions.Contains(extension, StringComparer.OrdinalIgnoreCase));

2
src/ImageSharp/Formats/Jpeg/Components/Block8x8.Intrinsic.cs

@ -1,7 +1,6 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Six Labors Split License. // Licensed under the Six Labors Split License.
#if SUPPORTS_RUNTIME_INTRINSICS
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Runtime.Intrinsics; using System.Runtime.Intrinsics;
@ -36,4 +35,3 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
public Vector256<short> V67; public Vector256<short> V67;
} }
} }
#endif

68
src/ImageSharp/Formats/Jpeg/Components/Block8x8.cs

@ -5,11 +5,10 @@ using System;
using System.Numerics; using System.Numerics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
#if SUPPORTS_RUNTIME_INTRINSICS
using System.Runtime.Intrinsics; using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.X86; using System.Runtime.Intrinsics.X86;
#endif
using System.Text; using System.Text;
using SixLabors.ImageSharp.Common.Helpers;
namespace SixLabors.ImageSharp.Formats.Jpeg.Components namespace SixLabors.ImageSharp.Formats.Jpeg.Components
{ {
@ -188,7 +187,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public nint GetLastNonZeroIndex() public nint GetLastNonZeroIndex()
{ {
#if SUPPORTS_RUNTIME_INTRINSICS
if (Avx2.IsSupported) if (Avx2.IsSupported)
{ {
const int equalityMask = unchecked((int)0b1111_1111_1111_1111_1111_1111_1111_1111); const int equalityMask = unchecked((int)0b1111_1111_1111_1111_1111_1111_1111_1111);
@ -222,7 +220,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
return -1; return -1;
} }
else else
#endif
{ {
nint index = Size - 1; nint index = Size - 1;
ref short elemRef = ref Unsafe.As<Block8x8, short>(ref this); ref short elemRef = ref Unsafe.As<Block8x8, short>(ref this);
@ -245,53 +242,46 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
ref short elemRef = ref Unsafe.As<Block8x8, short>(ref this); ref short elemRef = ref Unsafe.As<Block8x8, short>(ref this);
// row #0 // row #0
Swap(ref Unsafe.Add(ref elemRef, 1), ref Unsafe.Add(ref elemRef, 8)); RuntimeUtility.Swap(ref Unsafe.Add(ref elemRef, 1), ref Unsafe.Add(ref elemRef, 8));
Swap(ref Unsafe.Add(ref elemRef, 2), ref Unsafe.Add(ref elemRef, 16)); RuntimeUtility.Swap(ref Unsafe.Add(ref elemRef, 2), ref Unsafe.Add(ref elemRef, 16));
Swap(ref Unsafe.Add(ref elemRef, 3), ref Unsafe.Add(ref elemRef, 24)); RuntimeUtility.Swap(ref Unsafe.Add(ref elemRef, 3), ref Unsafe.Add(ref elemRef, 24));
Swap(ref Unsafe.Add(ref elemRef, 4), ref Unsafe.Add(ref elemRef, 32)); RuntimeUtility.Swap(ref Unsafe.Add(ref elemRef, 4), ref Unsafe.Add(ref elemRef, 32));
Swap(ref Unsafe.Add(ref elemRef, 5), ref Unsafe.Add(ref elemRef, 40)); RuntimeUtility.Swap(ref Unsafe.Add(ref elemRef, 5), ref Unsafe.Add(ref elemRef, 40));
Swap(ref Unsafe.Add(ref elemRef, 6), ref Unsafe.Add(ref elemRef, 48)); RuntimeUtility.Swap(ref Unsafe.Add(ref elemRef, 6), ref Unsafe.Add(ref elemRef, 48));
Swap(ref Unsafe.Add(ref elemRef, 7), ref Unsafe.Add(ref elemRef, 56)); RuntimeUtility.Swap(ref Unsafe.Add(ref elemRef, 7), ref Unsafe.Add(ref elemRef, 56));
// row #1 // row #1
Swap(ref Unsafe.Add(ref elemRef, 10), ref Unsafe.Add(ref elemRef, 17)); RuntimeUtility.Swap(ref Unsafe.Add(ref elemRef, 10), ref Unsafe.Add(ref elemRef, 17));
Swap(ref Unsafe.Add(ref elemRef, 11), ref Unsafe.Add(ref elemRef, 25)); RuntimeUtility.Swap(ref Unsafe.Add(ref elemRef, 11), ref Unsafe.Add(ref elemRef, 25));
Swap(ref Unsafe.Add(ref elemRef, 12), ref Unsafe.Add(ref elemRef, 33)); RuntimeUtility.Swap(ref Unsafe.Add(ref elemRef, 12), ref Unsafe.Add(ref elemRef, 33));
Swap(ref Unsafe.Add(ref elemRef, 13), ref Unsafe.Add(ref elemRef, 41)); RuntimeUtility.Swap(ref Unsafe.Add(ref elemRef, 13), ref Unsafe.Add(ref elemRef, 41));
Swap(ref Unsafe.Add(ref elemRef, 14), ref Unsafe.Add(ref elemRef, 49)); RuntimeUtility.Swap(ref Unsafe.Add(ref elemRef, 14), ref Unsafe.Add(ref elemRef, 49));
Swap(ref Unsafe.Add(ref elemRef, 15), ref Unsafe.Add(ref elemRef, 57)); RuntimeUtility.Swap(ref Unsafe.Add(ref elemRef, 15), ref Unsafe.Add(ref elemRef, 57));
// row #2 // row #2
Swap(ref Unsafe.Add(ref elemRef, 19), ref Unsafe.Add(ref elemRef, 26)); RuntimeUtility.Swap(ref Unsafe.Add(ref elemRef, 19), ref Unsafe.Add(ref elemRef, 26));
Swap(ref Unsafe.Add(ref elemRef, 20), ref Unsafe.Add(ref elemRef, 34)); RuntimeUtility.Swap(ref Unsafe.Add(ref elemRef, 20), ref Unsafe.Add(ref elemRef, 34));
Swap(ref Unsafe.Add(ref elemRef, 21), ref Unsafe.Add(ref elemRef, 42)); RuntimeUtility.Swap(ref Unsafe.Add(ref elemRef, 21), ref Unsafe.Add(ref elemRef, 42));
Swap(ref Unsafe.Add(ref elemRef, 22), ref Unsafe.Add(ref elemRef, 50)); RuntimeUtility.Swap(ref Unsafe.Add(ref elemRef, 22), ref Unsafe.Add(ref elemRef, 50));
Swap(ref Unsafe.Add(ref elemRef, 23), ref Unsafe.Add(ref elemRef, 58)); RuntimeUtility.Swap(ref Unsafe.Add(ref elemRef, 23), ref Unsafe.Add(ref elemRef, 58));
// row #3 // row #3
Swap(ref Unsafe.Add(ref elemRef, 28), ref Unsafe.Add(ref elemRef, 35)); RuntimeUtility.Swap(ref Unsafe.Add(ref elemRef, 28), ref Unsafe.Add(ref elemRef, 35));
Swap(ref Unsafe.Add(ref elemRef, 29), ref Unsafe.Add(ref elemRef, 43)); RuntimeUtility.Swap(ref Unsafe.Add(ref elemRef, 29), ref Unsafe.Add(ref elemRef, 43));
Swap(ref Unsafe.Add(ref elemRef, 30), ref Unsafe.Add(ref elemRef, 51)); RuntimeUtility.Swap(ref Unsafe.Add(ref elemRef, 30), ref Unsafe.Add(ref elemRef, 51));
Swap(ref Unsafe.Add(ref elemRef, 31), ref Unsafe.Add(ref elemRef, 59)); RuntimeUtility.Swap(ref Unsafe.Add(ref elemRef, 31), ref Unsafe.Add(ref elemRef, 59));
// row #4 // row #4
Swap(ref Unsafe.Add(ref elemRef, 37), ref Unsafe.Add(ref elemRef, 44)); RuntimeUtility.Swap(ref Unsafe.Add(ref elemRef, 37), ref Unsafe.Add(ref elemRef, 44));
Swap(ref Unsafe.Add(ref elemRef, 38), ref Unsafe.Add(ref elemRef, 52)); RuntimeUtility.Swap(ref Unsafe.Add(ref elemRef, 38), ref Unsafe.Add(ref elemRef, 52));
Swap(ref Unsafe.Add(ref elemRef, 39), ref Unsafe.Add(ref elemRef, 60)); RuntimeUtility.Swap(ref Unsafe.Add(ref elemRef, 39), ref Unsafe.Add(ref elemRef, 60));
// row #5 // row #5
Swap(ref Unsafe.Add(ref elemRef, 46), ref Unsafe.Add(ref elemRef, 53)); RuntimeUtility.Swap(ref Unsafe.Add(ref elemRef, 46), ref Unsafe.Add(ref elemRef, 53));
Swap(ref Unsafe.Add(ref elemRef, 47), ref Unsafe.Add(ref elemRef, 61)); RuntimeUtility.Swap(ref Unsafe.Add(ref elemRef, 47), ref Unsafe.Add(ref elemRef, 61));
// row #6 // row #6
Swap(ref Unsafe.Add(ref elemRef, 55), ref Unsafe.Add(ref elemRef, 62)); RuntimeUtility.Swap(ref Unsafe.Add(ref elemRef, 55), ref Unsafe.Add(ref elemRef, 62));
static void Swap(ref short a, ref short b)
{
short tmp = a;
a = b;
b = tmp;
}
} }
/// <summary> /// <summary>

4
src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Intrinsic.cs

@ -1,7 +1,6 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Six Labors Split License. // Licensed under the Six Labors Split License.
#if SUPPORTS_RUNTIME_INTRINSICS
using System; using System;
using System.Numerics; using System.Numerics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
@ -43,7 +42,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
ref Vector256<float> bBase = ref b.V0; ref Vector256<float> bBase = ref b.V0;
ref Vector256<short> destRef = ref dest.V01; ref Vector256<short> destRef = ref dest.V01;
Vector256<int> multiplyIntoInt16ShuffleMask = Vector256.Create(0, 1, 4, 5, 2, 3, 6, 7); var multiplyIntoInt16ShuffleMask = Vector256.Create(0, 1, 4, 5, 2, 3, 6, 7);
for (nint i = 0; i < 8; i += 2) for (nint i = 0; i < 8; i += 2)
{ {
@ -145,4 +144,3 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
} }
} }
} }
#endif

148
src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs

@ -5,11 +5,10 @@ using System;
using System.Numerics; using System.Numerics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
#if SUPPORTS_RUNTIME_INTRINSICS
using System.Runtime.Intrinsics; using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.X86; using System.Runtime.Intrinsics.X86;
#endif
using System.Text; using System.Text;
using SixLabors.ImageSharp.Common.Helpers;
// ReSharper disable InconsistentNaming // ReSharper disable InconsistentNaming
namespace SixLabors.ImageSharp.Formats.Jpeg.Components namespace SixLabors.ImageSharp.Formats.Jpeg.Components
@ -160,10 +159,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public void MultiplyInPlace(float value) public void MultiplyInPlace(float value)
{ {
#if SUPPORTS_RUNTIME_INTRINSICS
if (Avx.IsSupported) if (Avx.IsSupported)
{ {
var valueVec = Vector256.Create(value); Vector256<float> valueVec = Vector256.Create(value);
this.V0 = Avx.Multiply(this.V0, valueVec); this.V0 = Avx.Multiply(this.V0, valueVec);
this.V1 = Avx.Multiply(this.V1, valueVec); this.V1 = Avx.Multiply(this.V1, valueVec);
this.V2 = Avx.Multiply(this.V2, valueVec); this.V2 = Avx.Multiply(this.V2, valueVec);
@ -174,9 +172,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
this.V7 = Avx.Multiply(this.V7, valueVec); this.V7 = Avx.Multiply(this.V7, valueVec);
} }
else else
#endif
{ {
var valueVec = new Vector4(value); Vector4 valueVec = new(value);
this.V0L *= valueVec; this.V0L *= valueVec;
this.V0R *= valueVec; this.V0R *= valueVec;
this.V1L *= valueVec; this.V1L *= valueVec;
@ -199,10 +196,10 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
/// <summary> /// <summary>
/// Multiply all elements of the block by the corresponding elements of 'other'. /// Multiply all elements of the block by the corresponding elements of 'other'.
/// </summary> /// </summary>
/// <param name="other">The other block.</param>
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public unsafe void MultiplyInPlace(ref Block8x8F other) public unsafe void MultiplyInPlace(ref Block8x8F other)
{ {
#if SUPPORTS_RUNTIME_INTRINSICS
if (Avx.IsSupported) if (Avx.IsSupported)
{ {
this.V0 = Avx.Multiply(this.V0, other.V0); this.V0 = Avx.Multiply(this.V0, other.V0);
@ -215,7 +212,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
this.V7 = Avx.Multiply(this.V7, other.V7); this.V7 = Avx.Multiply(this.V7, other.V7);
} }
else else
#endif
{ {
this.V0L *= other.V0L; this.V0L *= other.V0L;
this.V0R *= other.V0R; this.V0R *= other.V0R;
@ -243,10 +239,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public void AddInPlace(float value) public void AddInPlace(float value)
{ {
#if SUPPORTS_RUNTIME_INTRINSICS
if (Avx.IsSupported) if (Avx.IsSupported)
{ {
var valueVec = Vector256.Create(value); Vector256<float> valueVec = Vector256.Create(value);
this.V0 = Avx.Add(this.V0, valueVec); this.V0 = Avx.Add(this.V0, valueVec);
this.V1 = Avx.Add(this.V1, valueVec); this.V1 = Avx.Add(this.V1, valueVec);
this.V2 = Avx.Add(this.V2, valueVec); this.V2 = Avx.Add(this.V2, valueVec);
@ -257,9 +252,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
this.V7 = Avx.Add(this.V7, valueVec); this.V7 = Avx.Add(this.V7, valueVec);
} }
else else
#endif
{ {
var valueVec = new Vector4(value); Vector4 valueVec = new(value);
this.V0L += valueVec; this.V0L += valueVec;
this.V0R += valueVec; this.V0R += valueVec;
this.V1L += valueVec; this.V1L += valueVec;
@ -287,7 +281,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
/// <param name="qt">The quantization table.</param> /// <param name="qt">The quantization table.</param>
public static void Quantize(ref Block8x8F block, ref Block8x8 dest, ref Block8x8F qt) public static void Quantize(ref Block8x8F block, ref Block8x8 dest, ref Block8x8F qt)
{ {
#if SUPPORTS_RUNTIME_INTRINSICS
if (Avx2.IsSupported) if (Avx2.IsSupported)
{ {
MultiplyIntoInt16_Avx2(ref block, ref qt, ref dest); MultiplyIntoInt16_Avx2(ref block, ref qt, ref dest);
@ -299,7 +292,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
ZigZag.ApplyTransposingZigZagOrderingSsse3(ref dest); ZigZag.ApplyTransposingZigZagOrderingSsse3(ref dest);
} }
else else
#endif
{ {
for (int i = 0; i < Size; i++) for (int i = 0; i < Size; i++)
{ {
@ -339,6 +331,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
/// <summary> /// <summary>
/// Level shift by +maximum/2, clip to [0..maximum], and round all the values in the block. /// Level shift by +maximum/2, clip to [0..maximum], and round all the values in the block.
/// </summary> /// </summary>
/// <param name="maximum">The maximum value.</param>
public void NormalizeColorsAndRoundInPlace(float maximum) public void NormalizeColorsAndRoundInPlace(float maximum)
{ {
if (SimdUtils.HasVector8) if (SimdUtils.HasVector8)
@ -379,13 +372,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public void LoadFrom(ref Block8x8 source) public void LoadFrom(ref Block8x8 source)
{ {
#if SUPPORTS_EXTENDED_INTRINSICS
if (SimdUtils.HasVector8) if (SimdUtils.HasVector8)
{ {
this.LoadFromInt16ExtendedAvx2(ref source); this.LoadFromInt16ExtendedAvx2(ref source);
return; return;
} }
#endif
this.LoadFromInt16Scalar(ref source); this.LoadFromInt16Scalar(ref source);
} }
@ -427,12 +419,11 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
/// <param name="value">Value to compare to.</param> /// <param name="value">Value to compare to.</param>
public bool EqualsToScalar(int value) public bool EqualsToScalar(int value)
{ {
#if SUPPORTS_RUNTIME_INTRINSICS
if (Avx2.IsSupported) if (Avx2.IsSupported)
{ {
const int equalityMask = unchecked((int)0b1111_1111_1111_1111_1111_1111_1111_1111); const int equalityMask = unchecked((int)0b1111_1111_1111_1111_1111_1111_1111_1111);
var targetVector = Vector256.Create(value); Vector256<int> targetVector = Vector256.Create(value);
ref Vector256<float> blockStride = ref this.V0; ref Vector256<float> blockStride = ref this.V0;
for (int i = 0; i < RowCount; i++) for (int i = 0; i < RowCount; i++)
@ -446,20 +437,18 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
return true; return true;
} }
#endif
{
ref float scalars = ref Unsafe.As<Block8x8F, float>(ref this);
for (int i = 0; i < Size; i++) ref float scalars = ref Unsafe.As<Block8x8F, float>(ref this);
for (int i = 0; i < Size; i++)
{
if ((int)Unsafe.Add(ref scalars, i) != value)
{ {
if ((int)Unsafe.Add(ref scalars, i) != value) return false;
{
return false;
}
} }
return true;
} }
return true;
} }
/// <inheritdoc /> /// <inheritdoc />
@ -481,20 +470,46 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
&& this.V7L == other.V7L && this.V7L == other.V7L
&& this.V7R == other.V7R; && this.V7R == other.V7R;
/// <inheritdoc />
public override bool Equals(object obj) => this.Equals((Block8x8F)obj);
/// <inheritdoc />
public override int GetHashCode()
{
int left = HashCode.Combine(
this.V0L,
this.V1L,
this.V2L,
this.V3L,
this.V4L,
this.V5L,
this.V6L,
this.V7L);
int right = HashCode.Combine(
this.V0R,
this.V1R,
this.V2R,
this.V3R,
this.V4R,
this.V5R,
this.V6R,
this.V7R);
return HashCode.Combine(left, right);
}
/// <inheritdoc /> /// <inheritdoc />
public override string ToString() public override string ToString()
{ {
var sb = new StringBuilder(); StringBuilder sb = new();
sb.Append('['); sb.Append('[');
for (int i = 0; i < Size - 1; i++) for (int i = 0; i < Size - 1; i++)
{ {
sb.Append(this[i]); sb.Append(this[i]).Append(',');
sb.Append(',');
} }
sb.Append(this[Size - 1]); sb.Append(this[Size - 1]).Append(']');
sb.Append(']');
return sb.ToString(); return sb.ToString();
} }
@ -504,13 +519,11 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public void TransposeInplace() public void TransposeInplace()
{ {
#if SUPPORTS_RUNTIME_INTRINSICS
if (Avx.IsSupported) if (Avx.IsSupported)
{ {
this.TransposeInplace_Avx(); this.TransposeInplace_Avx();
} }
else else
#endif
{ {
this.TransposeInplace_Scalar(); this.TransposeInplace_Scalar();
} }
@ -525,53 +538,46 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
ref float elemRef = ref Unsafe.As<Block8x8F, float>(ref this); ref float elemRef = ref Unsafe.As<Block8x8F, float>(ref this);
// row #0 // row #0
Swap(ref Unsafe.Add(ref elemRef, 1), ref Unsafe.Add(ref elemRef, 8)); RuntimeUtility.Swap(ref Unsafe.Add(ref elemRef, 1), ref Unsafe.Add(ref elemRef, 8));
Swap(ref Unsafe.Add(ref elemRef, 2), ref Unsafe.Add(ref elemRef, 16)); RuntimeUtility.Swap(ref Unsafe.Add(ref elemRef, 2), ref Unsafe.Add(ref elemRef, 16));
Swap(ref Unsafe.Add(ref elemRef, 3), ref Unsafe.Add(ref elemRef, 24)); RuntimeUtility.Swap(ref Unsafe.Add(ref elemRef, 3), ref Unsafe.Add(ref elemRef, 24));
Swap(ref Unsafe.Add(ref elemRef, 4), ref Unsafe.Add(ref elemRef, 32)); RuntimeUtility.Swap(ref Unsafe.Add(ref elemRef, 4), ref Unsafe.Add(ref elemRef, 32));
Swap(ref Unsafe.Add(ref elemRef, 5), ref Unsafe.Add(ref elemRef, 40)); RuntimeUtility.Swap(ref Unsafe.Add(ref elemRef, 5), ref Unsafe.Add(ref elemRef, 40));
Swap(ref Unsafe.Add(ref elemRef, 6), ref Unsafe.Add(ref elemRef, 48)); RuntimeUtility.Swap(ref Unsafe.Add(ref elemRef, 6), ref Unsafe.Add(ref elemRef, 48));
Swap(ref Unsafe.Add(ref elemRef, 7), ref Unsafe.Add(ref elemRef, 56)); RuntimeUtility.Swap(ref Unsafe.Add(ref elemRef, 7), ref Unsafe.Add(ref elemRef, 56));
// row #1 // row #1
Swap(ref Unsafe.Add(ref elemRef, 10), ref Unsafe.Add(ref elemRef, 17)); RuntimeUtility.Swap(ref Unsafe.Add(ref elemRef, 10), ref Unsafe.Add(ref elemRef, 17));
Swap(ref Unsafe.Add(ref elemRef, 11), ref Unsafe.Add(ref elemRef, 25)); RuntimeUtility.Swap(ref Unsafe.Add(ref elemRef, 11), ref Unsafe.Add(ref elemRef, 25));
Swap(ref Unsafe.Add(ref elemRef, 12), ref Unsafe.Add(ref elemRef, 33)); RuntimeUtility.Swap(ref Unsafe.Add(ref elemRef, 12), ref Unsafe.Add(ref elemRef, 33));
Swap(ref Unsafe.Add(ref elemRef, 13), ref Unsafe.Add(ref elemRef, 41)); RuntimeUtility.Swap(ref Unsafe.Add(ref elemRef, 13), ref Unsafe.Add(ref elemRef, 41));
Swap(ref Unsafe.Add(ref elemRef, 14), ref Unsafe.Add(ref elemRef, 49)); RuntimeUtility.Swap(ref Unsafe.Add(ref elemRef, 14), ref Unsafe.Add(ref elemRef, 49));
Swap(ref Unsafe.Add(ref elemRef, 15), ref Unsafe.Add(ref elemRef, 57)); RuntimeUtility.Swap(ref Unsafe.Add(ref elemRef, 15), ref Unsafe.Add(ref elemRef, 57));
// row #2 // row #2
Swap(ref Unsafe.Add(ref elemRef, 19), ref Unsafe.Add(ref elemRef, 26)); RuntimeUtility.Swap(ref Unsafe.Add(ref elemRef, 19), ref Unsafe.Add(ref elemRef, 26));
Swap(ref Unsafe.Add(ref elemRef, 20), ref Unsafe.Add(ref elemRef, 34)); RuntimeUtility.Swap(ref Unsafe.Add(ref elemRef, 20), ref Unsafe.Add(ref elemRef, 34));
Swap(ref Unsafe.Add(ref elemRef, 21), ref Unsafe.Add(ref elemRef, 42)); RuntimeUtility.Swap(ref Unsafe.Add(ref elemRef, 21), ref Unsafe.Add(ref elemRef, 42));
Swap(ref Unsafe.Add(ref elemRef, 22), ref Unsafe.Add(ref elemRef, 50)); RuntimeUtility.Swap(ref Unsafe.Add(ref elemRef, 22), ref Unsafe.Add(ref elemRef, 50));
Swap(ref Unsafe.Add(ref elemRef, 23), ref Unsafe.Add(ref elemRef, 58)); RuntimeUtility.Swap(ref Unsafe.Add(ref elemRef, 23), ref Unsafe.Add(ref elemRef, 58));
// row #3 // row #3
Swap(ref Unsafe.Add(ref elemRef, 28), ref Unsafe.Add(ref elemRef, 35)); RuntimeUtility.Swap(ref Unsafe.Add(ref elemRef, 28), ref Unsafe.Add(ref elemRef, 35));
Swap(ref Unsafe.Add(ref elemRef, 29), ref Unsafe.Add(ref elemRef, 43)); RuntimeUtility.Swap(ref Unsafe.Add(ref elemRef, 29), ref Unsafe.Add(ref elemRef, 43));
Swap(ref Unsafe.Add(ref elemRef, 30), ref Unsafe.Add(ref elemRef, 51)); RuntimeUtility.Swap(ref Unsafe.Add(ref elemRef, 30), ref Unsafe.Add(ref elemRef, 51));
Swap(ref Unsafe.Add(ref elemRef, 31), ref Unsafe.Add(ref elemRef, 59)); RuntimeUtility.Swap(ref Unsafe.Add(ref elemRef, 31), ref Unsafe.Add(ref elemRef, 59));
// row #4 // row #4
Swap(ref Unsafe.Add(ref elemRef, 37), ref Unsafe.Add(ref elemRef, 44)); RuntimeUtility.Swap(ref Unsafe.Add(ref elemRef, 37), ref Unsafe.Add(ref elemRef, 44));
Swap(ref Unsafe.Add(ref elemRef, 38), ref Unsafe.Add(ref elemRef, 52)); RuntimeUtility.Swap(ref Unsafe.Add(ref elemRef, 38), ref Unsafe.Add(ref elemRef, 52));
Swap(ref Unsafe.Add(ref elemRef, 39), ref Unsafe.Add(ref elemRef, 60)); RuntimeUtility.Swap(ref Unsafe.Add(ref elemRef, 39), ref Unsafe.Add(ref elemRef, 60));
// row #5 // row #5
Swap(ref Unsafe.Add(ref elemRef, 46), ref Unsafe.Add(ref elemRef, 53)); RuntimeUtility.Swap(ref Unsafe.Add(ref elemRef, 46), ref Unsafe.Add(ref elemRef, 53));
Swap(ref Unsafe.Add(ref elemRef, 47), ref Unsafe.Add(ref elemRef, 61)); RuntimeUtility.Swap(ref Unsafe.Add(ref elemRef, 47), ref Unsafe.Add(ref elemRef, 61));
// row #6 // row #6
Swap(ref Unsafe.Add(ref elemRef, 55), ref Unsafe.Add(ref elemRef, 62)); RuntimeUtility.Swap(ref Unsafe.Add(ref elemRef, 55), ref Unsafe.Add(ref elemRef, 62));
static void Swap(ref float a, ref float b)
{
float tmp = a;
a = b;
b = tmp;
}
} }
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]

2
src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.CmykAvx.cs

@ -1,7 +1,6 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Six Labors Split License. // Licensed under the Six Labors Split License.
#if SUPPORTS_RUNTIME_INTRINSICS
using System; using System;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
@ -96,4 +95,3 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
} }
} }
} }
#endif

2
src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.GrayScaleAvx.cs

@ -1,7 +1,6 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Six Labors Split License. // Licensed under the Six Labors Split License.
#if SUPPORTS_RUNTIME_INTRINSICS
using System; using System;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
@ -69,4 +68,3 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
} }
} }
} }
#endif

2
src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.RgbAvx.cs

@ -1,7 +1,6 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Six Labors Split License. // Licensed under the Six Labors Split License.
#if SUPPORTS_RUNTIME_INTRINSICS
using System; using System;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
@ -53,4 +52,3 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
} }
} }
} }
#endif

2
src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.YCbCrAvx.cs

@ -1,7 +1,6 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Six Labors Split License. // Licensed under the Six Labors Split License.
#if SUPPORTS_RUNTIME_INTRINSICS
using System; using System;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
@ -122,4 +121,3 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
} }
} }
} }
#endif

2
src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.YccKAvx.cs

@ -1,7 +1,6 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Six Labors Split License. // Licensed under the Six Labors Split License.
#if SUPPORTS_RUNTIME_INTRINSICS
using System; using System;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
@ -133,4 +132,3 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
} }
} }
} }
#endif

2
src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverterAvx.cs

@ -1,6 +1,5 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Six Labors Split License. // Licensed under the Six Labors Split License.
#if SUPPORTS_RUNTIME_INTRINSICS
using System.Runtime.Intrinsics; using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.X86; using System.Runtime.Intrinsics.X86;
@ -34,4 +33,3 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
} }
} }
} }
#endif

14
src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverterBase.cs

@ -20,6 +20,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="JpegColorConverterBase"/> class. /// Initializes a new instance of the <see cref="JpegColorConverterBase"/> class.
/// </summary> /// </summary>
/// <param name="colorSpace">The color space.</param>
/// <param name="precision">The precision in bits.</param>
protected JpegColorConverterBase(JpegColorSpace colorSpace, int precision) protected JpegColorConverterBase(JpegColorSpace colorSpace, int precision)
{ {
this.ColorSpace = colorSpace; this.ColorSpace = colorSpace;
@ -66,6 +68,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
/// <summary> /// <summary>
/// Returns the <see cref="JpegColorConverterBase"/> corresponding to the given <see cref="JpegColorSpace"/> /// Returns the <see cref="JpegColorConverterBase"/> corresponding to the given <see cref="JpegColorSpace"/>
/// </summary> /// </summary>
/// <param name="colorSpace">The color space.</param>
/// <param name="precision">The precision in bits.</param>
/// <exception cref="InvalidImageContentException">Invalid colorspace.</exception>
public static JpegColorConverterBase GetConverter(JpegColorSpace colorSpace, int precision) public static JpegColorConverterBase GetConverter(JpegColorSpace colorSpace, int precision)
{ {
JpegColorConverterBase converter = Array.Find( JpegColorConverterBase converter = Array.Find(
@ -75,7 +80,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
if (converter is null) if (converter is null)
{ {
throw new Exception($"Could not find any converter for JpegColorSpace {colorSpace}!"); throw new InvalidImageContentException($"Could not find any converter for JpegColorSpace {colorSpace}!");
} }
return converter; return converter;
@ -104,7 +109,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
// 5 color types with 2 supported precisions: 8 bit & 12 bit // 5 color types with 2 supported precisions: 8 bit & 12 bit
const int colorConvertersCount = 5 * 2; const int colorConvertersCount = 5 * 2;
var converters = new JpegColorConverterBase[colorConvertersCount]; JpegColorConverterBase[] converters = new JpegColorConverterBase[colorConvertersCount];
// 8-bit converters // 8-bit converters
converters[0] = GetYCbCrConverter(8); converters[0] = GetYCbCrConverter(8);
@ -126,6 +131,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
/// <summary> /// <summary>
/// Returns the <see cref="JpegColorConverterBase"/>s for the YCbCr colorspace. /// Returns the <see cref="JpegColorConverterBase"/>s for the YCbCr colorspace.
/// </summary> /// </summary>
/// <param name="precision">The precision in bits.</param>
private static JpegColorConverterBase GetYCbCrConverter(int precision) private static JpegColorConverterBase GetYCbCrConverter(int precision)
{ {
if (JpegColorConverterAvx.IsSupported) if (JpegColorConverterAvx.IsSupported)
@ -144,6 +150,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
/// <summary> /// <summary>
/// Returns the <see cref="JpegColorConverterBase"/>s for the YccK colorspace. /// Returns the <see cref="JpegColorConverterBase"/>s for the YccK colorspace.
/// </summary> /// </summary>
/// <param name="precision">The precision in bits.</param>
private static JpegColorConverterBase GetYccKConverter(int precision) private static JpegColorConverterBase GetYccKConverter(int precision)
{ {
if (JpegColorConverterAvx.IsSupported) if (JpegColorConverterAvx.IsSupported)
@ -162,6 +169,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
/// <summary> /// <summary>
/// Returns the <see cref="JpegColorConverterBase"/>s for the CMYK colorspace. /// Returns the <see cref="JpegColorConverterBase"/>s for the CMYK colorspace.
/// </summary> /// </summary>
/// <param name="precision">The precision in bits.</param>
private static JpegColorConverterBase GetCmykConverter(int precision) private static JpegColorConverterBase GetCmykConverter(int precision)
{ {
if (JpegColorConverterAvx.IsSupported) if (JpegColorConverterAvx.IsSupported)
@ -180,6 +188,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
/// <summary> /// <summary>
/// Returns the <see cref="JpegColorConverterBase"/>s for the gray scale colorspace. /// Returns the <see cref="JpegColorConverterBase"/>s for the gray scale colorspace.
/// </summary> /// </summary>
/// <param name="precision">The precision in bits.</param>
private static JpegColorConverterBase GetGrayScaleConverter(int precision) private static JpegColorConverterBase GetGrayScaleConverter(int precision)
{ {
if (JpegColorConverterAvx.IsSupported) if (JpegColorConverterAvx.IsSupported)
@ -198,6 +207,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
/// <summary> /// <summary>
/// Returns the <see cref="JpegColorConverterBase"/>s for the RGB colorspace. /// Returns the <see cref="JpegColorConverterBase"/>s for the RGB colorspace.
/// </summary> /// </summary>
/// <param name="precision">The precision in bits.</param>
private static JpegColorConverterBase GetRgbConverter(int precision) private static JpegColorConverterBase GetRgbConverter(int precision)
{ {
if (JpegColorConverterAvx.IsSupported) if (JpegColorConverterAvx.IsSupported)

25
src/ImageSharp/Formats/Jpeg/Components/Decoder/ArithmeticScanDecoder.cs

@ -225,10 +225,10 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
{ {
for (int i = 0; i < this.components.Length; i++) for (int i = 0; i < this.components.Length; i++)
{ {
var component = this.components[i] as ArithmeticDecodingComponent; ArithmeticDecodingComponent component = this.components[i] as ArithmeticDecodingComponent;
this.dcDecodingTables[i] = this.GetArithmeticTable(arithmeticDecodingTables, true, component.DcTableId); this.dcDecodingTables[i] = GetArithmeticTable(arithmeticDecodingTables, true, component.DcTableId);
component.DcStatistics = this.CreateOrGetStatisticsBin(true, component.DcTableId); component.DcStatistics = this.CreateOrGetStatisticsBin(true, component.DcTableId);
this.acDecodingTables[i] = this.GetArithmeticTable(arithmeticDecodingTables, false, component.AcTableId); this.acDecodingTables[i] = GetArithmeticTable(arithmeticDecodingTables, false, component.AcTableId);
component.AcStatistics = this.CreateOrGetStatisticsBin(false, component.AcTableId); component.AcStatistics = this.CreateOrGetStatisticsBin(false, component.AcTableId);
} }
} }
@ -276,7 +276,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
this.spectralConverter.InjectFrameData(frame, jpegData); this.spectralConverter.InjectFrameData(frame, jpegData);
} }
private ArithmeticDecodingTable GetArithmeticTable(List<ArithmeticDecodingTable> arithmeticDecodingTables, bool isDcTable, int identifier) private static ArithmeticDecodingTable GetArithmeticTable(List<ArithmeticDecodingTable> arithmeticDecodingTables, bool isDcTable, int identifier)
{ {
int tableClass = isDcTable ? 0 : 1; int tableClass = isDcTable ? 0 : 1;
@ -306,15 +306,16 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
} }
} }
var statistic = new ArithmeticStatistics(dc, identifier); ArithmeticStatistics statistic = new(dc, identifier);
this.statistics.Add(statistic); this.statistics.Add(statistic);
return statistic; return statistic;
} }
private void ParseBaselineData() private void ParseBaselineData()
{ {
foreach (ArithmeticDecodingComponent component in this.components) for (int i = 0; i < this.components.Length; i++)
{ {
ArithmeticDecodingComponent component = (ArithmeticDecodingComponent)this.components[i];
component.DcPredictor = 0; component.DcPredictor = 0;
component.DcContext = 0; component.DcContext = 0;
component.DcStatistics?.Reset(); component.DcStatistics?.Reset();
@ -441,7 +442,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
for (int k = 0; k < this.scanComponentCount; k++) for (int k = 0; k < this.scanComponentCount; k++)
{ {
int order = this.frame.ComponentOrder[k]; int order = this.frame.ComponentOrder[k];
var component = this.components[order] as ArithmeticDecodingComponent; ArithmeticDecodingComponent component = this.components[order] as ArithmeticDecodingComponent;
ref ArithmeticDecodingTable dcDecodingTable = ref this.dcDecodingTables[component.DcTableId]; ref ArithmeticDecodingTable dcDecodingTable = ref this.dcDecodingTables[component.DcTableId];
ref ArithmeticDecodingTable acDecodingTable = ref this.acDecodingTables[component.AcTableId]; ref ArithmeticDecodingTable acDecodingTable = ref this.acDecodingTables[component.AcTableId];
@ -491,7 +492,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
private void ParseBaselineDataSingleComponent() private void ParseBaselineDataSingleComponent()
{ {
var component = this.frame.Components[0] as ArithmeticDecodingComponent; ArithmeticDecodingComponent component = this.frame.Components[0] as ArithmeticDecodingComponent;
int mcuLines = this.frame.McusPerColumn; int mcuLines = this.frame.McusPerColumn;
int w = component.WidthInBlocks; int w = component.WidthInBlocks;
int h = component.SamplingFactors.Height; int h = component.SamplingFactors.Height;
@ -537,7 +538,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
private void ParseBaselineDataNonInterleaved() private void ParseBaselineDataNonInterleaved()
{ {
var component = (ArithmeticDecodingComponent)this.components[this.frame.ComponentOrder[0]]; ArithmeticDecodingComponent component = (ArithmeticDecodingComponent)this.components[this.frame.ComponentOrder[0]];
ref JpegBitReader reader = ref this.scanBuffer; ref JpegBitReader reader = ref this.scanBuffer;
int w = component.WidthInBlocks; int w = component.WidthInBlocks;
@ -586,7 +587,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
for (int k = 0; k < this.scanComponentCount; k++) for (int k = 0; k < this.scanComponentCount; k++)
{ {
int order = this.frame.ComponentOrder[k]; int order = this.frame.ComponentOrder[k];
var component = this.components[order] as ArithmeticDecodingComponent; ArithmeticDecodingComponent component = this.components[order] as ArithmeticDecodingComponent;
ref ArithmeticDecodingTable dcDecodingTable = ref this.dcDecodingTables[component.DcTableId]; ref ArithmeticDecodingTable dcDecodingTable = ref this.dcDecodingTables[component.DcTableId];
int h = component.HorizontalSamplingFactor; int h = component.HorizontalSamplingFactor;
@ -628,7 +629,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
private void ParseProgressiveDataNonInterleaved() private void ParseProgressiveDataNonInterleaved()
{ {
var component = this.components[this.frame.ComponentOrder[0]] as ArithmeticDecodingComponent; ArithmeticDecodingComponent component = this.components[this.frame.ComponentOrder[0]] as ArithmeticDecodingComponent;
ref JpegBitReader reader = ref this.scanBuffer; ref JpegBitReader reader = ref this.scanBuffer;
int w = component.WidthInBlocks; int w = component.WidthInBlocks;
@ -1140,7 +1141,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
{ {
for (int i = 0; i < this.components.Length; i++) for (int i = 0; i < this.components.Length; i++)
{ {
var component = this.components[i] as ArithmeticDecodingComponent; ArithmeticDecodingComponent component = this.components[i] as ArithmeticDecodingComponent;
component.DcPredictor = 0; component.DcPredictor = 0;
} }

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

Loading…
Cancel
Save