Browse Source

update to most recent version

pull/725/head
SimantoR 7 years ago
parent
commit
be3718dd56
  1. 5
      .github/CONTRIBUTING.md
  2. 3
      .gitmodules
  3. 5
      ImageSharp.sln
  4. 1
      ImageSharp.sln.DotSettings
  5. 8
      README.md
  6. 103
      src/ImageSharp.Drawing/ImageSharp.Drawing.csproj
  7. 2
      src/ImageSharp.Drawing/Processing/BrushApplicator.cs
  8. 18
      src/ImageSharp.Drawing/Processing/EllipticGradientBrush{TPixel}.cs
  9. 14
      src/ImageSharp.Drawing/Processing/GradientBrushBase{TPixel}.cs
  10. 7
      src/ImageSharp.Drawing/Processing/ImageBrush{TPixel}.cs
  11. 22
      src/ImageSharp.Drawing/Processing/LinearGradientBrush{TPixel}.cs
  12. 7
      src/ImageSharp.Drawing/Processing/PatternBrush{TPixel}.cs
  13. 4
      src/ImageSharp.Drawing/Processing/Processors/Drawing/DrawImageProcessor.cs
  14. 36
      src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor.cs
  15. 52
      src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor.cs
  16. 10
      src/ImageSharp.Drawing/Processing/RadialGradientBrush{TPixel}.cs
  17. 7
      src/ImageSharp.Drawing/Processing/RecolorBrush{TPixel}.cs
  18. 22
      src/ImageSharp.Drawing/Processing/SolidBrush{TPixel}.cs
  19. 10
      src/ImageSharp/Advanced/AdvancedImageExtensions.cs
  20. 150
      src/ImageSharp/Advanced/AotCompilerTools.cs
  21. 1
      src/ImageSharp/Advanced/IPixelSource.cs
  22. 8
      src/ImageSharp/ColorSpaces/CieLab.cs
  23. 11
      src/ImageSharp/ColorSpaces/CieLch.cs
  24. 8
      src/ImageSharp/ColorSpaces/CieLchuv.cs
  25. 8
      src/ImageSharp/ColorSpaces/CieLuv.cs
  26. 4
      src/ImageSharp/ColorSpaces/CieXyChromaticityCoordinates.cs
  27. 7
      src/ImageSharp/ColorSpaces/CieXyy.cs
  28. 9
      src/ImageSharp/ColorSpaces/CieXyz.cs
  29. 10
      src/ImageSharp/ColorSpaces/Cmyk.cs
  30. 2
      src/ImageSharp/ColorSpaces/Companding/GammaCompanding.cs
  31. 6
      src/ImageSharp/ColorSpaces/Companding/LCompanding.cs
  32. 13
      src/ImageSharp/ColorSpaces/Companding/Rec2020Companding.cs
  33. 6
      src/ImageSharp/ColorSpaces/Companding/Rec709Companding.cs
  34. 26
      src/ImageSharp/ColorSpaces/Companding/SRgbCompanding.cs
  35. 47
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLab.cs
  36. 50
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLch.cs
  37. 50
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLchuv.cs
  38. 54
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLuv.cs
  39. 57
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyz.cs
  40. 42
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Cmyk.cs
  41. 36
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsl.cs
  42. 2
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsv.cs
  43. 68
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.HunterLab.cs
  44. 92
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.LinearRgb.cs
  45. 54
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.YCbCr.cs
  46. 2
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CIeLchToCieLabConverter.cs
  47. 2
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLabToCieLchConverter.cs
  48. 2
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLchuvToCieLuvConverter.cs
  49. 2
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLuvToCieLchuvConverter.cs
  50. 2
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzAndCieXyyConverter.cs
  51. 8
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToHunterLabConverter.cs
  52. 14
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToLinearRgbConverter.cs
  53. 4
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CmykAndRgbConverter.cs
  54. 9
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/HunterLabToCieXyzConverter.cs
  55. 15
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/LinearRgbToRgbConverter.cs
  56. 15
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/RgbToLinearRgbConverter.cs
  57. 4
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/YCbCrAndRgbConverter.cs
  58. 10
      src/ImageSharp/ColorSpaces/Conversion/Implementation/RGBPrimariesChromaticityCoordinates.cs
  59. 12
      src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/GammaWorkingSpace.cs
  60. 5
      src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/RgbWorkingSpaceBase.cs
  61. 4
      src/ImageSharp/ColorSpaces/Conversion/VonKriesChromaticAdaptation.cs
  62. 7
      src/ImageSharp/ColorSpaces/Hsl.cs
  63. 7
      src/ImageSharp/ColorSpaces/Hsv.cs
  64. 12
      src/ImageSharp/ColorSpaces/HunterLab.cs
  65. 6
      src/ImageSharp/ColorSpaces/Illuminants.cs
  66. 7
      src/ImageSharp/ColorSpaces/LinearRgb.cs
  67. 7
      src/ImageSharp/ColorSpaces/Lms.cs
  68. 15
      src/ImageSharp/ColorSpaces/Rgb.cs
  69. 3
      src/ImageSharp/ColorSpaces/RgbWorkingSpaces.cs
  70. 7
      src/ImageSharp/ColorSpaces/YCbCr.cs
  71. 5
      src/ImageSharp/Common/Extensions/EncoderExtensions.cs
  72. 4
      src/ImageSharp/Common/Extensions/EnumerableExtensions.cs
  73. 21
      src/ImageSharp/Common/Extensions/StreamExtensions.cs
  74. 14
      src/ImageSharp/Common/Helpers/DebugGuard.cs
  75. 20
      src/ImageSharp/Common/Helpers/Guard.cs
  76. 15
      src/ImageSharp/Common/Helpers/ImageMaths.cs
  77. 2
      src/ImageSharp/Common/Helpers/InliningOptions.cs
  78. 2
      src/ImageSharp/Common/Helpers/SimdUtils.BasicIntrinsics256.cs
  79. 19
      src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs
  80. 4
      src/ImageSharp/Common/Helpers/SimdUtils.cs
  81. 2
      src/ImageSharp/Common/Helpers/TestHelpers.cs
  82. 106
      src/ImageSharp/Common/Helpers/TolerantMath.cs
  83. 4
      src/ImageSharp/Common/Helpers/UnitConverter.cs
  84. 37
      src/ImageSharp/Common/Helpers/Vector4Utils.cs
  85. 2
      src/ImageSharp/Common/ParallelUtils/ParallelExecutionSettings.cs
  86. 6
      src/ImageSharp/Common/ParallelUtils/ParallelHelper.cs
  87. 7
      src/ImageSharp/Common/Tuples/Octet.cs
  88. 22
      src/ImageSharp/Common/Tuples/Vector4Pair.cs
  89. 12
      src/ImageSharp/Formats/Bmp/BmpCompression.cs
  90. 36
      src/ImageSharp/Formats/Bmp/BmpConstants.cs
  91. 2
      src/ImageSharp/Formats/Bmp/BmpDecoder.cs
  92. 647
      src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs
  93. 93
      src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs
  94. 4
      src/ImageSharp/Formats/Bmp/BmpFormat.cs
  95. 8
      src/ImageSharp/Formats/Bmp/BmpImageFormatDetector.cs
  96. 326
      src/ImageSharp/Formats/Bmp/BmpInfoHeader.cs
  97. 51
      src/ImageSharp/Formats/Bmp/BmpInfoHeaderType.cs
  98. 21
      src/ImageSharp/Formats/Bmp/BmpMetaData.cs
  99. 31
      src/ImageSharp/Formats/Bmp/BmpThrowHelper.cs
  100. 2
      src/ImageSharp/Formats/Bmp/IBmpDecoderOptions.cs

5
.github/CONTRIBUTING.md

@ -20,6 +20,11 @@
* Do not open an issue on GitHub until you have collected positive feedback about the change. GitHub issues are primarily intended for bug reports and fixes.
#### **Running tests and Debugging**
* Expected test output is pulled in as a submodule from the [ImageSharp.Tests.Images repository](https://github.com/SixLabors/Imagesharp.Tests.Images/tree/master/ReferenceOutput). To succesfully run tests, make sure that you have updated the submodules!
* Debugging (running tests in Debug mode) is only supported on .NET Core 2.1, because of JIT Code Generation bugs like [dotnet/coreclr#16443](https://github.com/dotnet/coreclr/issues/16443) or [dotnet/coreclr#20657](https://github.com/dotnet/coreclr/issues/20657)
#### **Do you have questions about consuming the library or the source code?**
* Ask any question about how to use ImageSharp in the [ImageSharp Gitter Chat Room](https://gitter.im/ImageSharp/General).

3
.gitmodules

@ -2,3 +2,6 @@
path = tests/Images/External
url = https://github.com/SixLabors/Imagesharp.Tests.Images.git
branch = master
[submodule "standards"]
path = standards
url = https://github.com/SixLabors/Standards

5
ImageSharp.sln

@ -5,7 +5,7 @@ VisualStudioVersion = 15.0.26730.12
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SolutionItems", "SolutionItems", "{C317F1B1-D75E-4C6D-83EB-80367343E0D7}"
ProjectSection(SolutionItems) = preProject
.editorconfig = .editorconfig
standards\.editorconfig = standards\.editorconfig
.travis.yml = .travis.yml
appveyor.yml = appveyor.yml
.github\ISSUE_TEMPLATE\ask-question.md = .github\ISSUE_TEMPLATE\ask-question.md
@ -15,12 +15,13 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SolutionItems", "SolutionIt
.github\CONTRIBUTING.md = .github\CONTRIBUTING.md
.github\ISSUE_TEMPLATE\feature-request.md = .github\ISSUE_TEMPLATE\feature-request.md
features.md = features.md
ImageSharp.ruleset = ImageSharp.ruleset
ImageSharp.sln.DotSettings = ImageSharp.sln.DotSettings
NuGet.config = NuGet.config
.github\PULL_REQUEST_TEMPLATE.md = .github\PULL_REQUEST_TEMPLATE.md
README.md = README.md
run-tests.ps1 = run-tests.ps1
standards\SixLabors.ruleset = standards\SixLabors.ruleset
standards\stylecop.json = standards\stylecop.json
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Source", "Source", "{815C0625-CD3D-440F-9F80-2D83856AB7AE}"

1
ImageSharp.sln.DotSettings

@ -382,6 +382,7 @@
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpKeepExistingMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpPlaceEmbeddedOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpRenamePlacementToArrangementMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpUseContinuousIndentInsideBracesMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EAddAccessorOwnerDeclarationBracesMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EAlwaysTreatStructAsNotReorderableMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002ECSharpPlaceAttributeOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>

8
README.md

@ -123,6 +123,14 @@ To clone ImageSharp locally click the "Clone in Windows" button above or run the
git clone https://github.com/SixLabors/ImageSharp
```
### Submodules
This repository contains [git submodules](https://blog.github.com/2016-02-01-working-with-submodules/). To add the submodules to the project, navigate to the repository root and type:
``` bash
git submodule update --init --recursive
```
### How can you help?
Please... Spread the word, contribute algorithms, submit performance improvements, unit tests, no input is too little. Make sure to read our [Contribution Guide](https://github.com/SixLabors/ImageSharp/blob/master/.github/CONTRIBUTING.md) before opening a PR.

103
src/ImageSharp.Drawing/ImageSharp.Drawing.csproj

@ -1,54 +1,53 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Description>An extension to ImageSharp that allows the drawing of images, paths, and text.</Description>
<AssemblyTitle>SixLabors.ImageSharp.Drawing</AssemblyTitle>
<VersionPrefix Condition="$(packageversion) != ''">$(packageversion)</VersionPrefix>
<VersionPrefix Condition="$(packageversion) == ''">0.0.1</VersionPrefix>
<Authors>SixLabors and contributors</Authors>
<TargetFrameworks>netstandard1.3;netstandard2.0</TargetFrameworks>
<LangVersion>7.3</LangVersion>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<AssemblyName>SixLabors.ImageSharp.Drawing</AssemblyName>
<PackageId>SixLabors.ImageSharp.Drawing</PackageId>
<PackageTags>Image Draw Shape Path Font</PackageTags>
<PackageIconUrl>https://raw.githubusercontent.com/SixLabors/Branding/master/icons/imagesharp/sixlabors.imagesharp.128.png</PackageIconUrl>
<PackageProjectUrl>https://github.com/SixLabors/ImageSharp</PackageProjectUrl>
<PackageLicenseUrl>http://www.apache.org/licenses/LICENSE-2.0</PackageLicenseUrl>
<RepositoryType>git</RepositoryType>
<RepositoryUrl>https://github.com/SixLabors/ImageSharp</RepositoryUrl>
<GenerateAssemblyDescriptionAttribute>false</GenerateAssemblyDescriptionAttribute>
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
<GenerateAssemblyCopyrightAttribute>false</GenerateAssemblyCopyrightAttribute>
<GenerateNeutralResourcesLanguageAttribute>false</GenerateNeutralResourcesLanguageAttribute>
<GenerateAssemblyVersionAttribute>false</GenerateAssemblyVersionAttribute>
<GenerateAssemblyFileVersionAttribute>false</GenerateAssemblyFileVersionAttribute>
<GenerateAssemblyInformationalVersionAttribute>false</GenerateAssemblyInformationalVersionAttribute>
<DebugType Condition="$(codecov) != ''">full</DebugType>
<DebugType Condition="$(codecov) == ''">portable</DebugType>
<DebugSymbols>True</DebugSymbols>
</PropertyGroup>
<ItemGroup>
<Compile Include="..\Shared\*.cs" Exclude="bin\**;obj\**;**\*.xproj;packages\**" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ImageSharp\ImageSharp.csproj" />
</ItemGroup>
<ItemGroup>
<AdditionalFiles Include="..\..\stylecop.json" />
<PackageReference Include="SixLabors.Fonts" Version="1.0.0-beta0007" />
<PackageReference Include="SixLabors.Shapes" Version="1.0.0-beta0007" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.0-beta007">
<PrivateAssets>All</PrivateAssets>
</PackageReference>
</ItemGroup>
<PropertyGroup>
<CodeAnalysisRuleSet>..\..\ImageSharp.ruleset</CodeAnalysisRuleSet>
<RootNamespace>SixLabors.ImageSharp</RootNamespace>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>
<PropertyGroup>
<AssemblyTitle>SixLabors.ImageSharp.Drawing</AssemblyTitle>
<Authors>SixLabors and contributors</Authors>
<Company>Six Labors</Company>
<Copyright>Copyright (c) Six Labors and contributors.</Copyright>
<Product>SixLabors.ImageSharp</Product>
<Description>An extension to ImageSharp that allows the drawing of images, paths, and text.</Description>
<NeutralLanguage>en</NeutralLanguage>
<VersionPrefix Condition="$(packageversion) != ''">$(packageversion)</VersionPrefix>
<VersionPrefix Condition="$(packageversion) == ''">0.0.1</VersionPrefix>
<TargetFrameworks>netcoreapp2.1;netstandard1.3;netstandard2.0</TargetFrameworks>
<LangVersion>7.3</LangVersion>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<AssemblyName>SixLabors.ImageSharp.Drawing</AssemblyName>
<PackageId>SixLabors.ImageSharp.Drawing</PackageId>
<PackageTags>Image Draw Shape Path Font</PackageTags>
<PackageIconUrl>https://raw.githubusercontent.com/SixLabors/Branding/master/icons/imagesharp/sixlabors.imagesharp.128.png</PackageIconUrl>
<PackageProjectUrl>https://github.com/SixLabors/ImageSharp</PackageProjectUrl>
<PackageLicenseUrl>http://www.apache.org/licenses/LICENSE-2.0</PackageLicenseUrl>
<RepositoryType>git</RepositoryType>
<RepositoryUrl>https://github.com/SixLabors/ImageSharp</RepositoryUrl>
<DebugType Condition="$(codecov) != ''">full</DebugType>
<DebugType Condition="$(codecov) == ''">portable</DebugType>
<DebugSymbols>True</DebugSymbols>
</PropertyGroup>
<ItemGroup>
<Compile Include="..\Shared\*.cs" Exclude="bin\**;obj\**;**\*.xproj;packages\**" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ImageSharp\ImageSharp.csproj" />
</ItemGroup>
<ItemGroup>
<AdditionalFiles Include="..\..\standards\stylecop.json" />
<PackageReference Include="SixLabors.Fonts" Version="1.0.0-beta0008" />
<PackageReference Include="SixLabors.Shapes" Version="1.0.0-beta0008" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.1-beta.61" PrivateAssets="All" />
</ItemGroup>
<PropertyGroup>
<CodeAnalysisRuleSet>..\..\standards\SixLabors.ruleset</CodeAnalysisRuleSet>
<RootNamespace>SixLabors.ImageSharp</RootNamespace>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>
</Project>

2
src/ImageSharp.Drawing/Processing/BrushApplicator.cs

@ -89,7 +89,7 @@ namespace SixLabors.ImageSharp.Processing
}
Span<TPixel> destinationRow = this.Target.GetPixelRowSpan(y).Slice(x, scanline.Length);
this.Blender.Blend(memoryAllocator, destinationRow, destinationRow, overlaySpan, amountSpan);
this.Blender.Blend(this.Target.Configuration, destinationRow, destinationRow, overlaySpan, amountSpan);
}
}
}

18
src/ImageSharp.Drawing/Processing/EllipticGradientBrush{TPixel}.cs

@ -18,9 +18,9 @@ namespace SixLabors.ImageSharp.Processing
public sealed class EllipticGradientBrush<TPixel> : GradientBrushBase<TPixel>
where TPixel : struct, IPixel<TPixel>
{
private readonly Point center;
private readonly PointF center;
private readonly Point referenceAxisEnd;
private readonly PointF referenceAxisEnd;
private readonly float axisRatio;
@ -35,8 +35,8 @@ namespace SixLabors.ImageSharp.Processing
/// <param name="repetitionMode">Defines how the colors of the gradients are repeated.</param>
/// <param name="colorStops">the color stops as defined in base class.</param>
public EllipticGradientBrush(
Point center,
Point referenceAxisEnd,
PointF center,
PointF referenceAxisEnd,
float axisRatio,
GradientRepetitionMode repetitionMode,
params ColorStop<TPixel>[] colorStops)
@ -64,9 +64,9 @@ namespace SixLabors.ImageSharp.Processing
/// <inheritdoc />
private sealed class RadialGradientBrushApplicator : GradientBrushApplicatorBase
{
private readonly Point center;
private readonly PointF center;
private readonly Point referenceAxisEnd;
private readonly PointF referenceAxisEnd;
private readonly float axisRatio;
@ -99,8 +99,8 @@ namespace SixLabors.ImageSharp.Processing
public RadialGradientBrushApplicator(
ImageFrame<TPixel> target,
GraphicsOptions options,
Point center,
Point referenceAxisEnd,
PointF center,
PointF referenceAxisEnd,
float axisRatio,
ColorStop<TPixel>[] colorStops,
GradientRepetitionMode repetitionMode)
@ -129,7 +129,7 @@ namespace SixLabors.ImageSharp.Processing
}
/// <inheritdoc />
protected override float PositionOnGradient(int xt, int yt)
protected override float PositionOnGradient(float xt, float yt)
{
float x0 = xt - this.center.X;
float y0 = yt - this.center.Y;

14
src/ImageSharp.Drawing/Processing/GradientBrushBase{TPixel}.cs

@ -81,7 +81,7 @@ namespace SixLabors.ImageSharp.Processing
{
get
{
float positionOnCompleteGradient = this.PositionOnGradient(x, y);
float positionOnCompleteGradient = this.PositionOnGradient(x + 0.5f, y + 0.5f);
switch (this.repetitionMode)
{
@ -121,7 +121,7 @@ namespace SixLabors.ImageSharp.Processing
{
var fromAsVector = from.Color.ToVector4();
var toAsVector = to.Color.ToVector4();
float onLocalGradient = (positionOnCompleteGradient - from.Ratio) / to.Ratio;
float onLocalGradient = (positionOnCompleteGradient - from.Ratio) / (to.Ratio - from.Ratio);
// TODO: this should be changeble for different gradienting functions
Vector4 result = PorterDuffFunctions.NormalSrcOver(
@ -137,18 +137,18 @@ namespace SixLabors.ImageSharp.Processing
}
/// <summary>
/// calculates the position on the gradient for a given pixel.
/// calculates the position on the gradient for a given point.
/// This method is abstract as it's content depends on the shape of the gradient.
/// </summary>
/// <param name="x">The x coordinate of the pixel</param>
/// <param name="y">The y coordinate of the pixel</param>
/// <param name="x">The x coordinate of the point</param>
/// <param name="y">The y coordinate of the point</param>
/// <returns>
/// The position the given pixel has on the gradient.
/// The position the given point has on the gradient.
/// The position is not bound to the [0..1] interval.
/// Values outside of that interval may be treated differently,
/// e.g. for the <see cref="GradientRepetitionMode" /> enum.
/// </returns>
protected abstract float PositionOnGradient(int x, int y);
protected abstract float PositionOnGradient(float x, float y);
private (ColorStop<TPixel> from, ColorStop<TPixel> to) GetGradientSegment(
float positionOnCompleteGradient)

7
src/ImageSharp.Drawing/Processing/ImageBrush{TPixel}.cs

@ -140,7 +140,12 @@ namespace SixLabors.ImageSharp.Processing
}
Span<TPixel> destinationRow = this.Target.GetPixelRowSpan(y).Slice(x, scanline.Length);
this.Blender.Blend(this.source.MemoryAllocator, destinationRow, destinationRow, overlaySpan, amountSpan);
this.Blender.Blend(
this.source.Configuration,
destinationRow,
destinationRow,
overlaySpan,
amountSpan);
}
}
}

22
src/ImageSharp.Drawing/Processing/LinearGradientBrush{TPixel}.cs

@ -17,9 +17,9 @@ namespace SixLabors.ImageSharp.Processing
public sealed class LinearGradientBrush<TPixel> : GradientBrushBase<TPixel>
where TPixel : struct, IPixel<TPixel>
{
private readonly Point p1;
private readonly PointF p1;
private readonly Point p2;
private readonly PointF p2;
/// <summary>
/// Initializes a new instance of the <see cref="LinearGradientBrush{TPixel}"/> class.
@ -29,8 +29,8 @@ namespace SixLabors.ImageSharp.Processing
/// <param name="repetitionMode">defines how colors are repeated.</param>
/// <param name="colorStops"><inheritdoc /></param>
public LinearGradientBrush(
Point p1,
Point p2,
PointF p1,
PointF p2,
GradientRepetitionMode repetitionMode,
params ColorStop<TPixel>[] colorStops)
: base(repetitionMode, colorStops)
@ -48,9 +48,9 @@ namespace SixLabors.ImageSharp.Processing
/// </summary>
private sealed class LinearGradientBrushApplicator : GradientBrushApplicatorBase
{
private readonly Point start;
private readonly PointF start;
private readonly Point end;
private readonly PointF end;
/// <summary>
/// the vector along the gradient, x component
@ -93,8 +93,8 @@ namespace SixLabors.ImageSharp.Processing
/// <param name="options">the graphics options</param>
public LinearGradientBrushApplicator(
ImageFrame<TPixel> source,
Point start,
Point end,
PointF start,
PointF end,
ColorStop<TPixel>[] colorStops,
GradientRepetitionMode repetitionMode,
GraphicsOptions options)
@ -116,15 +116,15 @@ namespace SixLabors.ImageSharp.Processing
this.length = (float)Math.Sqrt(this.alongsSquared);
}
protected override float PositionOnGradient(int x, int y)
protected override float PositionOnGradient(float x, float y)
{
if (this.acrossX == 0)
{
return (x - this.start.X) / (float)(this.end.X - this.start.X);
return (x - this.start.X) / (this.end.X - this.start.X);
}
else if (this.acrossY == 0)
{
return (y - this.start.Y) / (float)(this.end.Y - this.start.Y);
return (y - this.start.Y) / (this.end.Y - this.start.Y);
}
else
{

7
src/ImageSharp.Drawing/Processing/PatternBrush{TPixel}.cs

@ -170,7 +170,12 @@ namespace SixLabors.ImageSharp.Processing
}
Span<TPixel> destinationRow = this.Target.GetPixelRowSpan(y).Slice(x, scanline.Length);
this.Blender.Blend(memoryAllocator, destinationRow, destinationRow, overlaySpan, amountSpan);
this.Blender.Blend(
this.Target.Configuration,
destinationRow,
destinationRow,
overlaySpan,
amountSpan);
}
}
}

4
src/ImageSharp.Drawing/Processing/Processors/Drawing/DrawImageProcessor.cs

@ -79,8 +79,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing
int width = maxX - minX;
MemoryAllocator memoryAllocator = this.Image.GetConfiguration().MemoryAllocator;
var workingRect = Rectangle.FromLTRB(minX, minY, maxX, maxY);
ParallelHelper.IterateRows(
@ -93,7 +91,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing
Span<TPixelDst> background = source.GetPixelRowSpan(y).Slice(minX, width);
Span<TPixelSrc> foreground =
targetImage.GetPixelRowSpan(y - locationY).Slice(targetX, width);
blender.Blend<TPixelSrc>(memoryAllocator, background, background, foreground, this.Opacity);
blender.Blend<TPixelSrc>(configuration, background, background, foreground, this.Opacity);
}
});
}

36
src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor.cs

@ -3,7 +3,7 @@
using System;
using System.Buffers;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Primitives;
@ -82,11 +82,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing
// we need to offset the pixel grid to account for when we outline a path.
// basically if the line is [1,2] => [3,2] then when outlining at 1 we end up with a region of [0.5,1.5],[1.5, 1.5],[3.5,2.5],[2.5,2.5]
// and this can cause missed fills when not using antialiasing.so we offset the pixel grid by 0.5 in the x & y direction thus causing the#
// region to alline with the pixel grid.
// region to align with the pixel grid.
float offset = 0.5f;
if (this.Options.Antialias)
{
offset = 0f; // we are antialising skip offsetting as real antalising should take care of offset.
offset = 0f; // we are antialiasing skip offsetting as real antialiasing should take care of offset.
subpixelCount = this.Options.AntialiasSubpixelDepth;
if (subpixelCount < 4)
{
@ -107,6 +107,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing
Span<float> buffer = bBuffer.GetSpan();
Span<float> scanline = bScanline.GetSpan();
bool isSolidBrushWithoutBlending = this.IsSolidBrushWithoutBlending(out SolidBrush<TPixel> solidBrush);
for (int y = minY; y < maxY; y++)
{
if (scanlineDirty)
@ -121,7 +123,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing
int pointsFound = region.Scan(subPixel + offset, buffer, configuration);
if (pointsFound == 0)
{
// nothing on this line skip
// nothing on this line, skip
continue;
}
@ -168,16 +170,30 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing
{
if (!this.Options.Antialias)
{
bool hasOnes = false;
bool hasZeros = false;
for (int x = 0; x < scanlineWidth; x++)
{
if (scanline[x] >= 0.5)
{
scanline[x] = 1;
hasOnes = true;
}
else
{
scanline[x] = 0;
hasZeros = true;
}
}
if (isSolidBrushWithoutBlending && hasOnes != hasZeros)
{
if (hasOnes)
{
source.GetPixelRowSpan(y).Slice(minX, scanlineWidth).Fill(solidBrush.Color);
}
continue;
}
}
@ -187,5 +203,17 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing
}
}
}
private bool IsSolidBrushWithoutBlending(out SolidBrush<TPixel> solidBrush)
{
solidBrush = this.Brush as SolidBrush<TPixel>;
if (solidBrush == null)
{
return false;
}
return this.Options.IsOpaqueColorWithoutBlending(solidBrush.Color);
}
}
}

52
src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor.cs

@ -32,7 +32,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Text
/// <param name="font">The font we want to render with</param>
/// <param name="brush">The brush to source pixel colors from.</param>
/// <param name="pen">The pen to outline text with.</param>
/// <param name="location">The location on the image to start drawign the text from.</param>
/// <param name="location">The location on the image to start drawing the text from.</param>
public DrawTextProcessor(TextGraphicsOptions options, string text, Font font, IBrush<TPixel> brush, IPen<TPixel> pen, PointF location)
{
Guard.NotNull(text, nameof(text));
@ -85,7 +85,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Text
{
base.BeforeImageApply(source, sourceRectangle);
// do everythign at the image level as we are deligating the processing down to other processors
// do everything at the image level as we are delegating the processing down to other processors
var style = new RendererOptions(this.Font, this.Options.DpiX, this.Options.DpiY, this.Location)
{
ApplyKerning = this.Options.ApplyKerning,
@ -97,7 +97,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Text
this.textRenderer = new CachingGlyphRenderer(source.GetMemoryAllocator(), this.Text.Length, this.Pen, this.Brush != null);
this.textRenderer.Options = (GraphicsOptions)this.Options;
TextRenderer.RenderTextTo(this.textRenderer, this.Text, style);
var renderer = new TextRenderer(this.textRenderer);
renderer.RenderText(this.Text, style);
}
protected override void AfterImageApply(Image<TPixel> source, Rectangle sourceRectangle)
@ -138,10 +139,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Text
fistRow = -startY;
}
int end = operation.Map.Height;
int maxHeight = source.Height - startY;
end = Math.Min(end, maxHeight);
int end = Math.Min(operation.Map.Height, maxHeight);
for (int row = fistRow; row < end; row++)
{
@ -164,18 +163,26 @@ namespace SixLabors.ImageSharp.Processing.Processors.Text
private class CachingGlyphRenderer : IGlyphRenderer, IDisposable
{
private PathBuilder builder;
// just enough accuracy to allow for 1/8 pixel differences which
// later are accumulated while rendering, but do not grow into full pixel offsets
// The value 8 is benchmarked to:
// - Provide a good accuracy (smaller than 0.2% image difference compared to the non-caching variant)
// - Cache hit ratio above 60%
private const float AccuracyMultiple = 8;
private readonly PathBuilder builder;
private Point currentRenderPosition = default;
private GlyphRendererParameters currentGlyphRenderParams = default;
private int offset = 0;
private (GlyphRendererParameters glyph, PointF subPixelOffset) currentGlyphRenderParams = default;
private readonly int offset = 0;
private PointF currentPoint = default(PointF);
private readonly Dictionary<GlyphRendererParameters, GlyphRenderData> glyphData = new Dictionary<GlyphRendererParameters, GlyphRenderData>();
private readonly Dictionary<(GlyphRendererParameters glyph, PointF subPixelOffset), GlyphRenderData>
glyphData = new Dictionary<(GlyphRendererParameters glyph, PointF subPixelOffset), GlyphRenderData>();
private bool renderOutline = false;
private bool renderFill = false;
private bool raterizationRequired = false;
private readonly bool renderOutline = false;
private readonly bool renderFill = false;
private bool rasterizationRequired = false;
public CachingGlyphRenderer(MemoryAllocator memoryAllocator, int size, IPen pen, bool renderFill)
{
@ -213,17 +220,22 @@ namespace SixLabors.ImageSharp.Processing.Processors.Text
this.builder.StartFigure();
}
public bool BeginGlyph(RectangleF bounds, GlyphRendererParameters paramters)
public bool BeginGlyph(RectangleF bounds, GlyphRendererParameters parameters)
{
this.currentRenderPosition = Point.Truncate(bounds.Location);
PointF subPixelOffset = bounds.Location - this.currentRenderPosition;
subPixelOffset.X = MathF.Round(subPixelOffset.X * AccuracyMultiple) / AccuracyMultiple;
subPixelOffset.Y = MathF.Round(subPixelOffset.Y * AccuracyMultiple) / AccuracyMultiple;
// we have offset our rendering origion a little bit down to prevent edge cropping, move the draw origin up to compensate
this.currentRenderPosition = new Point(this.currentRenderPosition.X - this.offset, this.currentRenderPosition.Y - this.offset);
this.currentGlyphRenderParams = paramters;
if (this.glyphData.ContainsKey(paramters))
this.currentGlyphRenderParams = (parameters, subPixelOffset);
if (this.glyphData.ContainsKey(this.currentGlyphRenderParams))
{
// we have already drawn the glyph vectors skip trying again
this.raterizationRequired = false;
this.rasterizationRequired = false;
return false;
}
@ -233,7 +245,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Text
// ensure all glyphs render around [zero, zero] so offset negative root positions so when we draw the glyph we can offet it back
this.builder.SetOrigin(new PointF(-(int)bounds.X + this.offset, -(int)bounds.Y + this.offset));
this.raterizationRequired = true;
this.rasterizationRequired = true;
return true;
}
@ -252,7 +264,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Text
public void Dispose()
{
foreach (KeyValuePair<GlyphRendererParameters, GlyphRenderData> kv in this.glyphData)
foreach (KeyValuePair<(GlyphRendererParameters glyph, PointF subPixelOffset), GlyphRenderData> kv in this.glyphData)
{
kv.Value.Dispose();
}
@ -270,7 +282,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Text
GlyphRenderData renderData = default;
// has the glyoh been rendedered already????
if (this.raterizationRequired)
if (this.rasterizationRequired)
{
IPath path = this.builder.Build();

10
src/ImageSharp.Drawing/Processing/RadialGradientBrush{TPixel}.cs

@ -15,7 +15,7 @@ namespace SixLabors.ImageSharp.Processing
public sealed class RadialGradientBrush<TPixel> : GradientBrushBase<TPixel>
where TPixel : struct, IPixel<TPixel>
{
private readonly Point center;
private readonly PointF center;
private readonly float radius;
@ -25,7 +25,7 @@ namespace SixLabors.ImageSharp.Processing
/// <param name="repetitionMode">Defines how the colors in the gradient are repeated.</param>
/// <param name="colorStops">the color stops as defined in base class.</param>
public RadialGradientBrush(
Point center,
PointF center,
float radius,
GradientRepetitionMode repetitionMode,
params ColorStop<TPixel>[] colorStops)
@ -51,7 +51,7 @@ namespace SixLabors.ImageSharp.Processing
/// <inheritdoc />
private sealed class RadialGradientBrushApplicator : GradientBrushApplicatorBase
{
private readonly Point center;
private readonly PointF center;
private readonly float radius;
@ -67,7 +67,7 @@ namespace SixLabors.ImageSharp.Processing
public RadialGradientBrushApplicator(
ImageFrame<TPixel> target,
GraphicsOptions options,
Point center,
PointF center,
float radius,
ColorStop<TPixel>[] colorStops,
GradientRepetitionMode repetitionMode)
@ -89,7 +89,7 @@ namespace SixLabors.ImageSharp.Processing
/// <param name="x">The X coordinate of the target pixel.</param>
/// <param name="y">The Y coordinate of the target pixel.</param>
/// <returns>the position on the color gradient.</returns>
protected override float PositionOnGradient(int x, int y)
protected override float PositionOnGradient(float x, float y)
{
float distance = (float)Math.Sqrt(Math.Pow(this.center.X - x, 2) + Math.Pow(this.center.Y - y, 2));
return distance / this.radius;

7
src/ImageSharp.Drawing/Processing/RecolorBrush{TPixel}.cs

@ -158,7 +158,12 @@ namespace SixLabors.ImageSharp.Processing
}
Span<TPixel> destinationRow = this.Target.GetPixelRowSpan(y).Slice(x, scanline.Length);
this.Blender.Blend(memoryAllocator, destinationRow, destinationRow, overlaySpan, amountSpan);
this.Blender.Blend(
this.Target.Configuration,
destinationRow,
destinationRow,
overlaySpan,
amountSpan);
}
}
}

22
src/ImageSharp.Drawing/Processing/SolidBrush{TPixel}.cs

@ -89,13 +89,24 @@ namespace SixLabors.ImageSharp.Processing
/// <inheritdoc />
internal override void Apply(Span<float> scanline, int x, int y)
{
Span<TPixel> destinationRow = this.Target.GetPixelRowSpan(y).Slice(x, scanline.Length);
Span<TPixel> destinationRow = this.Target.GetPixelRowSpan(y).Slice(x);
// constrain the spans to each other
if (destinationRow.Length > scanline.Length)
{
destinationRow = destinationRow.Slice(0, scanline.Length);
}
else
{
scanline = scanline.Slice(0, destinationRow.Length);
}
MemoryAllocator memoryAllocator = this.Target.MemoryAllocator;
Configuration configuration = this.Target.Configuration;
if (this.Options.BlendPercentage == 1f)
{
this.Blender.Blend(memoryAllocator, destinationRow, destinationRow, this.Colors.GetSpan(), scanline);
this.Blender.Blend(configuration, destinationRow, destinationRow, this.Colors.GetSpan(), scanline);
}
else
{
@ -108,7 +119,12 @@ namespace SixLabors.ImageSharp.Processing
amountSpan[i] = scanline[i] * this.Options.BlendPercentage;
}
this.Blender.Blend(memoryAllocator, destinationRow, destinationRow, this.Colors.GetSpan(), amountSpan);
this.Blender.Blend(
configuration,
destinationRow,
destinationRow,
this.Colors.GetSpan(),
amountSpan);
}
}
}

10
src/ImageSharp/Advanced/AdvancedImageExtensions.cs

@ -19,7 +19,7 @@ namespace SixLabors.ImageSharp.Advanced
/// Gets the configuration for the image.
/// </summary>
/// <typeparam name="TPixel">The Pixel format.</typeparam>
/// <param name="source">The source image</param>
/// <param name="source">The source image.</param>
/// <returns>Returns the configuration.</returns>
public static Configuration GetConfiguration<TPixel>(this Image<TPixel> source)
where TPixel : struct, IPixel<TPixel>
@ -150,7 +150,7 @@ namespace SixLabors.ImageSharp.Advanced
/// <summary>
/// Gets the <see cref="MemoryAllocator"/> assigned to 'source'.
/// </summary>
/// <param name="source">The source image</param>
/// <param name="source">The source image.</param>
/// <returns>Returns the configuration.</returns>
internal static MemoryAllocator GetMemoryAllocator(this IConfigurable source)
=> GetConfiguration(source).MemoryAllocator;
@ -160,7 +160,7 @@ namespace SixLabors.ImageSharp.Advanced
/// </summary>
/// <typeparam name="TPixel">The type of the pixel.</typeparam>
/// <param name="source">The source.</param>
/// <returns>The span retuned from Pixel source</returns>
/// <returns>The span returned from Pixel source</returns>
private static Span<TPixel> GetSpan<TPixel>(IPixelSource<TPixel> source)
where TPixel : struct, IPixel<TPixel>
=> source.PixelBuffer.GetSpan();
@ -172,7 +172,7 @@ namespace SixLabors.ImageSharp.Advanced
/// <param name="source">The source.</param>
/// <param name="row">The row.</param>
/// <returns>
/// The span retuned from Pixel source
/// The span returned from Pixel source
/// </returns>
private static Span<TPixel> GetSpan<TPixel>(IPixelSource<TPixel> source, int row)
where TPixel : struct, IPixel<TPixel>
@ -185,7 +185,7 @@ namespace SixLabors.ImageSharp.Advanced
/// <param name="source">The source.</param>
/// <param name="row">The row.</param>
/// <returns>
/// The span retuned from Pixel source
/// The span returned from Pixel source.
/// </returns>
private static Span<TPixel> GetSpan<TPixel>(Buffer2D<TPixel> source, int row)
where TPixel : struct, IPixel<TPixel>

150
src/ImageSharp/Advanced/AotCompilerTools.cs

@ -0,0 +1,150 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System.Numerics;
using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.Formats.Jpeg.Components;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Processors.Dithering;
using SixLabors.ImageSharp.Processing.Processors.Quantization;
namespace SixLabors.ImageSharp.Advanced
{
/// <summary>
/// Unlike traditional Mono/.NET, code on the iPhone is statically compiled ahead of time instead of being
/// compiled on demand by a JIT compiler. This means there are a few limitations with respect to generics,
/// these are caused because not every possible generic instantiation can be determined up front at compile time.
/// The Aot Compiler is designed to overcome the limitations of this compiler.
/// </summary>
public static class AotCompilerTools
{
static AotCompilerTools()
{
System.Runtime.CompilerServices.Unsafe.SizeOf<long>();
System.Runtime.CompilerServices.Unsafe.SizeOf<short>();
System.Runtime.CompilerServices.Unsafe.SizeOf<float>();
System.Runtime.CompilerServices.Unsafe.SizeOf<double>();
System.Runtime.CompilerServices.Unsafe.SizeOf<byte>();
System.Runtime.CompilerServices.Unsafe.SizeOf<Block8x8>();
System.Runtime.CompilerServices.Unsafe.SizeOf<Vector4>();
}
/// <summary>
/// Seeds the compiler using the given pixel format.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
public static void Seed<TPixel>()
where TPixel : struct, IPixel<TPixel>
{
// This is we actually call all the individual methods you need to seed.
AotCompileOctreeQuantizer<TPixel>();
AotCompileWuQuantizer<TPixel>();
AotCompileDithering<TPixel>();
System.Runtime.CompilerServices.Unsafe.SizeOf<TPixel>();
AotCodec<TPixel>(new Formats.Png.PngDecoder(), new Formats.Png.PngEncoder());
AotCodec<TPixel>(new Formats.Bmp.BmpDecoder(), new Formats.Bmp.BmpEncoder());
AotCodec<TPixel>(new Formats.Gif.GifDecoder(), new Formats.Gif.GifEncoder());
AotCodec<TPixel>(new Formats.Jpeg.JpegDecoder(), new Formats.Jpeg.JpegEncoder());
// TODO: Do the discovery work to figure out what works and what doesn't.
}
/// <summary>
/// Seeds the compiler using the given pixel formats.
/// </summary>
/// <typeparam name="TPixel">The first pixel format.</typeparam>
/// <typeparam name="TPixel2">The second pixel format.</typeparam>
public static void Seed<TPixel, TPixel2>()
where TPixel : struct, IPixel<TPixel>
where TPixel2 : struct, IPixel<TPixel2>
{
Seed<TPixel>();
Seed<TPixel2>();
}
/// <summary>
/// Seeds the compiler using the given pixel formats.
/// </summary>
/// <typeparam name="TPixel">The first pixel format.</typeparam>
/// <typeparam name="TPixel2">The second pixel format.</typeparam>
/// <typeparam name="TPixel3">The third pixel format.</typeparam>
public static void Seed<TPixel, TPixel2, TPixel3>()
where TPixel : struct, IPixel<TPixel>
where TPixel2 : struct, IPixel<TPixel2>
where TPixel3 : struct, IPixel<TPixel3>
{
Seed<TPixel, TPixel2>();
Seed<TPixel3>();
}
/// <summary>
/// This method doesn't actually do anything but serves an important purpose...
/// If you are running ImageSharp on iOS and try to call SaveAsGif, it will throw an excepion:
/// "Attempting to JIT compile method... OctreeFrameQuantizer.ConstructPalette... while running in aot-only mode."
/// The reason this happens is the SaveAsGif method makes haevy use of generics, which are too confusing for the AoT
/// compiler used on Xamarin.iOS. It spins up the JIT compiler to try and figure it out, but that is an illegal op on
/// iOS so it bombs out.
/// If you are getting the above error, you need to call this method, which will pre-seed the AoT compiler with the
/// necessary methods to complete the SaveAsGif call. That's it, otherwise you should NEVER need this method!!!
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
private static void AotCompileOctreeQuantizer<TPixel>()
where TPixel : struct, IPixel<TPixel>
{
var test = new OctreeFrameQuantizer<TPixel>(new OctreeQuantizer(false));
test.AotGetPalette();
}
/// <summary>
/// This method pre-seeds the WuQuantizer in the AoT compiler for iOS.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
private static void AotCompileWuQuantizer<TPixel>()
where TPixel : struct, IPixel<TPixel>
{
var test = new WuFrameQuantizer<TPixel>(new WuQuantizer(false));
test.QuantizeFrame(new ImageFrame<TPixel>(Configuration.Default, 1, 1));
test.AotGetPalette();
}
/// <summary>
/// This method pre-seeds the default dithering engine (FloydSteinbergDiffuser) in the AoT compiler for iOS.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
private static void AotCompileDithering<TPixel>()
where TPixel : struct, IPixel<TPixel>
{
var test = new FloydSteinbergDiffuser();
TPixel pixel = default;
test.Dither<TPixel>(new ImageFrame<TPixel>(Configuration.Default, 1, 1), pixel, pixel, 0, 0, 0, 0, 0, 0);
}
/// <summary>
/// This method pre-seeds the decoder and encoder for a given pixel format in the AoT compiler for iOS.
/// </summary>
/// <param name="decoder">The image decoder to seed.</param>
/// <param name="encoder">The image encoder to seed.</param>
/// <typeparam name="TPixel">The pixel format.</typeparam>
private static void AotCodec<TPixel>(IImageDecoder decoder, IImageEncoder encoder)
where TPixel : struct, IPixel<TPixel>
{
try
{
decoder.Decode<TPixel>(Configuration.Default, null);
}
catch
{
}
try
{
encoder.Encode<TPixel>(null, null);
}
catch
{
}
}
}
}

1
src/ImageSharp/Advanced/IPixelSource.cs

@ -3,7 +3,6 @@
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Memory;
namespace SixLabors.ImageSharp.Advanced
{

8
src/ImageSharp/ColorSpaces/CieLab.cs

@ -118,13 +118,7 @@ namespace SixLabors.ImageSharp.ColorSpaces
public static bool operator !=(CieLab left, CieLab right) => !left.Equals(right);
/// <inheritdoc/>
public override int GetHashCode()
{
int hash = this.L.GetHashCode();
hash = HashHelpers.Combine(hash, this.A.GetHashCode());
hash = HashHelpers.Combine(hash, this.B.GetHashCode());
return HashHelpers.Combine(hash, this.WhitePoint.GetHashCode());
}
public override int GetHashCode() => HashCode.Combine(this.L, this.A, this.B, this.WhitePoint);
/// <inheritdoc/>
public override string ToString() => FormattableString.Invariant($"CieLab({this.L:#0.##}, {this.A:#0.##}, {this.B:#0.##})");

11
src/ImageSharp/ColorSpaces/CieLch.cs

@ -13,15 +13,15 @@ namespace SixLabors.ImageSharp.ColorSpaces
/// </summary>
public readonly struct CieLch : IEquatable<CieLch>
{
private static readonly Vector3 Min = new Vector3(0, -200, 0);
private static readonly Vector3 Max = new Vector3(100, 200, 360);
/// <summary>
/// D50 standard illuminant.
/// Used when reference white is not specified explicitly.
/// </summary>
public static readonly CieXyz DefaultWhitePoint = Illuminants.D50;
private static readonly Vector3 Min = new Vector3(0, -200, 0);
private static readonly Vector3 Max = new Vector3(100, 200, 360);
/// <summary>
/// Gets the lightness dimension.
/// <remarks>A value ranging between 0 (black), 100 (diffuse white) or higher (specular white).</remarks>
@ -122,10 +122,7 @@ namespace SixLabors.ImageSharp.ColorSpaces
/// <inheritdoc/>
public override int GetHashCode()
{
int hash = this.L.GetHashCode();
hash = HashHelpers.Combine(hash, this.C.GetHashCode());
hash = HashHelpers.Combine(hash, this.H.GetHashCode());
return HashHelpers.Combine(hash, this.WhitePoint.GetHashCode());
return HashCode.Combine(this.L, this.C, this.H, this.WhitePoint);
}
/// <inheritdoc/>

8
src/ImageSharp/ColorSpaces/CieLchuv.cs

@ -119,13 +119,7 @@ namespace SixLabors.ImageSharp.ColorSpaces
public static bool operator !=(CieLchuv left, CieLchuv right) => !left.Equals(right);
/// <inheritdoc/>
public override int GetHashCode()
{
int hash = this.L.GetHashCode();
hash = HashHelpers.Combine(hash, this.C.GetHashCode());
hash = HashHelpers.Combine(hash, this.H.GetHashCode());
return HashHelpers.Combine(hash, this.WhitePoint.GetHashCode());
}
public override int GetHashCode() => HashCode.Combine(this.L, this.C, this.H, this.WhitePoint);
/// <inheritdoc/>
public override string ToString() => FormattableString.Invariant($"CieLchuv({this.L:#0.##}, {this.C:#0.##}, {this.H:#0.##})");

8
src/ImageSharp/ColorSpaces/CieLuv.cs

@ -119,13 +119,7 @@ namespace SixLabors.ImageSharp.ColorSpaces
public static bool operator !=(CieLuv left, CieLuv right) => !left.Equals(right);
/// <inheritdoc/>
public override int GetHashCode()
{
int hash = this.L.GetHashCode();
hash = HashHelpers.Combine(hash, this.U.GetHashCode());
hash = HashHelpers.Combine(hash, this.V.GetHashCode());
return HashHelpers.Combine(hash, this.WhitePoint.GetHashCode());
}
public override int GetHashCode() => HashCode.Combine(this.L, this.U, this.V, this.WhitePoint);
/// <inheritdoc/>
public override string ToString() => FormattableString.Invariant($"CieLuv({this.L:#0.##}, {this.U:#0.##}, {this.V:#0.##})");

4
src/ImageSharp/ColorSpaces/CieXyChromaticityCoordinates.cs

@ -8,7 +8,7 @@ using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.ColorSpaces
{
/// <summary>
/// Represents the coordinates of CIEXY chromaticity space
/// Represents the coordinates of CIEXY chromaticity space.
/// </summary>
public readonly struct CieXyChromaticityCoordinates : IEquatable<CieXyChromaticityCoordinates>
{
@ -64,7 +64,7 @@ namespace SixLabors.ImageSharp.ColorSpaces
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public override int GetHashCode() => HashHelpers.Combine(this.X.GetHashCode(), this.Y.GetHashCode());
public override int GetHashCode() => HashCode.Combine(this.X, this.Y);
/// <inheritdoc/>
public override string ToString() => FormattableString.Invariant($"CieXyChromaticityCoordinates({this.X:#0.##}, {this.Y:#0.##})");

7
src/ImageSharp/ColorSpaces/CieXyy.cs

@ -83,12 +83,7 @@ namespace SixLabors.ImageSharp.ColorSpaces
public static bool operator !=(CieXyy left, CieXyy right) => !left.Equals(right);
/// <inheritdoc/>
public override int GetHashCode()
{
int hash = this.X.GetHashCode();
hash = HashHelpers.Combine(hash, this.Y.GetHashCode());
return HashHelpers.Combine(hash, this.Yl.GetHashCode());
}
public override int GetHashCode() => HashCode.Combine(this.X, this.Y, this.Yl);
/// <inheritdoc/>
public override string ToString() => FormattableString.Invariant($"CieXyy({this.X:#0.##}, {this.Y:#0.##}, {this.Yl:#0.##})");

9
src/ImageSharp/ColorSpaces/CieXyz.cs

@ -26,7 +26,7 @@ namespace SixLabors.ImageSharp.ColorSpaces
public readonly float Y;
/// <summary>
/// Gets the Z component. Quasi-equal to blue stimulation, or the S cone response
/// 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;
@ -86,12 +86,7 @@ namespace SixLabors.ImageSharp.ColorSpaces
public Vector3 ToVector3() => new Vector3(this.X, this.Y, this.Z);
/// <inheritdoc/>
public override int GetHashCode()
{
int hash = this.X.GetHashCode();
hash = HashHelpers.Combine(hash, this.Y.GetHashCode());
return HashHelpers.Combine(hash, this.Z.GetHashCode());
}
public override int GetHashCode() => HashCode.Combine(this.X, this.Y, this.Z);
/// <inheritdoc/>
public override string ToString() => FormattableString.Invariant($"CieXyz({this.X:#0.##}, {this.Y:#0.##}, {this.Z:#0.##})");

10
src/ImageSharp/ColorSpaces/Cmyk.cs

@ -78,7 +78,7 @@ namespace SixLabors.ImageSharp.ColorSpaces
public static bool operator ==(Cmyk left, Cmyk right) => left.Equals(right);
/// <summary>
/// Compares two <see cref="Cmyk"/> objects for inequality
/// Compares two <see cref="Cmyk"/> objects for inequality.
/// </summary>
/// <param name="left">The <see cref="Cmyk"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="Cmyk"/> on the right side of the operand.</param>
@ -90,13 +90,7 @@ namespace SixLabors.ImageSharp.ColorSpaces
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public override int GetHashCode()
{
int hash = this.C.GetHashCode();
hash = HashHelpers.Combine(hash, this.M.GetHashCode());
hash = HashHelpers.Combine(hash, this.Y.GetHashCode());
return HashHelpers.Combine(hash, this.K.GetHashCode());
}
public override int GetHashCode() => HashCode.Combine(this.C, this.M, this.Y, this.K);
/// <inheritdoc/>
public override string ToString() => FormattableString.Invariant($"Cmyk({this.C:#0.##}, {this.M:#0.##}, {this.Y:#0.##}, {this.K:#0.##})");

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

@ -7,7 +7,7 @@ using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.ColorSpaces.Companding
{
/// <summary>
/// Implements gamma companding
/// Implements gamma companding.
/// </summary>
/// <remarks>
/// <see href="http://www.brucelindbloom.com/index.html?Eqn_RGB_to_XYZ.html"/>

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

@ -8,7 +8,7 @@ using SixLabors.ImageSharp.ColorSpaces.Conversion;
namespace SixLabors.ImageSharp.ColorSpaces.Companding
{
/// <summary>
/// Implements L* companding
/// Implements L* companding.
/// </summary>
/// <remarks>
/// For more info see:
@ -24,7 +24,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Companding
/// <returns>The <see cref="float"/> representing the linear channel value.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static float Expand(float channel)
=> channel <= 0.08 ? 100 * channel / CieConstants.Kappa : ImageMaths.Pow3((channel + 0.16F) / 1.16F);
=> channel <= 0.08F ? (100F * channel) / CieConstants.Kappa : ImageMaths.Pow3((channel + 0.16F) / 1.16F);
/// <summary>
/// Compresses an uncompanded channel (linear) to its nonlinear equivalent.
@ -33,6 +33,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Companding
/// <returns>The <see cref="float"/> representing the nonlinear channel value.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static float Compress(float channel)
=> channel <= CieConstants.Epsilon ? channel * CieConstants.Kappa / 100F : MathF.Pow(1.16F * channel, 0.3333333F) - 0.16F;
=> channel <= CieConstants.Epsilon ? (channel * CieConstants.Kappa) / 100F : (1.16F * MathF.Pow(channel, 0.3333333F)) - 0.16F;
}
}

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

@ -7,14 +7,19 @@ using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.ColorSpaces.Companding
{
/// <summary>
/// Implements Rec. 2020 companding function (for 12-bits).
/// Implements Rec. 2020 companding function.
/// </summary>
/// <remarks>
/// <see href="http://en.wikipedia.org/wiki/Rec._2020"/>
/// For 10-bits, companding is identical to <see cref="Rec709Companding"/>
/// </remarks>
public static class Rec2020Companding
{
private const float Alpha = 1.09929682680944F;
private const float AlphaMinusOne = Alpha - 1F;
private const float Beta = 0.018053968510807F;
private const float InverseBeta = Beta * 4.5F;
private const float Epsilon = 1 / 0.45F;
/// <summary>
/// Expands a companded channel to its linear equivalent with respect to the energy.
/// </summary>
@ -22,7 +27,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Companding
/// <returns>The <see cref="float"/> representing the linear channel value.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static float Expand(float channel)
=> channel < 0.08145F ? channel / 4.5F : MathF.Pow((channel + 0.0993F) / 1.0993F, 2.222222F);
=> channel < InverseBeta ? channel / 4.5F : MathF.Pow((channel + AlphaMinusOne) / Alpha, Epsilon);
/// <summary>
/// Compresses an uncompanded channel (linear) to its nonlinear equivalent.
@ -31,6 +36,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Companding
/// <returns>The <see cref="float"/> representing the nonlinear channel value.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static float Compress(float channel)
=> channel < 0.0181F ? 4500F * channel : (1.0993F * channel) - 0.0993F;
=> channel < Beta ? 4.5F * channel : (Alpha * MathF.Pow(channel, 0.45F)) - AlphaMinusOne;
}
}

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

@ -14,6 +14,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Companding
/// </remarks>
public static class Rec709Companding
{
private const float Epsilon = 1 / 0.45F;
/// <summary>
/// Expands a companded channel to its linear equivalent with respect to the energy.
/// </summary>
@ -21,7 +23,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Companding
/// <returns>The <see cref="float"/> representing the linear channel value.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static float Expand(float channel)
=> channel < 0.081F ? channel / 4.5F : MathF.Pow((channel + 0.099F) / 1.099F, 2.222222F);
=> channel < 0.081F ? channel / 4.5F : MathF.Pow((channel + 0.099F) / 1.099F, Epsilon);
/// <summary>
/// Compresses an uncompanded channel (linear) to its nonlinear equivalent.
@ -30,6 +32,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Companding
/// <returns>The <see cref="float"/> representing the nonlinear channel value.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static float Compress(float channel)
=> channel < 0.018F ? 4500F * channel : (1.099F * channel) - 0.099F;
=> channel < 0.018F ? 4.5F * channel : (1.099F * MathF.Pow(channel, 0.45F)) - 0.099F;
}
}

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

@ -9,7 +9,7 @@ using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.ColorSpaces.Companding
{
/// <summary>
/// Implements sRGB companding
/// Implements sRGB companding.
/// </summary>
/// <remarks>
/// For more info see:
@ -30,9 +30,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Companding
for (int i = 0; i < vectors.Length; i++)
{
ref Vector4 v = ref Unsafe.Add(ref baseRef, i);
v.X = Expand(v.X);
v.Y = Expand(v.Y);
v.Z = Expand(v.Z);
Expand(ref v);
}
}
@ -48,9 +46,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Companding
for (int i = 0; i < vectors.Length; i++)
{
ref Vector4 v = ref Unsafe.Add(ref baseRef, i);
v.X = Compress(v.X);
v.Y = Compress(v.Y);
v.Z = Compress(v.Z);
Compress(ref v);
}
}
@ -58,17 +54,25 @@ namespace SixLabors.ImageSharp.ColorSpaces.Companding
/// Expands a companded vector to its linear equivalent with respect to the energy.
/// </summary>
/// <param name="vector">The vector.</param>
/// <returns>The <see cref="Vector4"/> representing the linear channel values.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static Vector4 Expand(Vector4 vector) => new Vector4(Expand(vector.X), Expand(vector.Y), Expand(vector.Z), vector.W);
public static void Expand(ref Vector4 vector)
{
vector.X = Expand(vector.X);
vector.Y = Expand(vector.Y);
vector.Z = Expand(vector.Z);
}
/// <summary>
/// Compresses an uncompanded vector (linear) to its nonlinear equivalent.
/// </summary>
/// <param name="vector">The vector.</param>
/// <returns>The <see cref="Vector4"/> representing the nonlinear channel values.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static Vector4 Compress(Vector4 vector) => new Vector4(Compress(vector.X), Compress(vector.Y), Compress(vector.Z), vector.W);
public static void Compress(ref Vector4 vector)
{
vector.X = Compress(vector.X);
vector.Y = Compress(vector.Y);
vector.Z = Compress(vector.Z);
}
/// <summary>
/// Expands a companded channel to its linear equivalent with respect to the energy.

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

@ -19,7 +19,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
private static readonly CieLchToCieLabConverter CieLchToCieLabConverter = new CieLchToCieLabConverter();
/// <summary>
/// Converts a <see cref="CieLch"/> into a <see cref="CieLab"/>
/// Converts a <see cref="CieLch"/> into a <see cref="CieLab"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLab"/></returns>
@ -28,12 +28,11 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
// Conversion (perserving white point)
CieLab unadapted = CieLchToCieLabConverter.Convert(color);
// Adaptation
return this.Adapt(unadapted);
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLch"/> into <see cref="CieLab"/>
/// Performs the bulk conversion from <see cref="CieLch"/> into <see cref="CieLab"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
@ -54,7 +53,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="CieLchuv"/> into a <see cref="CieLab"/>
/// Converts a <see cref="CieLchuv"/> into a <see cref="CieLab"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLab"/></returns>
@ -66,7 +65,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLchuv"/> into <see cref="CieLab"/>
/// Performs the bulk conversion from <see cref="CieLchuv"/> into <see cref="CieLab"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
@ -87,7 +86,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="CieLuv"/> into a <see cref="CieLab"/>
/// Converts a <see cref="CieLuv"/> into a <see cref="CieLab"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLab"/></returns>
@ -99,7 +98,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLuv"/> into <see cref="CieLab"/>
/// Performs the bulk conversion from <see cref="CieLuv"/> into <see cref="CieLab"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
@ -120,7 +119,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="CieXyy"/> into a <see cref="CieLab"/>
/// Converts a <see cref="CieXyy"/> into a <see cref="CieLab"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLab"/></returns>
@ -132,7 +131,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieXyy"/> into <see cref="CieLab"/>
/// Performs the bulk conversion from <see cref="CieXyy"/> into <see cref="CieLab"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
@ -159,10 +158,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="CieLab"/></returns>
public CieLab ToCieLab(in CieXyz color)
{
// Adaptation
CieXyz adapted = this.Adapt(color, this.whitePoint, this.targetLabWhitePoint);
// Conversion
return this.cieXyzToCieLabConverter.Convert(adapted);
}
@ -199,7 +196,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="Cmyk"/> into <see cref="CieLab"/>
/// Performs the bulk conversion from <see cref="Cmyk"/> into <see cref="CieLab"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
@ -220,7 +217,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="Hsl"/> into a <see cref="CieLab"/>
/// Converts a <see cref="Hsl"/> into a <see cref="CieLab"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLab"/></returns>
@ -232,7 +229,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="Hsl"/> into <see cref="CieLab"/>
/// Performs the bulk conversion from <see cref="Hsl"/> into <see cref="CieLab"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
@ -253,7 +250,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="Hsv"/> into a <see cref="CieLab"/>
/// Converts a <see cref="Hsv"/> into a <see cref="CieLab"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLab"/></returns>
@ -264,7 +261,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="Hsv"/> into <see cref="CieLab"/>
/// Performs the bulk conversion from <see cref="Hsv"/> into <see cref="CieLab"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
@ -285,7 +282,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="HunterLab"/> into a <see cref="CieLab"/>
/// Converts a <see cref="HunterLab"/> into a <see cref="CieLab"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLab"/></returns>
@ -297,7 +294,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="HunterLab"/> into <see cref="CieLab"/>
/// Performs the bulk conversion from <see cref="HunterLab"/> into <see cref="CieLab"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
@ -318,7 +315,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="Lms"/> into a <see cref="CieLab"/>
/// Converts a <see cref="Lms"/> into a <see cref="CieLab"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLab"/></returns>
@ -330,7 +327,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="Lms"/> into <see cref="CieLab"/>
/// Performs the bulk conversion from <see cref="Lms"/> into <see cref="CieLab"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
@ -351,7 +348,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="LinearRgb"/> into a <see cref="CieLab"/>
/// Converts a <see cref="LinearRgb"/> into a <see cref="CieLab"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLab"/></returns>
@ -363,7 +360,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="LinearRgb"/> into <see cref="CieLab"/>
/// Performs the bulk conversion from <see cref="LinearRgb"/> into <see cref="CieLab"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
@ -384,7 +381,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="Rgb"/> into a <see cref="CieLab"/>
/// Converts a <see cref="Rgb"/> into a <see cref="CieLab"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLab"/></returns>
@ -396,7 +393,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="LinearRgb"/> into <see cref="CieLab"/>
/// Performs the bulk conversion from <see cref="LinearRgb"/> into <see cref="CieLab"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
@ -429,7 +426,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="YCbCr"/> into <see cref="CieLab"/>
/// Performs the bulk conversion from <see cref="YCbCr"/> into <see cref="CieLab"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>

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

@ -26,15 +26,13 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="CieLch"/></returns>
public CieLch ToCieLch(in CieLab color)
{
// Adaptation
CieLab adapted = this.Adapt(color);
// Conversion
return CieLabToCieLchConverter.Convert(adapted);
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLab"/> into <see cref="CieLch"/>
/// Performs the bulk conversion from <see cref="CieLab"/> into <see cref="CieLch"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
@ -55,7 +53,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="CieLchuv"/> into a <see cref="CieLch"/>
/// Converts a <see cref="CieLchuv"/> into a <see cref="CieLch"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLch"/></returns>
@ -67,7 +65,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLchuv"/> into <see cref="CieLch"/>
/// Performs the bulk conversion from <see cref="CieLchuv"/> into <see cref="CieLch"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
@ -88,7 +86,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="CieLuv"/> into a <see cref="CieLch"/>
/// Converts a <see cref="CieLuv"/> into a <see cref="CieLch"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLch"/></returns>
@ -100,7 +98,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLuv"/> into <see cref="CieLch"/>
/// Performs the bulk conversion from <see cref="CieLuv"/> into <see cref="CieLch"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
@ -121,7 +119,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="CieXyy"/> into a <see cref="CieLch"/>
/// Converts a <see cref="CieXyy"/> into a <see cref="CieLch"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLch"/></returns>
@ -133,7 +131,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieXyy"/> into <see cref="CieLch"/>
/// Performs the bulk conversion from <see cref="CieXyy"/> into <see cref="CieLch"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
@ -166,7 +164,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieXyz"/> into <see cref="CieLch"/>
/// Performs the bulk conversion from <see cref="CieXyz"/> into <see cref="CieLch"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
@ -187,7 +185,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="Cmyk"/> into a <see cref="CieLch"/>
/// Converts a <see cref="Cmyk"/> into a <see cref="CieLch"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLch"/></returns>
@ -198,7 +196,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="Cmyk"/> into <see cref="CieLch"/>
/// Performs the bulk conversion from <see cref="Cmyk"/> into <see cref="CieLch"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
@ -219,7 +217,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="Hsl"/> into a <see cref="CieLch"/>
/// Converts a <see cref="Hsl"/> into a <see cref="CieLch"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLch"/></returns>
@ -231,7 +229,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="Hsl"/> into <see cref="CieLch"/>
/// Performs the bulk conversion from <see cref="Hsl"/> into <see cref="CieLch"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
@ -252,7 +250,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="Hsv"/> into a <see cref="CieLch"/>
/// Converts a <see cref="Hsv"/> into a <see cref="CieLch"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLch"/></returns>
@ -264,7 +262,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="Hsv"/> into <see cref="CieLch"/>
/// Performs the bulk conversion from <see cref="Hsv"/> into <see cref="CieLch"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
@ -285,7 +283,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="HunterLab"/> into a <see cref="CieLch"/>
/// Converts a <see cref="HunterLab"/> into a <see cref="CieLch"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLch"/></returns>
@ -297,7 +295,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="HunterLab"/> into <see cref="CieLch"/>
/// Performs the bulk conversion from <see cref="HunterLab"/> into <see cref="CieLch"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
@ -318,7 +316,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="LinearRgb"/> into a <see cref="CieLch"/>
/// Converts a <see cref="LinearRgb"/> into a <see cref="CieLch"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLch"/></returns>
@ -330,7 +328,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="LinearRgb"/> into <see cref="CieLch"/>
/// Performs the bulk conversion from <see cref="LinearRgb"/> into <see cref="CieLch"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
@ -351,7 +349,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="Lms"/> into a <see cref="CieLch"/>
/// Converts a <see cref="Lms"/> into a <see cref="CieLch"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLch"/></returns>
@ -363,7 +361,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="Lms"/> into <see cref="CieLch"/>
/// Performs the bulk conversion from <see cref="Lms"/> into <see cref="CieLch"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
@ -384,7 +382,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="Rgb"/> into a <see cref="CieLch"/>
/// Converts a <see cref="Rgb"/> into a <see cref="CieLch"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLch"/></returns>
@ -396,7 +394,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="Rgb"/> into <see cref="CieLch"/>
/// Performs the bulk conversion from <see cref="Rgb"/> into <see cref="CieLch"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
@ -417,7 +415,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="YCbCr"/> into a <see cref="CieLch"/>
/// Converts a <see cref="YCbCr"/> into a <see cref="CieLch"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLch"/></returns>
@ -429,7 +427,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="YCbCr"/> into <see cref="CieLch"/>
/// Performs the bulk conversion from <see cref="YCbCr"/> into <see cref="CieLch"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>

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

@ -32,7 +32,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLab"/> into <see cref="CieLchuv"/>
/// Performs the bulk conversion from <see cref="CieLab"/> into <see cref="CieLchuv"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
@ -53,7 +53,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="CieLch"/> into a <see cref="CieLchuv"/>
/// Converts a <see cref="CieLch"/> into a <see cref="CieLchuv"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLchuv"/></returns>
@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLch"/> into <see cref="CieLchuv"/>
/// Performs the bulk conversion from <see cref="CieLch"/> into <see cref="CieLchuv"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
@ -86,21 +86,19 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="CieLuv"/> into a <see cref="CieLchuv"/>
/// Converts a <see cref="CieLuv"/> into a <see cref="CieLchuv"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLchuv"/></returns>
public CieLchuv ToCieLchuv(in CieLuv color)
{
// Adaptation
CieLuv adapted = this.Adapt(color);
// Conversion
return CieLuvToCieLchuvConverter.Convert(adapted);
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLuv"/> into <see cref="CieLchuv"/>
/// Performs the bulk conversion from <see cref="CieLuv"/> into <see cref="CieLchuv"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
@ -121,7 +119,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="CieXyy"/> into a <see cref="CieLchuv"/>
/// Converts a <see cref="CieXyy"/> into a <see cref="CieLchuv"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLchuv"/></returns>
@ -133,7 +131,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieXyy"/> into <see cref="CieLchuv"/>
/// Performs the bulk conversion from <see cref="CieXyy"/> into <see cref="CieLchuv"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
@ -154,7 +152,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="CieXyz"/> into a <see cref="CieLchuv"/>
/// Converts a <see cref="CieXyz"/> into a <see cref="CieLchuv"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLchuv"/></returns>
@ -166,7 +164,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieXyz"/> into <see cref="CieLchuv"/>
/// Performs the bulk conversion from <see cref="CieXyz"/> into <see cref="CieLchuv"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
@ -187,7 +185,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="Cmyk"/> into a <see cref="CieLchuv"/>
/// Converts a <see cref="Cmyk"/> into a <see cref="CieLchuv"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLchuv"/></returns>
@ -199,7 +197,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="Cmyk"/> into <see cref="CieLchuv"/>
/// Performs the bulk conversion from <see cref="Cmyk"/> into <see cref="CieLchuv"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
@ -220,7 +218,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="Hsl"/> into a <see cref="CieLchuv"/>
/// Converts a <see cref="Hsl"/> into a <see cref="CieLchuv"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLchuv"/></returns>
@ -253,7 +251,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="Hsv"/> into a <see cref="CieLchuv"/>
/// Converts a <see cref="Hsv"/> into a <see cref="CieLchuv"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLchuv"/></returns>
@ -265,7 +263,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="Hsv"/> into <see cref="CieLchuv"/>
/// Performs the bulk conversion from <see cref="Hsv"/> into <see cref="CieLchuv"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
@ -286,7 +284,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="HunterLab"/> into a <see cref="CieLchuv"/>
/// Converts a <see cref="HunterLab"/> into a <see cref="CieLchuv"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLchuv"/></returns>
@ -298,7 +296,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="HunterLab"/> into <see cref="CieLchuv"/>
/// Performs the bulk conversion from <see cref="HunterLab"/> into <see cref="CieLchuv"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
@ -319,7 +317,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="LinearRgb"/> into a <see cref="CieLchuv"/>
/// Converts a <see cref="LinearRgb"/> into a <see cref="CieLchuv"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLchuv"/></returns>
@ -331,7 +329,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="LinearRgb"/> into <see cref="CieLchuv"/>
/// Performs the bulk conversion from <see cref="LinearRgb"/> into <see cref="CieLchuv"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
@ -352,7 +350,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="Lms"/> into a <see cref="CieLchuv"/>
/// Converts a <see cref="Lms"/> into a <see cref="CieLchuv"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLchuv"/></returns>
@ -364,7 +362,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="Lms"/> into <see cref="CieLchuv"/>
/// Performs the bulk conversion from <see cref="Lms"/> into <see cref="CieLchuv"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
@ -385,7 +383,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="Rgb"/> into a <see cref="CieLchuv"/>
/// Converts a <see cref="Rgb"/> into a <see cref="CieLchuv"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLchuv"/></returns>
@ -397,7 +395,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="Rgb"/> into <see cref="CieLchuv"/>
/// Performs the bulk conversion from <see cref="Rgb"/> into <see cref="CieLchuv"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
@ -418,7 +416,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="YCbCr"/> into a <see cref="CieLchuv"/>
/// Converts a <see cref="YCbCr"/> into a <see cref="CieLchuv"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLchuv"/></returns>
@ -429,7 +427,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="YCbCr"/> into <see cref="CieLchuv"/>
/// Performs the bulk conversion from <see cref="YCbCr"/> into <see cref="CieLchuv"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>

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

@ -17,7 +17,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
private static readonly CieLchuvToCieLuvConverter CieLchuvToCieLuvConverter = new CieLchuvToCieLuvConverter();
/// <summary>
/// Converts a <see cref="CieLab"/> into a <see cref="CieLuv"/>
/// Converts a <see cref="CieLab"/> into a <see cref="CieLuv"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLuv"/></returns>
@ -28,7 +28,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLab"/> into <see cref="CieLuv"/>
/// Performs the bulk conversion from <see cref="CieLab"/> into <see cref="CieLuv"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
@ -49,7 +49,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="CieLch"/> into a <see cref="CieLuv"/>
/// Converts a <see cref="CieLch"/> into a <see cref="CieLuv"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLuv"/></returns>
@ -60,7 +60,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLch"/> into <see cref="CieLuv"/>
/// Performs the bulk conversion from <see cref="CieLch"/> into <see cref="CieLuv"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
@ -81,7 +81,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="CieLchuv"/> into a <see cref="CieLuv"/>
/// Converts a <see cref="CieLchuv"/> into a <see cref="CieLuv"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLab"/></returns>
@ -95,7 +95,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLchuv"/> into <see cref="CieLuv"/>
/// Performs the bulk conversion from <see cref="CieLchuv"/> into <see cref="CieLuv"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
@ -116,7 +116,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="CieXyy"/> into a <see cref="CieLuv"/>
/// Converts a <see cref="CieXyy"/> into a <see cref="CieLuv"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLuv"/></returns>
@ -127,7 +127,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieXyy"/> into <see cref="CieLuv"/>
/// Performs the bulk conversion from <see cref="CieXyy"/> into <see cref="CieLuv"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
@ -148,7 +148,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="CieXyz"/> into a <see cref="CieLuv"/>
/// Converts a <see cref="CieXyz"/> into a <see cref="CieLuv"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLuv"/></returns>
@ -162,7 +162,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieXyz"/> into <see cref="CieLuv"/>
/// Performs the bulk conversion from <see cref="CieXyz"/> into <see cref="CieLuv"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
@ -183,7 +183,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="Cmyk"/> into a <see cref="CieLuv"/>
/// Converts a <see cref="Cmyk"/> into a <see cref="CieLuv"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLuv"/></returns>
@ -194,7 +194,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="Cmyk"/> into <see cref="CieLuv"/>
/// Performs the bulk conversion from <see cref="Cmyk"/> into <see cref="CieLuv"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
@ -226,7 +226,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="Hsl"/> into <see cref="CieLuv"/>
/// Performs the bulk conversion from <see cref="Hsl"/> into <see cref="CieLuv"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
@ -247,7 +247,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="Hsv"/> into a <see cref="CieLuv"/>
/// Converts a <see cref="Hsv"/> into a <see cref="CieLuv"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLuv"/></returns>
@ -258,7 +258,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="Hsv"/> into <see cref="CieLuv"/>
/// Performs the bulk conversion from <see cref="Hsv"/> into <see cref="CieLuv"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
@ -279,7 +279,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="HunterLab"/> into a <see cref="CieLuv"/>
/// Converts a <see cref="HunterLab"/> into a <see cref="CieLuv"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLuv"/></returns>
@ -290,7 +290,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="HunterLab"/> into <see cref="CieLuv"/>
/// Performs the bulk conversion from <see cref="HunterLab"/> into <see cref="CieLuv"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
@ -311,7 +311,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="Lms"/> into a <see cref="CieLuv"/>
/// Converts a <see cref="Lms"/> into a <see cref="CieLuv"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLuv"/></returns>
@ -322,7 +322,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="Lms"/> into <see cref="CieLuv"/>
/// Performs the bulk conversion from <see cref="Lms"/> into <see cref="CieLuv"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
@ -343,7 +343,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="LinearRgb"/> into a <see cref="CieLuv"/>
/// Converts a <see cref="LinearRgb"/> into a <see cref="CieLuv"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLuv"/></returns>
@ -354,7 +354,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="LinearRgb"/> into <see cref="CieLuv"/>
/// Performs the bulk conversion from <see cref="LinearRgb"/> into <see cref="CieLuv"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
@ -375,7 +375,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="Rgb"/> into a <see cref="CieLuv"/>
/// Converts a <see cref="Rgb"/> into a <see cref="CieLuv"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLuv"/></returns>
@ -386,7 +386,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="Rgb"/> into <see cref="CieLuv"/>
/// Performs the bulk conversion from <see cref="Rgb"/> into <see cref="CieLuv"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
@ -407,7 +407,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="YCbCr"/> into a <see cref="CieLuv"/>
/// Converts a <see cref="YCbCr"/> into a <see cref="CieLuv"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLuv"/></returns>
@ -418,10 +418,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="YCbCr"/> into <see cref="CieLuv"/>
/// Performs the bulk conversion from <see cref="YCbCr"/> into <see cref="CieLuv"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
/// <param name="source">The span to the source colors.</param>
/// <param name="destination">The span to the destination colors.</param>
public void Convert(ReadOnlySpan<YCbCr> source, Span<CieLuv> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));

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

@ -24,7 +24,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
private LinearRgbToCieXyzConverter linearRgbToCieXyzConverter;
/// <summary>
/// Converts a <see cref="CieLab"/> into a <see cref="CieXyz"/>
/// Converts a <see cref="CieLab"/> into a <see cref="CieXyz"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieXyz"/></returns>
@ -38,7 +38,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLab"/> into <see cref="CieXyz"/>
/// Performs the bulk conversion from <see cref="CieLab"/> into <see cref="CieXyz"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
@ -59,7 +59,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="CieLch"/> into a <see cref="CieXyz"/>
/// Converts a <see cref="CieLch"/> into a <see cref="CieXyz"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieXyz"/></returns>
@ -73,7 +73,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLch"/> into <see cref="CieXyz"/>
/// Performs the bulk conversion from <see cref="CieLch"/> into <see cref="CieXyz"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
@ -94,7 +94,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="CieLuv"/> into a <see cref="CieXyz"/>
/// Converts a <see cref="CieLuv"/> into a <see cref="CieXyz"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieXyz"/></returns>
@ -108,7 +108,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLchuv"/> into <see cref="CieXyz"/>
/// Performs the bulk conversion from <see cref="CieLchuv"/> into <see cref="CieXyz"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
@ -143,7 +143,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLuv"/> into <see cref="CieXyz"/>
/// Performs the bulk conversion from <see cref="CieLuv"/> into <see cref="CieXyz"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
@ -164,7 +164,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="CieXyy"/> into a <see cref="CieXyz"/>
/// Converts a <see cref="CieXyy"/> into a <see cref="CieXyz"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieXyz"/></returns>
@ -175,7 +175,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <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>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
@ -196,20 +196,19 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="Cmyk"/> into a <see cref="CieXyz"/>
/// Converts a <see cref="Cmyk"/> into a <see cref="CieXyz"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieXyz"/></returns>
public CieXyz ToCieXyz(in Cmyk color)
{
// Conversion
var rgb = this.ToRgb(color);
return this.ToCieXyz(rgb);
}
/// <summary>
/// Performs the bulk conversion from <see cref="Cmyk"/> into <see cref="CieXyz"/>
/// Performs the bulk conversion from <see cref="Cmyk"/> into <see cref="CieXyz"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
@ -230,23 +229,22 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="Hsl"/> into a <see cref="CieXyz"/>
/// Converts a <see cref="Hsl"/> into a <see cref="CieXyz"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieXyz"/></returns>
public CieXyz ToCieXyz(in Hsl color)
{
// Conversion
var rgb = this.ToRgb(color);
return this.ToCieXyz(rgb);
}
/// <summary>
/// Performs the bulk conversion from <see cref="Hsl"/> into <see cref="CieXyz"/>
/// Performs the bulk conversion from <see cref="Hsl"/> into <see cref="CieXyz"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
/// <param name="source">The span to the source colors.</param>
/// <param name="destination">The span to the destination colors.</param>
public void Convert(ReadOnlySpan<Hsl> source, Span<CieXyz> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
@ -264,7 +262,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="Hsv"/> into a <see cref="CieXyz"/>
/// Converts a <see cref="Hsv"/> into a <see cref="CieXyz"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieXyz"/></returns>
@ -277,7 +275,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="Hsv"/> into <see cref="CieXyz"/>
/// Performs the bulk conversion from <see cref="Hsv"/> into <see cref="CieXyz"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
@ -298,21 +296,19 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="HunterLab"/> into a <see cref="CieXyz"/>
/// Converts a <see cref="HunterLab"/> into a <see cref="CieXyz"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieXyz"/></returns>
public CieXyz ToCieXyz(in HunterLab color)
{
// Conversion
CieXyz unadapted = HunterLabToCieXyzConverter.Convert(color);
// Adaptation
return this.Adapt(unadapted, color.WhitePoint);
}
/// <summary>
/// Performs the bulk conversion from <see cref="HunterLab"/> into <see cref="CieXyz"/>
/// Performs the bulk conversion from <see cref="HunterLab"/> into <see cref="CieXyz"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
@ -333,7 +329,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="LinearRgb"/> into a <see cref="CieXyz"/>
/// Converts a <see cref="LinearRgb"/> into a <see cref="CieXyz"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieXyz"/></returns>
@ -343,15 +339,14 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
LinearRgbToCieXyzConverter converter = this.GetLinearRgbToCieXyzConverter(color.WorkingSpace);
CieXyz unadapted = converter.Convert(color);
// Adaptation
return this.Adapt(unadapted, color.WorkingSpace.WhitePoint);
}
/// <summary>
/// Performs the bulk conversion from <see cref="LinearRgb"/> into <see cref="CieXyz"/>
/// Performs the bulk conversion from <see cref="LinearRgb"/> into <see cref="CieXyz"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
/// <param name="source">The span to the source colors.</param>
/// <param name="destination">The span to the destination colors.</param>
public void Convert(ReadOnlySpan<LinearRgb> source, Span<CieXyz> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
@ -369,18 +364,17 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="Lms"/> into a <see cref="CieXyz"/>
/// Converts a <see cref="Lms"/> into a <see cref="CieXyz"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieXyz"/></returns>
public CieXyz ToCieXyz(in Lms color)
{
// Conversion
return this.cieXyzAndLmsConverter.Convert(color);
}
/// <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"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
@ -440,7 +434,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="CieXyz"/></returns>
public CieXyz ToCieXyz(in YCbCr color)
{
// Conversion
var rgb = this.ToRgb(color);
return this.ToCieXyz(rgb);

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

@ -17,7 +17,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
private static readonly CmykAndRgbConverter CmykAndRgbConverter = new CmykAndRgbConverter();
/// <summary>
/// Converts a <see cref="CieLab"/> into a <see cref="Cmyk"/>
/// Converts a <see cref="CieLab"/> into a <see cref="Cmyk"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Cmyk"/></returns>
@ -29,7 +29,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLab"/> into <see cref="Cmyk"/>
/// Performs the bulk conversion from <see cref="CieLab"/> into <see cref="Cmyk"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
@ -50,7 +50,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="CieLch"/> into a <see cref="Cmyk"/>
/// Converts a <see cref="CieLch"/> into a <see cref="Cmyk"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Cmyk"/></returns>
@ -62,7 +62,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLch"/> into <see cref="Cmyk"/>
/// Performs the bulk conversion from <see cref="CieLch"/> into <see cref="Cmyk"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
@ -149,7 +149,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="CieXyy"/> into a <see cref="Cmyk"/>
/// Converts a <see cref="CieXyy"/> into a <see cref="Cmyk"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Cmyk"/></returns>
@ -161,7 +161,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieXyy"/> into <see cref="Cmyk"/>
/// Performs the bulk conversion from <see cref="CieXyy"/> into <see cref="Cmyk"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
@ -182,7 +182,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="CieXyz"/> into a <see cref="Cmyk"/>
/// Converts a <see cref="CieXyz"/> into a <see cref="Cmyk"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Cmyk"/></returns>
@ -215,7 +215,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="Hsl"/> into a <see cref="Cmyk"/>
/// Converts a <see cref="Hsl"/> into a <see cref="Cmyk"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Cmyk"/></returns>
@ -227,7 +227,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="Hsl"/> into <see cref="Cmyk"/>
/// Performs the bulk conversion from <see cref="Hsl"/> into <see cref="Cmyk"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
@ -248,7 +248,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="Hsv"/> into a <see cref="Cmyk"/>
/// Converts a <see cref="Hsv"/> into a <see cref="Cmyk"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Cmyk"/></returns>
@ -260,7 +260,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="Hsv"/> into <see cref="Cmyk"/>
/// Performs the bulk conversion from <see cref="Hsv"/> into <see cref="Cmyk"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
@ -281,7 +281,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="HunterLab"/> into a <see cref="Cmyk"/>
/// Converts a <see cref="HunterLab"/> into a <see cref="Cmyk"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Cmyk"/></returns>
@ -293,7 +293,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="HunterLab"/> into <see cref="Cmyk"/>
/// Performs the bulk conversion from <see cref="HunterLab"/> into <see cref="Cmyk"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
@ -314,7 +314,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="LinearRgb"/> into a <see cref="Cmyk"/>
/// Converts a <see cref="LinearRgb"/> into a <see cref="Cmyk"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Cmyk"/></returns>
@ -326,7 +326,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="LinearRgb"/> into <see cref="Cmyk"/>
/// Performs the bulk conversion from <see cref="LinearRgb"/> into <see cref="Cmyk"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
@ -347,7 +347,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="Lms"/> into a <see cref="Cmyk"/>
/// Converts a <see cref="Lms"/> into a <see cref="Cmyk"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Cmyk"/></returns>
@ -359,9 +359,9 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="Lms"/> into <see cref="Cmyk"/>
/// Performs the bulk conversion from <see cref="Lms"/> into <see cref="Cmyk"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="source">The span to the source colors,</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Lms> source, Span<Cmyk> destination)
{
@ -380,7 +380,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="Rgb"/> into a <see cref="Cmyk"/>
/// Converts a <see cref="Rgb"/> into a <see cref="Cmyk"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Cmyk"/></returns>
@ -408,7 +408,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="YCbCr"/> into a <see cref="Cmyk"/>
/// Converts a <see cref="YCbCr"/> into a <see cref="Cmyk"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Cmyk"/></returns>
@ -420,7 +420,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="YCbCr"/> into <see cref="Cmyk"/>
/// Performs the bulk conversion from <see cref="YCbCr"/> into <see cref="Cmyk"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>

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

@ -17,7 +17,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
private static readonly HslAndRgbConverter HslAndRgbConverter = new HslAndRgbConverter();
/// <summary>
/// Converts a <see cref="CieLab"/> into a <see cref="Hsl"/>
/// Converts a <see cref="CieLab"/> into a <see cref="Hsl"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Hsl"/></returns>
@ -29,7 +29,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLab"/> into <see cref="Hsl"/>
/// Performs the bulk conversion from <see cref="CieLab"/> into <see cref="Hsl"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
@ -50,7 +50,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="CieLch"/> into a <see cref="Hsl"/>
/// Converts a <see cref="CieLch"/> into a <see cref="Hsl"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Hsl"/></returns>
@ -62,7 +62,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLch"/> into <see cref="Hsl"/>
/// Performs the bulk conversion from <see cref="CieLch"/> into <see cref="Hsl"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
@ -83,7 +83,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="CieLchuv"/> into a <see cref="Hsl"/>
/// Converts a <see cref="CieLchuv"/> into a <see cref="Hsl"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Hsl"/></returns>
@ -95,7 +95,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLchuv"/> into <see cref="Hsl"/>
/// Performs the bulk conversion from <see cref="CieLchuv"/> into <see cref="Hsl"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
@ -116,7 +116,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="CieLuv"/> into a <see cref="Hsl"/>
/// Converts a <see cref="CieLuv"/> into a <see cref="Hsl"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Hsl"/></returns>
@ -128,7 +128,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLuv"/> into <see cref="Hsl"/>
/// Performs the bulk conversion from <see cref="CieLuv"/> into <see cref="Hsl"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
@ -149,7 +149,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="CieXyy"/> into a <see cref="Hsl"/>
/// Converts a <see cref="CieXyy"/> into a <see cref="Hsl"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Hsl"/></returns>
@ -281,7 +281,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="HunterLab"/> into a <see cref="Hsl"/>
/// Converts a <see cref="HunterLab"/> into a <see cref="Hsl"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Hsl"/></returns>
@ -293,7 +293,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="HunterLab"/> into <see cref="Hsl"/>
/// Performs the bulk conversion from <see cref="HunterLab"/> into <see cref="Hsl"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
@ -314,7 +314,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="LinearRgb"/> into a <see cref="Hsl"/>
/// Converts a <see cref="LinearRgb"/> into a <see cref="Hsl"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Hsl"/></returns>
@ -326,7 +326,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="LinearRgb"/> into <see cref="Hsl"/>
/// Performs the bulk conversion from <see cref="LinearRgb"/> into <see cref="Hsl"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
@ -347,7 +347,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="Lms"/> into a <see cref="Hsl"/>
/// Converts a <see cref="Lms"/> into a <see cref="Hsl"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Hsl"/></returns>
@ -359,7 +359,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="Lms"/> into <see cref="Hsl"/>
/// Performs the bulk conversion from <see cref="Lms"/> into <see cref="Hsl"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
@ -387,7 +387,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
public Hsl ToHsl(in Rgb color) => HslAndRgbConverter.Convert(color);
/// <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>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
@ -408,7 +408,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="YCbCr"/> into a <see cref="Hsl"/>
/// Converts a <see cref="YCbCr"/> into a <see cref="Hsl"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Hsl"/></returns>
@ -420,7 +420,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="YCbCr"/> into <see cref="Hsl"/>
/// Performs the bulk conversion from <see cref="YCbCr"/> into <see cref="Hsl"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>

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

@ -263,7 +263,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// Performs the bulk conversion from <see cref="Hsl"/> into <see cref="Hsv"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
/// <param name="destination">The span to the destination colors.</param>
public void Convert(ReadOnlySpan<Hsl> source, Span<Hsv> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));

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

@ -13,10 +13,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
public partial class ColorSpaceConverter
{
/// <summary>
/// Performs the bulk conversion from <see cref="CieLab"/> into <see cref="HunterLab"/>
/// Performs the bulk conversion from <see cref="CieLab"/> into <see cref="HunterLab"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
/// <param name="source">The span to the source colors.</param>
/// <param name="destination">The span to the destination colors.</param>
public void Convert(ReadOnlySpan<CieLab> source, Span<HunterLab> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
@ -34,10 +34,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLch"/> into <see cref="HunterLab"/>
/// Performs the bulk conversion from <see cref="CieLch"/> into <see cref="HunterLab"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
/// <param name="source">The span to the source colors.</param>
/// <param name="destination">The span to the destination colors.</param>
public void Convert(ReadOnlySpan<CieLch> source, Span<HunterLab> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
@ -55,7 +55,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLchuv"/> into <see cref="HunterLab"/>
/// Performs the bulk conversion from <see cref="CieLchuv"/> into <see cref="HunterLab"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
@ -76,7 +76,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLuv"/> into <see cref="HunterLab"/>
/// Performs the bulk conversion from <see cref="CieLuv"/> into <see cref="HunterLab"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
@ -97,10 +97,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieXyy"/> into <see cref="HunterLab"/>
/// Performs the bulk conversion from <see cref="CieXyy"/> into <see cref="HunterLab"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
/// <param name="source">The span to the source colors.</param>
/// <param name="destination">The span to the destination colors.</param>
public void Convert(ReadOnlySpan<CieXyy> source, Span<HunterLab> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
@ -118,10 +118,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieXyz"/> into <see cref="HunterLab"/>
/// Performs the bulk conversion from <see cref="CieXyz"/> into <see cref="HunterLab"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
/// <param name="source">The span to the source colors.</param>
/// <param name="destination">The span to the destination colors.</param>
public void Convert(ReadOnlySpan<CieXyz> source, Span<HunterLab> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
@ -139,7 +139,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="Cmyk"/> into <see cref="HunterLab"/>
/// Performs the bulk conversion from <see cref="Cmyk"/> into <see cref="HunterLab"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
@ -160,10 +160,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="Hsl"/> into <see cref="HunterLab"/>
/// Performs the bulk conversion from <see cref="Hsl"/> into <see cref="HunterLab"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
/// <param name="destination">The span to the destination colors.</param>
public void Convert(ReadOnlySpan<Hsl> source, Span<HunterLab> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
@ -181,7 +181,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="Hsl"/> into <see cref="HunterLab"/>
/// Performs the bulk conversion from <see cref="Hsl"/> into <see cref="HunterLab"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
@ -223,7 +223,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="Lms"/> into <see cref="HunterLab"/>
/// Performs the bulk conversion from <see cref="Lms"/> into <see cref="HunterLab"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
@ -244,7 +244,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="Rgb"/> into <see cref="HunterLab"/>
/// Performs the bulk conversion from <see cref="Rgb"/> into <see cref="HunterLab"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
@ -265,7 +265,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="YCbCr"/> into <see cref="HunterLab"/>
/// Performs the bulk conversion from <see cref="YCbCr"/> into <see cref="HunterLab"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
@ -286,7 +286,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="CieLab"/> into a <see cref="HunterLab"/>
/// Converts a <see cref="CieLab"/> into a <see cref="HunterLab"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="HunterLab"/></returns>
@ -297,7 +297,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="CieLch"/> into a <see cref="HunterLab"/>
/// Converts a <see cref="CieLch"/> into a <see cref="HunterLab"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="HunterLab"/></returns>
@ -308,7 +308,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="CieLchuv"/> into a <see cref="HunterLab"/>
/// Converts a <see cref="CieLchuv"/> into a <see cref="HunterLab"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="HunterLab"/></returns>
@ -319,7 +319,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="CieLuv"/> into a <see cref="HunterLab"/>
/// Converts a <see cref="CieLuv"/> into a <see cref="HunterLab"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="HunterLab"/></returns>
@ -330,7 +330,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="CieXyy"/> into a <see cref="HunterLab"/>
/// Converts a <see cref="CieXyy"/> into a <see cref="HunterLab"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="HunterLab"/></returns>
@ -341,21 +341,19 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="CieXyz"/> into a <see cref="HunterLab"/>
/// Converts a <see cref="CieXyz"/> into a <see cref="HunterLab"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="HunterLab"/></returns>
public HunterLab ToHunterLab(in CieXyz color)
{
// Adaptation
CieXyz adapted = this.Adapt(color, this.whitePoint, this.targetHunterLabWhitePoint);
// Conversion
return this.cieXyzToHunterLabConverter.Convert(adapted);
}
/// <summary>
/// Converts a <see cref="Cmyk"/> into a <see cref="HunterLab"/>
/// Converts a <see cref="Cmyk"/> into a <see cref="HunterLab"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="HunterLab"/></returns>
@ -366,7 +364,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="Hsl"/> into a <see cref="HunterLab"/>
/// Converts a <see cref="Hsl"/> into a <see cref="HunterLab"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="HunterLab"/></returns>
@ -377,7 +375,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="Hsv"/> into a <see cref="HunterLab"/>
/// Converts a <see cref="Hsv"/> into a <see cref="HunterLab"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="HunterLab"/></returns>
@ -388,7 +386,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="LinearRgb"/> into a <see cref="HunterLab"/>
/// Converts a <see cref="LinearRgb"/> into a <see cref="HunterLab"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="HunterLab"/></returns>
@ -399,7 +397,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="Lms"/> into a <see cref="HunterLab"/>
/// Converts a <see cref="Lms"/> into a <see cref="HunterLab"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="HunterLab"/></returns>
@ -421,7 +419,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="YCbCr"/> into a <see cref="HunterLab"/>
/// Converts a <see cref="YCbCr"/> into a <see cref="HunterLab"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="HunterLab"/></returns>

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

@ -17,10 +17,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
private static readonly RgbToLinearRgbConverter RgbToLinearRgbConverter = new RgbToLinearRgbConverter();
/// <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>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
/// <param name="source">The span to the source colors.</param>
/// <param name="destination">The span to the destination colors.</param>
public void Convert(ReadOnlySpan<CieLab> source, Span<LinearRgb> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
@ -38,10 +38,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLch"/> into <see cref="LinearRgb"/>
/// Performs the bulk conversion from <see cref="CieLch"/> into <see cref="LinearRgb"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
/// <param name="source">The span to the source colors.</param>
/// <param name="destination">The span to the destination colors.</param>
public void Convert(ReadOnlySpan<CieLch> source, Span<LinearRgb> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
@ -59,10 +59,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLchuv"/> into <see cref="LinearRgb"/>
/// Performs the bulk conversion from <see cref="CieLchuv"/> into <see cref="LinearRgb"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
/// <param name="source">The span to the source colors.</param>
/// <param name="destination">The span to the destination colors.</param>
public void Convert(ReadOnlySpan<CieLchuv> source, Span<LinearRgb> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
@ -80,10 +80,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLuv"/> into <see cref="LinearRgb"/>
/// Performs the bulk conversion from <see cref="CieLuv"/> into <see cref="LinearRgb"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
/// <param name="source">The span to the source colors.</param>
/// <param name="destination">The span to the destination colors.</param>
public void Convert(ReadOnlySpan<CieLuv> source, Span<LinearRgb> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
@ -101,10 +101,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieXyy"/> into <see cref="LinearRgb"/>
/// Performs the bulk conversion from <see cref="CieXyy"/> into <see cref="LinearRgb"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
/// <param name="source">The span to the source colors.</param>
/// <param name="destination">The span to the destination colors.</param>
public void Convert(ReadOnlySpan<CieXyy> source, Span<LinearRgb> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
@ -122,10 +122,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieXyz"/> into <see cref="LinearRgb"/>
/// Performs the bulk conversion from <see cref="CieXyz"/> into <see cref="LinearRgb"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
/// <param name="source">The span to the source colors.</param>
/// <param name="destination">The span to the destination colors.</param>
public void Convert(ReadOnlySpan<CieXyz> source, Span<LinearRgb> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
@ -143,10 +143,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="Cmyk"/> into <see cref="LinearRgb"/>
/// Performs the bulk conversion from <see cref="Cmyk"/> into <see cref="LinearRgb"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
/// <param name="source">The span to the source colors.</param>
/// <param name="destination">The span to the destination colors.</param>
public void Convert(ReadOnlySpan<Cmyk> source, Span<LinearRgb> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
@ -164,10 +164,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="Hsl"/> into <see cref="LinearRgb"/>
/// Performs the bulk conversion from <see cref="Hsl"/> into <see cref="LinearRgb"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
/// <param name="source">The span to the source colors.</param>
/// <param name="destination">The span to the destination colors.</param>
public void Convert(ReadOnlySpan<Hsl> source, Span<LinearRgb> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
@ -185,10 +185,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="Hsv"/> into <see cref="LinearRgb"/>
/// Performs the bulk conversion from <see cref="Hsv"/> into <see cref="LinearRgb"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
/// <param name="source">The span to the source colors.</param>
/// <param name="destination">The span to the destination colors.</param>
public void Convert(ReadOnlySpan<Hsv> source, Span<LinearRgb> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
@ -206,10 +206,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="HunterLab"/> into <see cref="LinearRgb"/>
/// Performs the bulk conversion from <see cref="HunterLab"/> into <see cref="LinearRgb"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
/// <param name="source">The span to the source colors.</param>
/// <param name="destination">The span to the destination colors.</param>
public void Convert(ReadOnlySpan<HunterLab> source, Span<LinearRgb> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
@ -227,10 +227,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="Lms"/> into <see cref="LinearRgb"/>
/// Performs the bulk conversion from <see cref="Lms"/> into <see cref="LinearRgb"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
/// <param name="source">The span to the source colors.</param>
/// <param name="destination">The span to the destination colors.</param>
public void Convert(ReadOnlySpan<Lms> source, Span<LinearRgb> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
@ -248,7 +248,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="Lms"/> into <see cref="LinearRgb"/>
/// Performs the bulk conversion from <see cref="Lms"/> into <see cref="LinearRgb"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
@ -269,7 +269,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="YCbCr"/> into <see cref="LinearRgb"/>
/// Performs the bulk conversion from <see cref="YCbCr"/> into <see cref="LinearRgb"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
@ -290,7 +290,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="CieLab"/> into a <see cref="LinearRgb"/>
/// Converts a <see cref="CieLab"/> into a <see cref="LinearRgb"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="LinearRgb"/></returns>
@ -301,7 +301,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="CieLch"/> into a <see cref="LinearRgb"/>
/// Converts a <see cref="CieLch"/> into a <see cref="LinearRgb"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="LinearRgb"/></returns>
@ -312,7 +312,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="CieLchuv"/> into a <see cref="LinearRgb"/>
/// Converts a <see cref="CieLchuv"/> into a <see cref="LinearRgb"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="LinearRgb"/></returns>
@ -323,7 +323,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="CieLuv"/> into a <see cref="LinearRgb"/>
/// Converts a <see cref="CieLuv"/> into a <see cref="LinearRgb"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="LinearRgb"/></returns>
@ -345,7 +345,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="CieXyz"/> into a <see cref="LinearRgb"/>
/// Converts a <see cref="CieXyz"/> into a <see cref="LinearRgb"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="LinearRgb"/></returns>
@ -359,7 +359,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="Cmyk"/> into a <see cref="LinearRgb"/>
/// Converts a <see cref="Cmyk"/> into a <see cref="LinearRgb"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="LinearRgb"/></returns>
@ -370,7 +370,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="Hsl"/> into a <see cref="LinearRgb"/>
/// Converts a <see cref="Hsl"/> into a <see cref="LinearRgb"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="LinearRgb"/></returns>
@ -381,7 +381,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="Hsv"/> into a <see cref="LinearRgb"/>
/// Converts a <see cref="Hsv"/> into a <see cref="LinearRgb"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="LinearRgb"/></returns>
@ -392,7 +392,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="HunterLab"/> into a <see cref="LinearRgb"/>
/// Converts a <see cref="HunterLab"/> into a <see cref="LinearRgb"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="LinearRgb"/></returns>
@ -403,7 +403,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="Lms"/> into a <see cref="LinearRgb"/>
/// Converts a <see cref="Lms"/> into a <see cref="LinearRgb"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="LinearRgb"/></returns>
@ -425,7 +425,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="YCbCr"/> into a <see cref="LinearRgb"/>
/// Converts a <see cref="YCbCr"/> into a <see cref="LinearRgb"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="LinearRgb"/></returns>

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

@ -17,10 +17,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
private static readonly YCbCrAndRgbConverter YCbCrAndRgbConverter = new YCbCrAndRgbConverter();
/// <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>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
/// <param name="source">The span to the source colors.</param>
/// <param name="destination">The span to the destination colors.</param>
public void Convert(ReadOnlySpan<CieLab> source, Span<YCbCr> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
@ -38,10 +38,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLch"/> into <see cref="YCbCr"/>
/// Performs the bulk conversion from <see cref="CieLch"/> into <see cref="YCbCr"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
/// <param name="source">The span to the source colors.</param>
/// <param name="destination">The span to the destination colors.</param>
public void Convert(ReadOnlySpan<CieLch> source, Span<YCbCr> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
@ -59,7 +59,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLuv"/> into <see cref="YCbCr"/>
/// Performs the bulk conversion from <see cref="CieLuv"/> into <see cref="YCbCr"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
@ -101,7 +101,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieXyz"/> into <see cref="YCbCr"/>
/// Performs the bulk conversion from <see cref="CieXyz"/> into <see cref="YCbCr"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
@ -122,7 +122,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="Cmyk"/> into <see cref="YCbCr"/>
/// Performs the bulk conversion from <see cref="Cmyk"/> into <see cref="YCbCr"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
@ -143,7 +143,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="Hsl"/> into <see cref="YCbCr"/>
/// Performs the bulk conversion from <see cref="Hsl"/> into <see cref="YCbCr"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
@ -164,7 +164,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="Hsv"/> into <see cref="YCbCr"/>
/// Performs the bulk conversion from <see cref="Hsv"/> into <see cref="YCbCr"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
@ -185,7 +185,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="HunterLab"/> into <see cref="YCbCr"/>
/// Performs the bulk conversion from <see cref="HunterLab"/> into <see cref="YCbCr"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
@ -206,7 +206,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="LinearRgb"/> into <see cref="YCbCr"/>
/// Performs the bulk conversion from <see cref="LinearRgb"/> into <see cref="YCbCr"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
@ -227,7 +227,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="Lms"/> into <see cref="YCbCr"/>
/// Performs the bulk conversion from <see cref="Lms"/> into <see cref="YCbCr"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
@ -248,7 +248,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Performs the bulk conversion from <see cref="Rgb"/> into <see cref="YCbCr"/>
/// Performs the bulk conversion from <see cref="Rgb"/> into <see cref="YCbCr"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
@ -269,7 +269,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="CieLab"/> into a <see cref="YCbCr"/>
/// Converts a <see cref="CieLab"/> into a <see cref="YCbCr"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="YCbCr"/></returns>
@ -281,7 +281,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="CieLch"/> into a <see cref="YCbCr"/>
/// Converts a <see cref="CieLch"/> into a <see cref="YCbCr"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="YCbCr"/></returns>
@ -293,7 +293,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="CieLuv"/> into a <see cref="YCbCr"/>
/// Converts a <see cref="CieLuv"/> into a <see cref="YCbCr"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="YCbCr"/></returns>
@ -305,7 +305,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="CieXyy"/> into a <see cref="YCbCr"/>
/// Converts a <see cref="CieXyy"/> into a <see cref="YCbCr"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="YCbCr"/></returns>
@ -317,7 +317,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="CieXyz"/> into a <see cref="YCbCr"/>
/// Converts a <see cref="CieXyz"/> into a <see cref="YCbCr"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="YCbCr"/></returns>
@ -329,7 +329,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="Cmyk"/> into a <see cref="YCbCr"/>
/// Converts a <see cref="Cmyk"/> into a <see cref="YCbCr"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="YCbCr"/></returns>
@ -341,7 +341,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="Hsl"/> into a <see cref="YCbCr"/>
/// Converts a <see cref="Hsl"/> into a <see cref="YCbCr"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="YCbCr"/></returns>
@ -353,7 +353,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="Hsv"/> into a <see cref="YCbCr"/>
/// Converts a <see cref="Hsv"/> into a <see cref="YCbCr"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="YCbCr"/></returns>
@ -365,7 +365,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="HunterLab"/> into a <see cref="YCbCr"/>
/// Converts a <see cref="HunterLab"/> into a <see cref="YCbCr"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="YCbCr"/></returns>
@ -377,7 +377,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="LinearRgb"/> into a <see cref="YCbCr"/>
/// Converts a <see cref="LinearRgb"/> into a <see cref="YCbCr"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="YCbCr"/></returns>
@ -389,7 +389,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="Lms"/> into a <see cref="YCbCr"/>
/// Converts a <see cref="Lms"/> into a <see cref="YCbCr"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="YCbCr"/></returns>
@ -401,7 +401,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Converts a <see cref="Rgb"/> into a <see cref="YCbCr"/>
/// Converts a <see cref="Rgb"/> into a <see cref="YCbCr"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="YCbCr"/></returns>

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

@ -22,7 +22,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation
// Conversion algorithm described here:
// https://en.wikipedia.org/wiki/Lab_color_space#Cylindrical_representation:_CIELCh_or_CIEHLC
float l = input.L, c = input.C, hDegrees = input.H;
float hRadians = MathFExtensions.DegreeToRadian(hDegrees);
float hRadians = GeometryUtilities.DegreeToRadian(hDegrees);
float a = c * MathF.Cos(hRadians);
float b = c * MathF.Sin(hRadians);

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

@ -24,7 +24,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation
float l = input.L, a = input.A, b = input.B;
float c = MathF.Sqrt((a * a) + (b * b));
float hRadians = MathF.Atan2(b, a);
float hDegrees = MathFExtensions.RadianToDegree(hRadians);
float hDegrees = GeometryUtilities.RadianToDegree(hRadians);
// Wrap the angle round at 360.
hDegrees %= 360;

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

@ -22,7 +22,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation
// Conversion algorithm described here:
// https://en.wikipedia.org/wiki/CIELUV#Cylindrical_representation_.28CIELCH.29
float l = input.L, c = input.C, hDegrees = input.H;
float hRadians = MathFExtensions.DegreeToRadian(hDegrees);
float hRadians = GeometryUtilities.DegreeToRadian(hDegrees);
float u = c * MathF.Cos(hRadians);
float v = c * MathF.Sin(hRadians);

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

@ -24,7 +24,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation
float l = input.L, a = input.U, b = input.V;
float c = MathF.Sqrt((a * a) + (b * b));
float hRadians = MathF.Atan2(b, a);
float hDegrees = MathFExtensions.RadianToDegree(hRadians);
float hDegrees = GeometryUtilities.RadianToDegree(hRadians);
// Wrap the angle round at 360.
hDegrees %= 360;

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

@ -7,7 +7,7 @@ using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation
{
/// <summary>
/// Color converter between CIE XYZ and CIE xyY
/// Color converter between CIE XYZ and CIE xyY.
/// <see href="http://www.brucelindbloom.com/"/> for formulas.
/// </summary>
internal sealed class CieXyzAndCieXyyConverter

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

@ -45,9 +45,11 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation
float ka = ComputeKa(this.HunterLabWhitePoint);
float kb = ComputeKb(this.HunterLabWhitePoint);
float l = 100 * MathF.Sqrt(y / yn);
float a = ka * (((x / xn) - (y / yn)) / MathF.Sqrt(y / yn));
float b = kb * (((y / yn) - (z / zn)) / MathF.Sqrt(y / yn));
float yByYn = y / yn;
float sqrtYbyYn = MathF.Sqrt(yByYn);
float l = 100 * sqrtYbyYn;
float a = ka * (((x / xn) - yByYn) / sqrtYbyYn);
float b = kb * ((yByYn - (z / zn)) / sqrtYbyYn);
if (float.IsNaN(a))
{

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

@ -28,11 +28,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation
public CieXyzToLinearRgbConverter(RgbWorkingSpaceBase workingSpace)
{
this.TargetWorkingSpace = workingSpace;
this.conversionMatrix = GetRgbToCieXyzMatrix(workingSpace);
// Gets the inverted Rgb -> Xyz matrix
Matrix4x4.Invert(GetRgbToCieXyzMatrix(workingSpace), out Matrix4x4 inverted);
this.conversionMatrix = inverted;
}
/// <summary>
/// Gets the target working space
/// Gets the target working space.
/// </summary>
public RgbWorkingSpaceBase TargetWorkingSpace { get; }
@ -40,12 +44,12 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation
/// Performs the conversion from the <see cref="CieXyz"/> input to an instance of <see cref="LinearRgb"/> type.
/// </summary>
/// <param name="input">The input color instance.</param>
/// <returns>The converted result</returns>
/// <returns>The converted result.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public LinearRgb Convert(in CieXyz input)
{
Matrix4x4.Invert(this.conversionMatrix, out Matrix4x4 inverted);
var vector = Vector3.Transform(input.ToVector3(), inverted);
var vector = Vector3.Transform(input.ToVector3(), this.conversionMatrix);
return new LinearRgb(vector, this.TargetWorkingSpace);
}
}

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

@ -8,7 +8,7 @@ using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation
{
/// <summary>
/// Color converter between <see cref="Cmyk"/> and <see cref="Rgb"/>
/// Color converter between <see cref="Cmyk"/> and <see cref="Rgb"/>.
/// </summary>
internal sealed class CmykAndRgbConverter
{
@ -28,7 +28,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation
/// Performs the conversion from the <see cref="Rgb"/> input to an instance of <see cref="Cmyk"/> type.
/// </summary>
/// <param name="input">The input color instance.</param>
/// <returns>The converted result</returns>
/// <returns>The converted result.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public Cmyk Convert(in Rgb input)
{

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

@ -26,9 +26,12 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation
float ka = ComputeKa(input.WhitePoint);
float kb = ComputeKb(input.WhitePoint);
float y = ImageMaths.Pow2(l / 100F) * yn;
float x = (((a / ka) * MathF.Sqrt(y / yn)) + (y / yn)) * xn;
float z = (((b / kb) * MathF.Sqrt(y / yn)) - (y / yn)) * (-zn);
float pow = ImageMaths.Pow2(l / 100F);
float sqrtPow = MathF.Sqrt(pow);
float y = pow * yn;
float x = (((a / ka) * sqrtPow) + pow) * xn;
float z = (((b / kb) * sqrtPow) - pow) * (-zn);
return new CieXyz(x, y, z);
}

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

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

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

@ -6,7 +6,7 @@ using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation
{
/// <summary>
/// Color converter between Rgb and LinearRgb
/// Color converter between Rgb and LinearRgb.
/// </summary>
internal class RgbToLinearRgbConverter
{
@ -14,16 +14,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation
/// Performs the conversion from the <see cref="Rgb"/> input to an instance of <see cref="LinearRgb"/> type.
/// </summary>
/// <param name="input">The input color instance.</param>
/// <returns>The converted result</returns>
/// <returns>The converted result.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public LinearRgb Convert(in Rgb input)
{
var vector = input.ToVector3();
vector.X = input.WorkingSpace.Expand(vector.X);
vector.Y = input.WorkingSpace.Expand(vector.Y);
vector.Z = input.WorkingSpace.Expand(vector.Z);
return new LinearRgb(vector, input.WorkingSpace);
return new LinearRgb(
r: input.WorkingSpace.Expand(input.R),
g: input.WorkingSpace.Expand(input.G),
b: input.WorkingSpace.Expand(input.B),
workingSpace: input.WorkingSpace);
}
}
}

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

@ -19,7 +19,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation
/// Performs the conversion from the <see cref="YCbCr"/> input to an instance of <see cref="Rgb"/> type.
/// </summary>
/// <param name="input">The input color instance.</param>
/// <returns>The converted result</returns>
/// <returns>The converted result.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public Rgb Convert(in YCbCr input)
{
@ -38,7 +38,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation
/// Performs the conversion from the <see cref="Rgb"/> input to an instance of <see cref="YCbCr"/> type.
/// </summary>
/// <param name="input">The input color instance.</param>
/// <returns>The converted result</returns>
/// <returns>The converted result.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public YCbCr Convert(in Rgb input)
{

10
src/ImageSharp/ColorSpaces/Conversion/Implementation/RGBPrimariesChromaticityCoordinates.cs

@ -86,14 +86,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation
}
/// <inheritdoc />
public override int GetHashCode()
{
unchecked
{
int hashCode = this.R.GetHashCode();
hashCode = (hashCode * 397) ^ this.G.GetHashCode();
return (hashCode * 397) ^ this.B.GetHashCode();
}
}
public override int GetHashCode() => HashCode.Combine(this.R, this.G, this.B);
}
}

12
src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/GammaWorkingSpace.cs

@ -1,6 +1,7 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.ColorSpaces.Companding;
@ -9,7 +10,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation
/// <summary>
/// The gamma working space.
/// </summary>
public class GammaWorkingSpace : RgbWorkingSpaceBase
public sealed class GammaWorkingSpace : RgbWorkingSpaceBase
{
/// <summary>
/// Initializes a new instance of the <see cref="GammaWorkingSpace" /> class.
@ -57,10 +58,9 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation
}
/// <inheritdoc/>
public override int GetHashCode()
{
int hash = base.GetHashCode();
return HashHelpers.Combine(hash, this.Gamma.GetHashCode());
}
public override int GetHashCode() => HashCode.Combine(
this.WhitePoint,
this.ChromaticityCoordinates,
this.Gamma);
}
}

5
src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/RgbWorkingSpaceBase.cs

@ -1,6 +1,8 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation
{
/// <summary>
@ -76,8 +78,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation
/// <inheritdoc/>
public override int GetHashCode()
{
int hash = this.WhitePoint.GetHashCode();
return HashHelpers.Combine(hash, this.ChromaticityCoordinates.GetHashCode());
return HashCode.Combine(this.WhitePoint, this.ChromaticityCoordinates);
}
}
}

4
src/ImageSharp/ColorSpaces/Conversion/VonKriesChromaticAdaptation.cs

@ -10,13 +10,13 @@ using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion
{
/// <summary>
/// Basic implementation of the von Kries chromatic adaptation model
/// Implementation of the von Kries chromatic adaptation model.
/// </summary>
/// <remarks>
/// Transformation described here:
/// http://www.brucelindbloom.com/index.html?Eqn_ChromAdapt.html
/// </remarks>
public class VonKriesChromaticAdaptation : IChromaticAdaptation
public sealed class VonKriesChromaticAdaptation : IChromaticAdaptation
{
private readonly CieXyzAndLmsConverter converter;

7
src/ImageSharp/ColorSpaces/Hsl.cs

@ -84,12 +84,7 @@ namespace SixLabors.ImageSharp.ColorSpaces
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public override int GetHashCode()
{
int hash = this.H.GetHashCode();
hash = HashHelpers.Combine(hash, this.S.GetHashCode());
return HashHelpers.Combine(hash, this.L.GetHashCode());
}
public override int GetHashCode() => HashCode.Combine(this.H, this.S, this.L);
/// <inheritdoc/>
public override string ToString() => FormattableString.Invariant($"Hsl({this.H:#0.##}, {this.S:#0.##}, {this.L:#0.##})");

7
src/ImageSharp/ColorSpaces/Hsv.cs

@ -82,12 +82,7 @@ namespace SixLabors.ImageSharp.ColorSpaces
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public override int GetHashCode()
{
int hash = this.H.GetHashCode();
hash = HashHelpers.Combine(hash, this.S.GetHashCode());
return HashHelpers.Combine(hash, this.V.GetHashCode());
}
public override int GetHashCode() => HashCode.Combine(this.H, this.S, this.V);
/// <inheritdoc/>
public override string ToString() => FormattableString.Invariant($"Hsv({this.H:#0.##}, {this.S:#0.##}, {this.V:#0.##})");

12
src/ImageSharp/ColorSpaces/HunterLab.cs

@ -9,7 +9,7 @@ namespace SixLabors.ImageSharp.ColorSpaces
{
/// <summary>
/// Represents an Hunter LAB color.
/// <see href="https://en.wikipedia.org/wiki/Lab_color_space"/>
/// <see href="https://en.wikipedia.org/wiki/Lab_color_space"/>.
/// </summary>
public readonly struct HunterLab : IEquatable<HunterLab>
{
@ -38,7 +38,7 @@ namespace SixLabors.ImageSharp.ColorSpaces
public readonly float B;
/// <summary>
/// Gets the reference white point of this color
/// Gets the reference white point of this color.
/// </summary>
public readonly CieXyz WhitePoint;
@ -117,13 +117,7 @@ namespace SixLabors.ImageSharp.ColorSpaces
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public override int GetHashCode()
{
int hash = this.L.GetHashCode();
hash = HashHelpers.Combine(hash, this.A.GetHashCode());
hash = HashHelpers.Combine(hash, this.B.GetHashCode());
return HashHelpers.Combine(hash, this.WhitePoint.GetHashCode());
}
public override int GetHashCode() => HashCode.Combine(this.L, this.A, this.B, this.WhitePoint);
/// <inheritdoc/>
public override string ToString() => FormattableString.Invariant($"HunterLab({this.L:#0.##}, {this.A:#0.##}, {this.B:#0.##})");

6
src/ImageSharp/ColorSpaces/Illuminants.cs

@ -8,11 +8,9 @@ namespace SixLabors.ImageSharp.ColorSpaces
/// Standard illuminants provide a basis for comparing images or colors recorded under different lighting
/// </summary>
/// <remarks>
/// Coefficients taken from:
/// http://www.brucelindbloom.com/index.html?Eqn_ChromAdapt.html
/// Coefficients taken from: http://www.brucelindbloom.com/index.html?Eqn_ChromAdapt.html
/// <br />
/// Descriptions taken from:
/// http://en.wikipedia.org/wiki/Standard_illuminant
/// Descriptions taken from: http://en.wikipedia.org/wiki/Standard_illuminant
/// </remarks>
public static class Illuminants
{

7
src/ImageSharp/ColorSpaces/LinearRgb.cs

@ -126,12 +126,7 @@ namespace SixLabors.ImageSharp.ColorSpaces
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public override int GetHashCode()
{
int hash = this.R.GetHashCode();
hash = HashHelpers.Combine(hash, this.G.GetHashCode());
return HashHelpers.Combine(hash, this.B.GetHashCode());
}
public override int GetHashCode() => HashCode.Combine(this.R, this.G, this.B);
/// <inheritdoc/>
public override string ToString() => FormattableString.Invariant($"LinearRgb({this.R:#0.##}, {this.G:#0.##}, {this.B:#0.##})");

7
src/ImageSharp/ColorSpaces/Lms.cs

@ -87,12 +87,7 @@ namespace SixLabors.ImageSharp.ColorSpaces
public Vector3 ToVector3() => new Vector3(this.L, this.M, this.S);
/// <inheritdoc/>
public override int GetHashCode()
{
int hash = this.L.GetHashCode();
hash = HashHelpers.Combine(hash, this.M.GetHashCode());
return HashHelpers.Combine(hash, this.S.GetHashCode());
}
public override int GetHashCode() => HashCode.Combine(this.L, this.M, this.S);
/// <inheritdoc/>
public override string ToString() => FormattableString.Invariant($"Lms({this.L:#0.##}, {this.M:#0.##}, {this.S:#0.##})");

15
src/ImageSharp/ColorSpaces/Rgb.cs

@ -14,14 +14,14 @@ namespace SixLabors.ImageSharp.ColorSpaces
/// </summary>
public readonly struct Rgb : IEquatable<Rgb>
{
private static readonly Vector3 Min = Vector3.Zero;
private static readonly Vector3 Max = Vector3.One;
/// <summary>
/// The default rgb working space
/// The default rgb working space.
/// </summary>
public static readonly RgbWorkingSpaceBase DefaultWorkingSpace = RgbWorkingSpaces.SRgb;
private static readonly Vector3 Min = Vector3.Zero;
private static readonly Vector3 Max = Vector3.One;
/// <summary>
/// Gets the red component.
/// <remarks>A value usually ranging between 0 and 1.</remarks>
@ -147,12 +147,7 @@ namespace SixLabors.ImageSharp.ColorSpaces
public Vector3 ToVector3() => new Vector3(this.R, this.G, this.B);
/// <inheritdoc/>
public override int GetHashCode()
{
int hash = this.R.GetHashCode();
hash = HashHelpers.Combine(hash, this.G.GetHashCode());
return HashHelpers.Combine(hash, this.B.GetHashCode());
}
public override int GetHashCode() => HashCode.Combine(this.R, this.G, this.B);
/// <inheritdoc/>
public override string ToString() => FormattableString.Invariant($"Rgb({this.R:#0.##}, {this.G:#0.##}, {this.B:#0.##})");

3
src/ImageSharp/ColorSpaces/RgbWorkingSpaces.cs

@ -8,8 +8,7 @@ using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation;
namespace SixLabors.ImageSharp.ColorSpaces
{
/// <summary>
/// Chromaticity coordinates taken from:
/// <see href="http://www.brucelindbloom.com/index.html?WorkingSpaceInfo.html"/>
/// Chromaticity coordinates based on: <see href="http://www.brucelindbloom.com/index.html?WorkingSpaceInfo.html"/>
/// </summary>
public static class RgbWorkingSpaces
{

7
src/ImageSharp/ColorSpaces/YCbCr.cs

@ -83,12 +83,7 @@ namespace SixLabors.ImageSharp.ColorSpaces
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public override int GetHashCode()
{
int hash = this.Y.GetHashCode();
hash = HashHelpers.Combine(hash, this.Cb.GetHashCode());
return HashHelpers.Combine(hash, this.Cr.GetHashCode());
}
public override int GetHashCode() => HashCode.Combine(this.Y, this.Cb, this.Cr);
/// <inheritdoc/>
public override string ToString() => FormattableString.Invariant($"YCbCr({this.Y}, {this.Cb}, {this.Cr})");

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

@ -20,6 +20,11 @@ namespace SixLabors.ImageSharp
/// <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);

4
src/ImageSharp/Common/Extensions/EnumerableExtensions.cs

@ -45,7 +45,7 @@ namespace SixLabors.ImageSharp.Common
/// The start index, inclusive.
/// </param>
/// <param name="toDelegate">
/// A method that has one parameter and returns a <see cref="bool"/> calculating the end index
/// A method that has one parameter and returns a <see cref="bool"/> calculating the end index.
/// </param>
/// <param name="step">
/// The incremental step.
@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Common
/// The start index, inclusive.
/// </param>
/// <param name="toDelegate">
/// A method that has one parameter and returns a <see cref="bool"/> calculating the end index
/// A method that has one parameter and returns a <see cref="bool"/> calculating the end index.
/// </param>
/// <param name="step">
/// The incremental step.

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

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0.
using System;
using System.Buffers;
using System.IO;
using SixLabors.ImageSharp.Memory;
@ -82,5 +83,25 @@ namespace SixLabors.ImageSharp
{
stream.Write(buffer.Array, 0, buffer.Length());
}
#if NET472 || NETSTANDARD1_3 || NETSTANDARD2_0
// This is a port of the CoreFX implementation and is MIT Licensed: https://github.com/dotnet/coreclr/blob/c4dca1072d15bdda64c754ad1ea474b1580fa554/src/System.Private.CoreLib/shared/System/IO/Stream.cs#L770
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
}
}

14
src/ImageSharp/Common/Helpers/DebugGuard.cs

@ -163,6 +163,20 @@ namespace SixLabors.ImageSharp
}
}
/// <summary>
/// Verifies whether a specific condition is met, throwing an exception if it's false.
/// </summary>
/// <param name="target">The condition</param>
/// <param name="message">The error message</param>
[Conditional("DEBUG")]
public static void IsTrue(bool target, string message)
{
if (!target)
{
throw new InvalidOperationException(message);
}
}
/// <summary>
/// Verifies, that the method parameter with specified target value is false
/// and throws an exception if it is found to be so.

20
src/ImageSharp/Common/Helpers/Guard.cs

@ -257,6 +257,26 @@ namespace SixLabors.ImageSharp
}
}
/// <summary>
/// Verifies that the 'destination' span is not shorter than 'source'.
/// </summary>
/// <typeparam name="TSource">The source element type</typeparam>
/// <typeparam name="TDest">The destination element type</typeparam>
/// <param name="source">The source span</param>
/// <param name="destination">The destination span</param>
/// <param name="destinationParamName">The name of the argument for 'destination'</param>
[MethodImpl(InliningOptions.ShortMethod)]
public static void DestinationShouldNotBeTooShort<TSource, TDest>(
Span<TSource> source,
Span<TDest> destination,
string destinationParamName)
{
if (destination.Length < source.Length)
{
ThrowArgumentException($"Destination span is too short!", destinationParamName);
}
}
/// <summary>
/// Verifies, that the `source` span has the length of 'minLength', or longer.
/// </summary>

15
src/ImageSharp/Common/Helpers/ImageMaths.cs

@ -5,6 +5,7 @@ using System;
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Processors.Transforms;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp
@ -22,7 +23,8 @@ namespace SixLabors.ImageSharp
/// <param name="b">The blue component.</param>
/// <returns>The <see cref="byte"/>.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static byte Get8BitBT709Luminance(byte r, byte g, byte b) => (byte)((r * .2126F) + (g * .7152F) + (b * .0722F));
public static byte Get8BitBT709Luminance(byte r, byte g, byte b) =>
(byte)((r * .2126F) + (g * .7152F) + (b * .0722F) + 0.5f);
/// <summary>
/// Gets the luminance from the rgb components using the formula as specified by ITU-R Recommendation BT.709.
@ -32,7 +34,8 @@ namespace SixLabors.ImageSharp
/// <param name="b">The blue component.</param>
/// <returns>The <see cref="ushort"/>.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static ushort Get16BitBT709Luminance(ushort r, ushort g, ushort b) => (ushort)((r * .2126F) + (g * .7152F) + (b * .0722F));
public static ushort Get16BitBT709Luminance(ushort r, ushort g, ushort b) =>
(ushort)((r * .2126F) + (g * .7152F) + (b * .0722F));
/// <summary>
/// Scales a value from a 16 bit <see cref="ushort"/> to it's 8 bit <see cref="byte"/> equivalent.
@ -76,7 +79,7 @@ namespace SixLabors.ImageSharp
/// <summary>
/// Scales a value from an 8 bit <see cref="byte"/> to it's 16 bit <see cref="ushort"/> equivalent.
/// </summary>
/// <param name="component">The 8 bit compoonent value.</param>
/// <param name="component">The 8 bit component value.</param>
/// <returns>The <see cref="ushort"/></returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static ushort UpscaleFrom8BitTo16Bit(byte component) => (ushort)(component * 257);
@ -98,7 +101,6 @@ namespace SixLabors.ImageSharp
/// <summary>
/// Determine the Least Common Multiple (LCM) of two numbers.
/// TODO: This method might be useful for building a more compact <see cref="Processing.Processors.Transforms.KernelMap"/>
/// </summary>
public static int LeastCommonMultiple(int a, int b)
{
@ -123,10 +125,7 @@ namespace SixLabors.ImageSharp
/// <paramref name="m"/> should be power of 2.
/// </summary>
[MethodImpl(InliningOptions.ShortMethod)]
public static int ModuloP2(int x, int m)
{
return x & (m - 1);
}
public static int ModuloP2(int x, int m) => x & (m - 1);
/// <summary>
/// Returns the absolute value of a 32-bit signed integer. Uses bit shifting to speed up the operation.

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

@ -1,7 +1,7 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
// Uncomment this for verbose profiler results:
// Uncomment this for verbose profiler results. DO NOT PUSH TO MAIN!
// #define PROFILING
using System.Runtime.CompilerServices;

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

@ -90,7 +90,7 @@ namespace SixLabors.ImageSharp
var bVec = new Vector<float>(256.0f / 255.0f);
var magicFloat = new Vector<float>(32768.0f);
var magicInt = new Vector<uint>(1191182336); // reinterpreded value of 32768.0f
var magicInt = new Vector<uint>(1191182336); // reinterpreted value of 32768.0f
var mask = new Vector<uint>(255);
ref Octet.OfByte sourceBase = ref Unsafe.As<byte, Octet.OfByte>(ref MemoryMarshal.GetReference(source));

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

@ -1,4 +1,7 @@
using System;
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
@ -25,6 +28,20 @@ namespace SixLabors.ImageSharp
false;
#endif
/// <summary>
/// Widen and convert a vector of <see cref="short"/> values into 2 vectors of <see cref="float"/>-s.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static void ConvertToSingle(
Vector<short> source,
out Vector<float> dest1,
out Vector<float> dest2)
{
Vector.Widen(source, out Vector<int> i1, out Vector<int> i2);
dest1 = Vector.ConvertToSingle(i1);
dest2 = Vector.ConvertToSingle(i2);
}
/// <summary>
/// <see cref="BulkConvertByteToNormalizedFloat"/> as many elements as possible, slicing them down (keeping the remainder).
/// </summary>

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

@ -169,7 +169,7 @@ namespace SixLabors.ImageSharp
DebugGuard.IsTrue(
ImageMaths.ModuloP2(dest.Length, shouldBeDivisibleBy) == 0,
nameof(source),
$"length should be divisable by {shouldBeDivisibleBy}!");
$"length should be divisible by {shouldBeDivisibleBy}!");
}
[Conditional("DEBUG")]
@ -179,7 +179,7 @@ namespace SixLabors.ImageSharp
DebugGuard.IsTrue(
ImageMaths.ModuloP2(dest.Length, shouldBeDivisibleBy) == 0,
nameof(source),
$"length should be divisable by {shouldBeDivisibleBy}!");
$"length should be divisible by {shouldBeDivisibleBy}!");
}
}
}

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

@ -1,4 +1,4 @@
// Copyright(c) Six Labors and contributors.
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
namespace SixLabors.ImageSharp.Common.Helpers

106
src/ImageSharp/Common/Helpers/TolerantMath.cs

@ -0,0 +1,106 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp
{
/// <summary>
/// Implements basic math operations using tolerant comparison
/// whenever an equality check is needed.
/// </summary>
internal readonly struct TolerantMath
{
private readonly double epsilon;
private readonly double negEpsilon;
/// <summary>
/// A read-only default instance for <see cref="TolerantMath"/> using 1e-8 as epsilon.
/// It is a field so it can be passed as an 'in' parameter.
/// Does not necessarily fit all use cases!
/// </summary>
public static readonly TolerantMath Default = new TolerantMath(1e-8);
public TolerantMath(double epsilon)
{
DebugGuard.MustBeGreaterThan(epsilon, 0, nameof(epsilon));
this.epsilon = epsilon;
this.negEpsilon = -epsilon;
}
/// <summary>
/// <paramref name="a"/> == 0
/// </summary>
[MethodImpl(InliningOptions.ShortMethod)]
public bool IsZero(double a) => a > this.negEpsilon && a < this.epsilon;
/// <summary>
/// <paramref name="a"/> &gt; 0
/// </summary>
[MethodImpl(InliningOptions.ShortMethod)]
public bool IsPositive(double a) => a > this.epsilon;
/// <summary>
/// <paramref name="a"/> &lt; 0
/// </summary>
[MethodImpl(InliningOptions.ShortMethod)]
public bool IsNegative(double a) => a < this.negEpsilon;
/// <summary>
/// <paramref name="a"/> == <paramref name="b"/>
/// </summary>
[MethodImpl(InliningOptions.ShortMethod)]
public bool AreEqual(double a, double b) => this.IsZero(a - b);
/// <summary>
/// <paramref name="a"/> &gt; <paramref name="b"/>
/// </summary>
[MethodImpl(InliningOptions.ShortMethod)]
public bool IsGreater(double a, double b) => a > b + this.epsilon;
/// <summary>
/// <paramref name="a"/> &lt; <paramref name="b"/>
/// </summary>
[MethodImpl(InliningOptions.ShortMethod)]
public bool IsLess(double a, double b) => a < b - this.epsilon;
/// <summary>
/// <paramref name="a"/> &gt;= <paramref name="b"/>
/// </summary>
[MethodImpl(InliningOptions.ShortMethod)]
public bool IsGreaterOrEqual(double a, double b) => a >= b - this.epsilon;
/// <summary>
/// <paramref name="a"/> &lt;= <paramref name="b"/>
/// </summary>
[MethodImpl(InliningOptions.ShortMethod)]
public bool IsLessOrEqual(double a, double b) => b >= a - this.epsilon;
[MethodImpl(InliningOptions.ShortMethod)]
public double Ceiling(double a)
{
double rem = Math.IEEERemainder(a, 1);
if (this.IsZero(rem))
{
return Math.Round(a);
}
return Math.Ceiling(a);
}
[MethodImpl(InliningOptions.ShortMethod)]
public double Floor(double a)
{
double rem = Math.IEEERemainder(a, 1);
if (this.IsZero(rem))
{
return Math.Round(a);
}
return Math.Floor(a);
}
}
}

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

@ -2,8 +2,8 @@
// Licensed under the Apache License, Version 2.0.
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.MetaData;
using SixLabors.ImageSharp.MetaData.Profiles.Exif;
using SixLabors.ImageSharp.Metadata;
using SixLabors.ImageSharp.Metadata.Profiles.Exif;
namespace SixLabors.ImageSharp.Common.Helpers
{

37
src/ImageSharp/Common/Helpers/Vector4Utils.cs

@ -5,6 +5,7 @@ using System;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Primitives;
namespace SixLabors.ImageSharp
{
@ -70,5 +71,41 @@ namespace SixLabors.ImageSharp
UnPremultiply(ref v);
}
}
/// <summary>
/// Transforms a vector by the given matrix.
/// </summary>
/// <param name="vector">The source vector.</param>
/// <param name="matrix">The transformation matrix.</param>
[MethodImpl(InliningOptions.ShortMethod)]
public static void Transform(ref Vector4 vector, ref ColorMatrix matrix)
{
float x = vector.X;
float y = vector.Y;
float z = vector.Z;
float w = vector.W;
vector.X = (x * matrix.M11) + (y * matrix.M21) + (z * matrix.M31) + (w * matrix.M41) + matrix.M51;
vector.Y = (x * matrix.M12) + (y * matrix.M22) + (z * matrix.M32) + (w * matrix.M42) + matrix.M52;
vector.Z = (x * matrix.M13) + (y * matrix.M23) + (z * matrix.M33) + (w * matrix.M43) + matrix.M53;
vector.W = (x * matrix.M14) + (y * matrix.M24) + (z * matrix.M34) + (w * matrix.M44) + matrix.M54;
}
/// <summary>
/// Bulk variant of <see cref="Transform(ref Vector4, ref ColorMatrix)"/>
/// </summary>
/// <param name="vectors">The span of vectors</param>
/// <param name="matrix">The transformation matrix.</param>
[MethodImpl(InliningOptions.ShortMethod)]
public static void Transform(Span<Vector4> vectors, ref ColorMatrix matrix)
{
ref Vector4 baseRef = ref MemoryMarshal.GetReference(vectors);
for (int i = 0; i < vectors.Length; i++)
{
ref Vector4 v = ref Unsafe.Add(ref baseRef, i);
Transform(ref v, ref matrix);
}
}
}
}

2
src/ImageSharp/Common/ParallelUtils/ParallelExecutionSettings.cs

@ -1,4 +1,4 @@
// Copyright(c) Six Labors and contributors.
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System.Threading.Tasks;

6
src/ImageSharp/Common/ParallelUtils/ParallelHelper.cs

@ -1,4 +1,4 @@
// Copyright(c) Six Labors and contributors.
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
@ -85,7 +85,7 @@ namespace SixLabors.ImageSharp.ParallelUtils
Rectangle rectangle,
in ParallelExecutionSettings parallelSettings,
Action<RowInterval, Memory<T>> body)
where T : struct
where T : unmanaged
{
int maxSteps = DivideCeil(rectangle.Width * rectangle.Height, parallelSettings.MinimumPixelsProcessedPerTask);
@ -135,7 +135,7 @@ namespace SixLabors.ImageSharp.ParallelUtils
Rectangle rectangle,
Configuration configuration,
Action<RowInterval, Memory<T>> body)
where T : struct
where T : unmanaged
{
IterateRowsWithTempBuffer(rectangle, configuration.GetParallelSettings(), body);
}

7
src/ImageSharp/Common/Tuples/Octet.cs

@ -1,4 +1,7 @@
using System.Runtime.CompilerServices;
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.Tuples
@ -9,7 +12,7 @@ namespace SixLabors.ImageSharp.Tuples
internal static class Octet
{
/// <summary>
/// Value tuple of <see cref="uint"/>-s
/// Value tuple of <see cref="uint"/>-s.
/// </summary>
[StructLayout(LayoutKind.Explicit, Size = 8 * sizeof(uint))]
public struct OfUInt32

22
src/ImageSharp/Common/Tuples/Vector4Pair.cs

@ -1,4 +1,7 @@
using System.Numerics;
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
@ -37,12 +40,11 @@ namespace SixLabors.ImageSharp.Tuples
this.B += other.B;
}
/// <summary>
/// Downscale method, specific to Jpeg color conversion. Works only if Vector{float}.Count == 4!
/// TODO: Move it somewhere else.
/// <summary>.
/// Downscale method, specific to Jpeg color conversion. Works only if Vector{float}.Count == 4! /// TODO: Move it somewhere else.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void RoundAndDownscalePreAvx2()
internal void RoundAndDownscalePreAvx2(float downscaleFactor)
{
ref Vector<float> a = ref Unsafe.As<Vector4, Vector<float>>(ref this.A);
a = a.FastRound();
@ -50,8 +52,8 @@ namespace SixLabors.ImageSharp.Tuples
ref Vector<float> b = ref Unsafe.As<Vector4, Vector<float>>(ref this.B);
b = b.FastRound();
// Downscale by 1/255
var scale = new Vector4(1 / 255f);
// Downscale by 1/factor
var scale = new Vector4(1 / downscaleFactor);
this.A *= scale;
this.B *= scale;
}
@ -61,14 +63,14 @@ namespace SixLabors.ImageSharp.Tuples
/// TODO: Move it somewhere else.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void RoundAndDownscaleAvx2()
internal void RoundAndDownscaleAvx2(float downscaleFactor)
{
ref Vector<float> self = ref Unsafe.As<Vector4Pair, Vector<float>>(ref this);
Vector<float> v = self;
v = v.FastRound();
// Downscale by 1/255
v *= new Vector<float>(1 / 255f);
// Downscale by 1/factor
v *= new Vector<float>(1 / downscaleFactor);
self = v;
}

12
src/ImageSharp/Formats/Bmp/BmpCompression.cs

@ -25,7 +25,6 @@ namespace SixLabors.ImageSharp.Formats.Bmp
/// If the first byte is zero, the record has different meanings, depending
/// on the second byte. If the second byte is zero, it is the end of the row,
/// if it is one, it is the end of the image.
/// Not supported at the moment.
/// </summary>
RLE8 = 1,
@ -35,14 +34,12 @@ namespace SixLabors.ImageSharp.Formats.Bmp
/// If the first byte is zero, the record has different meanings, depending
/// on the second byte. If the second byte is zero, it is the end of the row,
/// if it is one, it is the end of the image.
/// Not supported at the moment.
/// </summary>
RLE4 = 2,
/// <summary>
/// Each image row has a multiple of four elements. If the
/// row has less elements, zeros will be added at the right side.
/// Not supported at the moment.
/// </summary>
BitFields = 3,
@ -56,6 +53,13 @@ namespace SixLabors.ImageSharp.Formats.Bmp
/// The bitmap contains a PNG image.
/// Not supported at the moment.
/// </summary>
PNG = 5
PNG = 5,
/// <summary>
/// Introduced with Windows CE.
/// Specifies that the bitmap is not compressed and that the color table consists of four DWORD color
/// masks that specify the red, green, blue, and alpha components of each pixel.
/// </summary>
BI_ALPHABITFIELDS = 6
}
}

36
src/ImageSharp/Formats/Bmp/BmpConstants.cs

@ -19,5 +19,41 @@ namespace SixLabors.ImageSharp.Formats.Bmp
/// The list of file extensions that equate to a bmp.
/// </summary>
public static readonly IEnumerable<string> FileExtensions = new[] { "bm", "bmp", "dip" };
/// <summary>
/// Valid magic bytes markers identifying a Bitmap file.
/// </summary>
internal static class TypeMarkers
{
/// <summary>
/// Single-image BMP file that may have been created under Windows or OS/2.
/// </summary>
public const int Bitmap = 0x4D42;
/// <summary>
/// OS/2 Bitmap Array.
/// </summary>
public const int BitmapArray = 0x4142;
/// <summary>
/// OS/2 Color Icon.
/// </summary>
public const int ColorIcon = 0x4943;
/// <summary>
/// OS/2 Color Pointer.
/// </summary>
public const int ColorPointer = 0x5043;
/// <summary>
/// OS/2 Icon.
/// </summary>
public const int Icon = 0x4349;
/// <summary>
/// OS/2 Pointer.
/// </summary>
public const int Pointer = 0x5450;
}
}
}

2
src/ImageSharp/Formats/Bmp/BmpDecoder.cs

@ -15,8 +15,6 @@ namespace SixLabors.ImageSharp.Formats.Bmp
/// <item>JPG</item>
/// <item>PNG</item>
/// <item>RLE4</item>
/// <item>RLE8</item>
/// <item>BitFields</item>
/// </list>
/// Formats will be supported in a later releases. We advise always
/// to use only 24 Bit Windows bitmaps.

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

@ -2,19 +2,21 @@
// Licensed under the Apache License, Version 2.0.
using System;
using System.Buffers;
using System.Buffers.Binary;
using System.IO;
using System.Numerics;
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Common.Helpers;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.MetaData;
using SixLabors.ImageSharp.Metadata;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Memory;
namespace SixLabors.ImageSharp.Formats.Bmp
{
/// <summary>
/// Performs the bmp decoding operation.
/// Performs the bitmap decoding operation.
/// </summary>
/// <remarks>
/// A useful decoding source example can be found at <see href="https://dxr.mozilla.org/mozilla-central/source/image/decoders/nsBMPDecoder.cpp"/>
@ -22,19 +24,19 @@ namespace SixLabors.ImageSharp.Formats.Bmp
internal sealed class BmpDecoderCore
{
/// <summary>
/// The mask for the red part of the color for 16 bit rgb bitmaps.
/// The default mask for the red part of the color for 16 bit rgb bitmaps.
/// </summary>
private const int Rgb16RMask = 0x7C00;
private const int DefaultRgb16RMask = 0x7C00;
/// <summary>
/// The mask for the green part of the color for 16 bit rgb bitmaps.
/// The default mask for the green part of the color for 16 bit rgb bitmaps.
/// </summary>
private const int Rgb16GMask = 0x3E0;
private const int DefaultRgb16GMask = 0x3E0;
/// <summary>
/// The mask for the blue part of the color for 16 bit rgb bitmaps.
/// The default mask for the blue part of the color for 16 bit rgb bitmaps.
/// </summary>
private const int Rgb16BMask = 0x1F;
private const int DefaultRgb16BMask = 0x1F;
/// <summary>
/// RLE8 flag value that indicates following byte has special meaning.
@ -62,13 +64,17 @@ namespace SixLabors.ImageSharp.Formats.Bmp
private Stream stream;
/// <summary>
/// The metadata
/// The metadata.
/// </summary>
private ImageMetaData metaData;
private ImageMetadata metadata;
/// <summary>
/// The bmp specific metadata.
/// </summary>
private BmpMetadata bmpMetadata;
/// <summary>
/// The file header containing general information.
/// TODO: Why is this not used? We advance the stream but do not use the values parsed.
/// </summary>
private BmpFileHeader fileHeader;
@ -85,7 +91,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
/// Initializes a new instance of the <see cref="BmpDecoderCore"/> class.
/// </summary>
/// <param name="configuration">The configuration.</param>
/// <param name="options">The options</param>
/// <param name="options">The options.</param>
public BmpDecoderCore(Configuration configuration, IBmpDecoderOptions options)
{
this.configuration = configuration;
@ -108,9 +114,9 @@ namespace SixLabors.ImageSharp.Formats.Bmp
{
try
{
this.ReadImageHeaders(stream, out bool inverted, out byte[] palette);
int bytesPerColorMapEntry = this.ReadImageHeaders(stream, out bool inverted, out byte[] palette);
var image = new Image<TPixel>(this.configuration, this.infoHeader.Width, this.infoHeader.Height, this.metaData);
var image = new Image<TPixel>(this.configuration, this.infoHeader.Width, this.infoHeader.Height, this.metadata);
Buffer2D<TPixel> pixels = image.GetRootFramePixelBuffer();
@ -119,7 +125,14 @@ namespace SixLabors.ImageSharp.Formats.Bmp
case BmpCompression.RGB:
if (this.infoHeader.BitsPerPixel == 32)
{
this.ReadRgb32(pixels, this.infoHeader.Width, this.infoHeader.Height, inverted);
if (this.bmpMetadata.InfoHeaderType == BmpInfoHeaderType.WinVersion3)
{
this.ReadRgb32Slow(pixels, this.infoHeader.Width, this.infoHeader.Height, inverted);
}
else
{
this.ReadRgb32Fast(pixels, this.infoHeader.Width, this.infoHeader.Height, inverted);
}
}
else if (this.infoHeader.BitsPerPixel == 24)
{
@ -137,16 +150,27 @@ namespace SixLabors.ImageSharp.Formats.Bmp
this.infoHeader.Width,
this.infoHeader.Height,
this.infoHeader.BitsPerPixel,
bytesPerColorMapEntry,
inverted);
}
break;
case BmpCompression.RLE8:
this.ReadRle8(pixels, palette, this.infoHeader.Width, this.infoHeader.Height, inverted);
case BmpCompression.RLE4:
this.ReadRle(this.infoHeader.Compression, pixels, palette, this.infoHeader.Width, this.infoHeader.Height, inverted);
break;
case BmpCompression.BitFields:
case BmpCompression.BI_ALPHABITFIELDS:
this.ReadBitFields(pixels, inverted);
break;
default:
throw new NotSupportedException("Does not support this kind of bitmap files.");
BmpThrowHelper.ThrowNotSupportedException("Does not support this kind of bitmap files.");
break;
}
return image;
@ -164,7 +188,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
public IImageInfo Identify(Stream stream)
{
this.ReadImageHeaders(stream, out _, out _);
return new ImageInfo(new PixelTypeInfo(this.infoHeader.BitsPerPixel), this.infoHeader.Width, this.infoHeader.Height, this.metaData);
return new ImageInfo(new PixelTypeInfo(this.infoHeader.BitsPerPixel), this.infoHeader.Width, this.infoHeader.Height, this.metadata);
}
/// <summary>
@ -198,30 +222,66 @@ namespace SixLabors.ImageSharp.Formats.Bmp
}
/// <summary>
/// Performs final shifting from a 5bit value to an 8bit one.
/// Decodes a bitmap containing BITFIELDS Compression type. For each color channel, there will be bitmask
/// which will be used to determine which bits belong to that channel.
/// </summary>
/// <param name="value">The masked and shifted value</param>
/// <returns>The <see cref="byte"/></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static byte GetBytesFrom5BitValue(int value) => (byte)((value << 3) | (value >> 2));
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="pixels">The output pixel buffer containing the decoded image.</param>
/// <param name="inverted">Whether the bitmap is inverted.</param>
private void ReadBitFields<TPixel>(Buffer2D<TPixel> pixels, bool inverted)
where TPixel : struct, IPixel<TPixel>
{
if (this.infoHeader.BitsPerPixel == 16)
{
this.ReadRgb16(
pixels,
this.infoHeader.Width,
this.infoHeader.Height,
inverted,
this.infoHeader.RedMask,
this.infoHeader.GreenMask,
this.infoHeader.BlueMask);
}
else
{
this.ReadRgb32BitFields(
pixels,
this.infoHeader.Width,
this.infoHeader.Height,
inverted,
this.infoHeader.RedMask,
this.infoHeader.GreenMask,
this.infoHeader.BlueMask,
this.infoHeader.AlphaMask);
}
}
/// <summary>
/// Looks up color values and builds the image from de-compressed RLE8 data.
/// Compresssed RLE8 stream is uncompressed by <see cref="UncompressRle8(int, Span{byte})"/>
/// Looks up color values and builds the image from de-compressed RLE8 or RLE4 data.
/// Compressed RLE8 stream is uncompressed by <see cref="UncompressRle8(int, Span{byte})"/>
/// Compressed RLE4 stream is uncompressed by <see cref="UncompressRle4(int, Span{byte})"/>
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="compression">The compression type. Either RLE4 or RLE8.</param>
/// <param name="pixels">The <see cref="Buffer2D{TPixel}"/> to assign the palette to.</param>
/// <param name="colors">The <see cref="T:byte[]"/> containing the colors.</param>
/// <param name="width">The width of the bitmap.</param>
/// <param name="height">The height of the bitmap.</param>
/// <param name="inverted">Whether the bitmap is inverted.</param>
private void ReadRle8<TPixel>(Buffer2D<TPixel> pixels, byte[] colors, int width, int height, bool inverted)
private void ReadRle<TPixel>(BmpCompression compression, Buffer2D<TPixel> pixels, byte[] colors, int width, int height, bool inverted)
where TPixel : struct, IPixel<TPixel>
{
TPixel color = default;
using (Buffer2D<byte> buffer = this.memoryAllocator.Allocate2D<byte>(width, height, AllocationOptions.Clean))
{
this.UncompressRle8(width, buffer.GetSpan());
if (compression == BmpCompression.RLE8)
{
this.UncompressRle8(width, buffer.GetSpan());
}
else
{
this.UncompressRle4(width, buffer.GetSpan());
}
for (int y = 0; y < height; y++)
{
@ -239,12 +299,122 @@ namespace SixLabors.ImageSharp.Formats.Bmp
}
/// <summary>
/// Produce uncompressed bitmap data from RLE8 stream
/// Produce uncompressed bitmap data from a RLE4 stream.
/// </summary>
/// <remarks>
/// RLE8 is a 2-byte run-length encoding
/// <br/>If first byte is 0, the second byte may have special meaning
/// <br/>Otherwise, first byte is the length of the run and second byte is the color for the run
/// RLE4 is a 2-byte run-length encoding.
/// <br/>If first byte is 0, the second byte may have special meaning.
/// <br/>Otherwise, the first byte is the length of the run and second byte contains two color indexes.
/// </remarks>
/// <param name="w">The width of the bitmap.</param>
/// <param name="buffer">Buffer for uncompressed data.</param>
private void UncompressRle4(int w, Span<byte> buffer)
{
#if NETCOREAPP2_1
Span<byte> cmd = stackalloc byte[2];
#else
byte[] cmd = new byte[2];
#endif
int count = 0;
while (count < buffer.Length)
{
if (this.stream.Read(cmd, 0, cmd.Length) != 2)
{
BmpThrowHelper.ThrowImageFormatException("Failed to read 2 bytes from the stream while uncompressing RLE4 bitmap.");
}
if (cmd[0] == RleCommand)
{
switch (cmd[1])
{
case RleEndOfBitmap:
return;
case RleEndOfLine:
int extra = count % w;
if (extra > 0)
{
count += w - extra;
}
break;
case RleDelta:
int dx = this.stream.ReadByte();
int dy = this.stream.ReadByte();
count += (w * dy) + dx;
break;
default:
// If the second byte > 2, we are in 'absolute mode'.
// The second byte contains the number of color indexes that follow.
int max = cmd[1];
int bytesToRead = (max + 1) / 2;
byte[] run = new byte[bytesToRead];
this.stream.Read(run, 0, run.Length);
int idx = 0;
for (int i = 0; i < max; i++)
{
byte twoPixels = run[idx];
if (i % 2 == 0)
{
byte leftPixel = (byte)((twoPixels >> 4) & 0xF);
buffer[count++] = leftPixel;
}
else
{
byte rightPixel = (byte)(twoPixels & 0xF);
buffer[count++] = rightPixel;
idx++;
}
}
// Absolute mode data is aligned to two-byte word-boundary
int padding = bytesToRead & 1;
this.stream.Skip(padding);
break;
}
}
else
{
int max = cmd[0];
// The second byte contains two color indexes, one in its high-order 4 bits and one in its low-order 4 bits.
byte twoPixels = cmd[1];
byte rightPixel = (byte)(twoPixels & 0xF);
byte leftPixel = (byte)((twoPixels >> 4) & 0xF);
for (int idx = 0; idx < max; idx++)
{
if (idx % 2 == 0)
{
buffer[count] = leftPixel;
}
else
{
buffer[count] = rightPixel;
}
count++;
}
}
}
}
/// <summary>
/// Produce uncompressed bitmap data from a RLE8 stream.
/// </summary>
/// <remarks>
/// RLE8 is a 2-byte run-length encoding.
/// <br/>If first byte is 0, the second byte may have special meaning.
/// <br/>Otherwise, the first byte is the length of the run and second byte is the color for the run.
/// </remarks>
/// <param name="w">The width of the bitmap.</param>
/// <param name="buffer">Buffer for uncompressed data.</param>
@ -261,7 +431,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
{
if (this.stream.Read(cmd, 0, cmd.Length) != 2)
{
throw new Exception("Failed to read 2 bytes from stream");
BmpThrowHelper.ThrowImageFormatException("Failed to read 2 bytes from stream while uncompressing RLE8 bitmap.");
}
if (cmd[0] == RleCommand)
@ -310,9 +480,12 @@ namespace SixLabors.ImageSharp.Formats.Bmp
}
else
{
for (int i = 0; i < cmd[0]; i++)
int max = count + cmd[0]; // as we start at the current count in the following loop, max is count + cmd[0]
byte cmd1 = cmd[1]; // store the value to avoid the repeated indexer access inside the loop
for (; count < max; count++)
{
buffer[count++] = cmd[1];
buffer[count] = cmd1;
}
}
}
@ -326,18 +499,20 @@ namespace SixLabors.ImageSharp.Formats.Bmp
/// <param name="colors">The <see cref="T:byte[]"/> containing the colors.</param>
/// <param name="width">The width of the bitmap.</param>
/// <param name="height">The height of the bitmap.</param>
/// <param name="bits">The number of bits per pixel.</param>
/// <param name="bitsPerPixel">The number of bits per pixel.</param>
/// <param name="bytesPerColorMapEntry">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.</param>
/// <param name="inverted">Whether the bitmap is inverted.</param>
private void ReadRgbPalette<TPixel>(Buffer2D<TPixel> pixels, byte[] colors, int width, int height, int bits, bool inverted)
private void ReadRgbPalette<TPixel>(Buffer2D<TPixel> pixels, byte[] colors, int width, int height, int bitsPerPixel, int bytesPerColorMapEntry, bool inverted)
where TPixel : struct, IPixel<TPixel>
{
// Pixels per byte (bits per pixel)
int ppb = 8 / bits;
int ppb = 8 / bitsPerPixel;
int arrayWidth = (width + ppb - 1) / ppb;
// Bit mask
int mask = 0xFF >> (8 - bits);
int mask = 0xFF >> (8 - bitsPerPixel);
// Rows are aligned on 4 byte boundaries
int padding = arrayWidth % 4;
@ -363,7 +538,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
int colOffset = x * ppb;
for (int shift = 0, newX = colOffset; shift < ppb && newX < width; shift++, newX++)
{
int colorIndex = ((rowSpan[offset] >> (8 - bits - (shift * bits))) & mask) * 4;
int colorIndex = ((rowSpan[offset] >> (8 - bitsPerPixel - (shift * bitsPerPixel))) & mask) * bytesPerColorMapEntry;
color.FromBgr24(Unsafe.As<byte, Bgr24>(ref colors[colorIndex]));
pixelRow[newX] = color;
@ -376,20 +551,32 @@ namespace SixLabors.ImageSharp.Formats.Bmp
}
/// <summary>
/// Reads the 16 bit color palette from the stream
/// Reads the 16 bit color palette from the stream.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="pixels">The <see cref="Buffer2D{TPixel}"/> to assign the palette to.</param>
/// <param name="width">The width of the bitmap.</param>
/// <param name="height">The height of the bitmap.</param>
/// <param name="inverted">Whether the bitmap is inverted.</param>
private void ReadRgb16<TPixel>(Buffer2D<TPixel> pixels, int width, int height, bool inverted)
/// <param name="redMask">The bitmask for the red channel.</param>
/// <param name="greenMask">The bitmask for the green channel.</param>
/// <param name="blueMask">The bitmask for the blue channel.</param>
private void ReadRgb16<TPixel>(Buffer2D<TPixel> pixels, int width, int height, bool inverted, int redMask = DefaultRgb16RMask, int greenMask = DefaultRgb16GMask, int blueMask = DefaultRgb16BMask)
where TPixel : struct, IPixel<TPixel>
{
int padding = CalculatePadding(width, 2);
int stride = (width * 2) + padding;
TPixel color = default;
int rightShiftRedMask = CalculateRightShift((uint)redMask);
int rightShiftGreenMask = CalculateRightShift((uint)greenMask);
int rightShiftBlueMask = CalculateRightShift((uint)blueMask);
// Each color channel contains either 5 or 6 Bits values.
int redMaskBits = CountBits((uint)redMask);
int greenMaskBits = CountBits((uint)greenMask);
int blueMaskBits = CountBits((uint)blueMask);
using (IManagedByteBuffer buffer = this.memoryAllocator.AllocateManagedByteBuffer(stride))
{
for (int y = 0; y < height; y++)
@ -403,10 +590,11 @@ namespace SixLabors.ImageSharp.Formats.Bmp
{
short temp = BitConverter.ToInt16(buffer.Array, offset);
var rgb = new Rgb24(
GetBytesFrom5BitValue((temp & Rgb16RMask) >> 10),
GetBytesFrom5BitValue((temp & Rgb16GMask) >> 5),
GetBytesFrom5BitValue(temp & Rgb16BMask));
// Rescale values, so the values range from 0 to 255.
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 b = (blueMaskBits == 5) ? GetBytesFrom5BitValue((temp & blueMask) >> rightShiftBlueMask) : GetBytesFrom6BitValue((temp & blueMask) >> rightShiftBlueMask);
var rgb = new Rgb24((byte)r, (byte)g, (byte)b);
color.FromRgb24(rgb);
pixelRow[x] = color;
@ -417,7 +605,23 @@ namespace SixLabors.ImageSharp.Formats.Bmp
}
/// <summary>
/// Reads the 24 bit color palette from the stream
/// Performs final shifting from a 5bit value to an 8bit one.
/// </summary>
/// <param name="value">The masked and shifted value.</param>
/// <returns>The <see cref="byte"/></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static byte GetBytesFrom5BitValue(int value) => (byte)((value << 3) | (value >> 2));
/// <summary>
/// Performs final shifting from a 6bit value to an 8bit one.
/// </summary>
/// <param name="value">The masked and shifted value.</param>
/// <returns>The <see cref="byte"/></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static byte GetBytesFrom6BitValue(int value) => (byte)((value << 2) | (value >> 4));
/// <summary>
/// Reads the 24 bit color palette from the stream.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="pixels">The <see cref="Buffer2D{TPixel}"/> to assign the palette to.</param>
@ -436,36 +640,266 @@ namespace SixLabors.ImageSharp.Formats.Bmp
this.stream.Read(row);
int newY = Invert(y, height, inverted);
Span<TPixel> pixelSpan = pixels.GetRowSpan(newY);
PixelOperations<TPixel>.Instance.FromBgr24Bytes(row.GetSpan(), pixelSpan, width);
PixelOperations<TPixel>.Instance.FromBgr24Bytes(
this.configuration,
row.GetSpan(),
pixelSpan,
width);
}
}
}
/// <summary>
/// Reads the 32 bit color palette from the stream.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="pixels">The <see cref="Buffer2D{TPixel}"/> to assign the palette to.</param>
/// <param name="width">The width of the bitmap.</param>
/// <param name="height">The height of the bitmap.</param>
/// <param name="inverted">Whether the bitmap is inverted.</param>
private void ReadRgb32Fast<TPixel>(Buffer2D<TPixel> pixels, int width, int height, bool inverted)
where TPixel : struct, IPixel<TPixel>
{
int padding = CalculatePadding(width, 4);
using (IManagedByteBuffer row = this.memoryAllocator.AllocatePaddedPixelRowBuffer(width, 4, padding))
{
for (int y = 0; y < height; y++)
{
this.stream.Read(row);
int newY = Invert(y, height, inverted);
Span<TPixel> pixelSpan = pixels.GetRowSpan(newY);
PixelOperations<TPixel>.Instance.FromBgra32Bytes(
this.configuration,
row.GetSpan(),
pixelSpan,
width);
}
}
}
/// <summary>
/// Reads the 32 bit color palette from the stream
/// Reads the 32 bit color palette from the stream, checking the alpha component of each pixel.
/// This is a special case only used for 32bpp WinBMPv3 files, which could be in either BGR0 or BGRA format.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="pixels">The <see cref="Buffer2D{TPixel}"/> to assign the palette to.</param>
/// <param name="width">The width of the bitmap.</param>
/// <param name="height">The height of the bitmap.</param>
/// <param name="inverted">Whether the bitmap is inverted.</param>
private void ReadRgb32<TPixel>(Buffer2D<TPixel> pixels, int width, int height, bool inverted)
private void ReadRgb32Slow<TPixel>(Buffer2D<TPixel> pixels, int width, int height, bool inverted)
where TPixel : struct, IPixel<TPixel>
{
int padding = CalculatePadding(width, 4);
using (IManagedByteBuffer row = this.memoryAllocator.AllocatePaddedPixelRowBuffer(width, 4, padding))
using (IMemoryOwner<Bgra32> bgraRow = this.memoryAllocator.Allocate<Bgra32>(width))
{
Span<Bgra32> bgraRowSpan = bgraRow.GetSpan();
long currentPosition = this.stream.Position;
bool hasAlpha = false;
// Loop though the rows checking each pixel. We start by assuming it's
// an BGR0 image. If we hit a non-zero alpha value, then we know it's
// actually a BGRA image, and change tactics accordingly.
for (int y = 0; y < height; y++)
{
this.stream.Read(row);
PixelOperations<Bgra32>.Instance.FromBgra32Bytes(
this.configuration,
row.GetSpan(),
bgraRowSpan,
width);
// Check each pixel in the row to see if it has an alpha value.
for (int x = 0; x < width; x++)
{
Bgra32 bgra = bgraRowSpan[x];
if (bgra.A > 0)
{
hasAlpha = true;
break;
}
}
if (hasAlpha)
{
break;
}
}
// Reset our stream for a second pass.
this.stream.Position = currentPosition;
// Process the pixels in bulk taking the raw alpha component value.
if (hasAlpha)
{
for (int y = 0; y < height; y++)
{
this.stream.Read(row);
int newY = Invert(y, height, inverted);
Span<TPixel> pixelSpan = pixels.GetRowSpan(newY);
PixelOperations<TPixel>.Instance.FromBgra32Bytes(
this.configuration,
row.GetSpan(),
pixelSpan,
width);
}
return;
}
// Slow path. We need to set each alpha component value to fully opaque.
for (int y = 0; y < height; y++)
{
this.stream.Read(row);
PixelOperations<Bgra32>.Instance.FromBgra32Bytes(
this.configuration,
row.GetSpan(),
bgraRowSpan,
width);
int newY = Invert(y, height, inverted);
Span<TPixel> pixelSpan = pixels.GetRowSpan(newY);
PixelOperations<TPixel>.Instance.FromBgra32Bytes(row.GetSpan(), pixelSpan, width);
for (int x = 0; x < width; x++)
{
Bgra32 bgra = bgraRowSpan[x];
bgra.A = byte.MaxValue;
ref TPixel pixel = ref pixelSpan[x];
pixel.FromBgra32(bgra);
}
}
}
}
/// <summary>
/// Decode an 32 Bit Bitmap containing a bitmask for each color channel.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="pixels">The output pixel buffer containing the decoded image.</param>
/// <param name="width">The width of the image.</param>
/// <param name="height">The height of the image.</param>
/// <param name="inverted">Whether the bitmap is inverted.</param>
/// <param name="redMask">The bitmask for the red channel.</param>
/// <param name="greenMask">The bitmask for the green channel.</param>
/// <param name="blueMask">The bitmask for the blue channel.</param>
/// <param name="alphaMask">The bitmask for the alpha channel.</param>
private void ReadRgb32BitFields<TPixel>(Buffer2D<TPixel> pixels, int width, int height, bool inverted, int redMask, int greenMask, int blueMask, int alphaMask)
where TPixel : struct, IPixel<TPixel>
{
TPixel color = default;
int padding = CalculatePadding(width, 4);
int stride = (width * 4) + padding;
int rightShiftRedMask = CalculateRightShift((uint)redMask);
int rightShiftGreenMask = CalculateRightShift((uint)greenMask);
int rightShiftBlueMask = CalculateRightShift((uint)blueMask);
int rightShiftAlphaMask = CalculateRightShift((uint)alphaMask);
int bitsRedMask = CountBits((uint)redMask);
int bitsGreenMask = CountBits((uint)greenMask);
int bitsBlueMask = CountBits((uint)blueMask);
int bitsAlphaMask = CountBits((uint)alphaMask);
float invMaxValueRed = 1.0f / (0xFFFFFFFF >> (32 - bitsRedMask));
float invMaxValueGreen = 1.0f / (0xFFFFFFFF >> (32 - bitsGreenMask));
float invMaxValueBlue = 1.0f / (0xFFFFFFFF >> (32 - bitsBlueMask));
uint maxValueAlpha = 0xFFFFFFFF >> (32 - bitsAlphaMask);
float invMaxValueAlpha = 1.0f / maxValueAlpha;
bool unusualBitMask = false;
if (bitsRedMask > 8 || bitsGreenMask > 8 || bitsBlueMask > 8 || invMaxValueAlpha > 8)
{
unusualBitMask = true;
}
using (IManagedByteBuffer buffer = this.memoryAllocator.AllocateManagedByteBuffer(stride))
{
for (int y = 0; y < height; y++)
{
this.stream.Read(buffer.Array, 0, stride);
int newY = Invert(y, height, inverted);
Span<TPixel> pixelRow = pixels.GetRowSpan(newY);
int offset = 0;
for (int x = 0; x < width; x++)
{
uint temp = BitConverter.ToUInt32(buffer.Array, offset);
if (unusualBitMask)
{
uint r = (uint)(temp & redMask) >> rightShiftRedMask;
uint g = (uint)(temp & greenMask) >> rightShiftGreenMask;
uint b = (uint)(temp & blueMask) >> rightShiftBlueMask;
float alpha = alphaMask != 0 ? invMaxValueAlpha * ((uint)(temp & alphaMask) >> rightShiftAlphaMask) : 1.0f;
var vector4 = new Vector4(
r * invMaxValueRed,
g * invMaxValueGreen,
b * invMaxValueBlue,
alpha);
color.FromVector4(vector4);
}
else
{
byte r = (byte)((temp & redMask) >> rightShiftRedMask);
byte g = (byte)((temp & greenMask) >> rightShiftGreenMask);
byte b = (byte)((temp & blueMask) >> rightShiftBlueMask);
byte a = alphaMask != 0 ? (byte)((temp & alphaMask) >> rightShiftAlphaMask) : (byte)255;
color.FromRgba32(new Rgba32(r, g, b, a));
}
pixelRow[x] = color;
offset += 4;
}
}
}
}
/// <summary>
/// Calculates the necessary right shifts for a given color bitmask (the 0 bits to the right).
/// </summary>
/// <param name="n">The color bit mask.</param>
/// <returns>Number of bits to shift right.</returns>
private static int CalculateRightShift(uint n)
{
int count = 0;
while (n > 0)
{
if ((1 & n) == 0)
{
count++;
}
else
{
break;
}
n >>= 1;
}
return count;
}
/// <summary>
/// Counts none zero bits.
/// </summary>
/// <param name="n">A color mask.</param>
/// <returns>The none zero bits.</returns>
private static int CountBits(uint n)
{
int count = 0;
while (n != 0)
{
count++;
n &= n - 1;
}
return count;
}
/// <summary>
/// Reads the <see cref="BmpInfoHeader"/> from the stream.
/// </summary>
@ -481,7 +915,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
int headerSize = BinaryPrimitives.ReadInt32LittleEndian(buffer);
if (headerSize < BmpInfoHeader.CoreSize)
{
throw new NotSupportedException($"ImageSharp does not support this BMP file. HeaderSize: {headerSize}.");
BmpThrowHelper.ThrowNotSupportedException($"ImageSharp does not support this BMP file. HeaderSize is '{headerSize}'.");
}
int skipAmount = 0;
@ -494,23 +928,78 @@ namespace SixLabors.ImageSharp.Formats.Bmp
// read the rest of the header
this.stream.Read(buffer, BmpInfoHeader.HeaderSizeSize, headerSize - BmpInfoHeader.HeaderSizeSize);
BmpInfoHeaderType infoHeaderType = BmpInfoHeaderType.WinVersion2;
if (headerSize == BmpInfoHeader.CoreSize)
{
// 12 bytes
infoHeaderType = BmpInfoHeaderType.WinVersion2;
this.infoHeader = BmpInfoHeader.ParseCore(buffer);
}
else if (headerSize >= BmpInfoHeader.Size)
else if (headerSize == BmpInfoHeader.Os22ShortSize)
{
// 16 bytes
infoHeaderType = BmpInfoHeaderType.Os2Version2Short;
this.infoHeader = BmpInfoHeader.ParseOs22Short(buffer);
}
else if (headerSize == BmpInfoHeader.SizeV3)
{
// == 40 bytes
infoHeaderType = BmpInfoHeaderType.WinVersion3;
this.infoHeader = BmpInfoHeader.ParseV3(buffer);
// If the info header is BMP version 3 and the compression type is BITFIELDS,
// color masks for each color channel follow the info header.
if (this.infoHeader.Compression == BmpCompression.BitFields)
{
byte[] bitfieldsBuffer = new byte[12];
this.stream.Read(bitfieldsBuffer, 0, 12);
Span<byte> data = bitfieldsBuffer.AsSpan<byte>();
this.infoHeader.RedMask = BinaryPrimitives.ReadInt32LittleEndian(data.Slice(0, 4));
this.infoHeader.GreenMask = BinaryPrimitives.ReadInt32LittleEndian(data.Slice(4, 4));
this.infoHeader.BlueMask = BinaryPrimitives.ReadInt32LittleEndian(data.Slice(8, 4));
}
else if (this.infoHeader.Compression == BmpCompression.BI_ALPHABITFIELDS)
{
byte[] bitfieldsBuffer = new byte[16];
this.stream.Read(bitfieldsBuffer, 0, 16);
Span<byte> data = bitfieldsBuffer.AsSpan<byte>();
this.infoHeader.RedMask = BinaryPrimitives.ReadInt32LittleEndian(data.Slice(0, 4));
this.infoHeader.GreenMask = BinaryPrimitives.ReadInt32LittleEndian(data.Slice(4, 4));
this.infoHeader.BlueMask = BinaryPrimitives.ReadInt32LittleEndian(data.Slice(8, 4));
this.infoHeader.AlphaMask = BinaryPrimitives.ReadInt32LittleEndian(data.Slice(12, 4));
}
}
else if (headerSize == BmpInfoHeader.AdobeV3Size)
{
// == 52 bytes
infoHeaderType = BmpInfoHeaderType.AdobeVersion3;
this.infoHeader = BmpInfoHeader.ParseAdobeV3(buffer, withAlpha: false);
}
else if (headerSize == BmpInfoHeader.AdobeV3WithAlphaSize)
{
// == 56 bytes
infoHeaderType = BmpInfoHeaderType.AdobeVersion3WithAlpha;
this.infoHeader = BmpInfoHeader.ParseAdobeV3(buffer, withAlpha: true);
}
else if (headerSize == BmpInfoHeader.Os2v2Size)
{
// == 64 bytes
infoHeaderType = BmpInfoHeaderType.Os2Version2;
this.infoHeader = BmpInfoHeader.ParseOs2Version2(buffer);
}
else if (headerSize >= BmpInfoHeader.SizeV4)
{
// >= 40 bytes
this.infoHeader = BmpInfoHeader.Parse(buffer);
// >= 108 bytes
infoHeaderType = headerSize == BmpInfoHeader.SizeV4 ? BmpInfoHeaderType.WinVersion4 : BmpInfoHeaderType.WinVersion5;
this.infoHeader = BmpInfoHeader.ParseV4(buffer);
}
else
{
throw new NotSupportedException($"ImageSharp does not support this BMP file. HeaderSize: {headerSize}.");
BmpThrowHelper.ThrowNotSupportedException($"ImageSharp does not support this BMP file. HeaderSize '{headerSize}'.");
}
// Resolution is stored in PPM.
var meta = new ImageMetaData
var meta = new ImageMetadata
{
ResolutionUnits = PixelResolutionUnit.PixelsPerMeter
};
@ -522,20 +1011,21 @@ namespace SixLabors.ImageSharp.Formats.Bmp
else
{
// Convert default metadata values to PPM.
meta.HorizontalResolution = Math.Round(UnitConverter.InchToMeter(ImageMetaData.DefaultHorizontalResolution));
meta.VerticalResolution = Math.Round(UnitConverter.InchToMeter(ImageMetaData.DefaultVerticalResolution));
meta.HorizontalResolution = Math.Round(UnitConverter.InchToMeter(ImageMetadata.DefaultHorizontalResolution));
meta.VerticalResolution = Math.Round(UnitConverter.InchToMeter(ImageMetadata.DefaultVerticalResolution));
}
this.metaData = meta;
this.metadata = meta;
short bitsPerPixel = this.infoHeader.BitsPerPixel;
BmpMetaData bmpMetaData = this.metaData.GetFormatMetaData(BmpFormat.Instance);
this.bmpMetadata = this.metadata.GetFormatMetadata(BmpFormat.Instance);
this.bmpMetadata.InfoHeaderType = infoHeaderType;
// We can only encode at these bit rates so far.
if (bitsPerPixel.Equals((short)BmpBitsPerPixel.Pixel24)
|| bitsPerPixel.Equals((short)BmpBitsPerPixel.Pixel32))
{
bmpMetaData.BitsPerPixel = (BmpBitsPerPixel)bitsPerPixel;
this.bmpMetadata.BitsPerPixel = (BmpBitsPerPixel)bitsPerPixel;
}
// skip the remaining header because we can't read those parts
@ -555,12 +1045,19 @@ namespace SixLabors.ImageSharp.Formats.Bmp
this.stream.Read(buffer, 0, BmpFileHeader.Size);
this.fileHeader = BmpFileHeader.Parse(buffer);
if (this.fileHeader.Type != BmpConstants.TypeMarkers.Bitmap)
{
BmpThrowHelper.ThrowNotSupportedException($"ImageSharp does not support this BMP file. File header bitmap type marker '{this.fileHeader.Type}'.");
}
}
/// <summary>
/// Reads the <see cref="BmpFileHeader"/> and <see cref="BmpInfoHeader"/> from the stream and sets the corresponding fields.
/// </summary>
private void ReadImageHeaders(Stream stream, out bool inverted, out byte[] palette)
/// <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>
private int ReadImageHeaders(Stream stream, out bool inverted, out byte[] palette)
{
this.stream = stream;
@ -580,6 +1077,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
}
int colorMapSize = -1;
int bytesPerColorMapEntry = 4;
if (this.infoHeader.ClrUsed == 0)
{
@ -587,12 +1085,18 @@ namespace SixLabors.ImageSharp.Formats.Bmp
|| this.infoHeader.BitsPerPixel == 4
|| this.infoHeader.BitsPerPixel == 8)
{
colorMapSize = ImageMaths.GetColorCountForBitDepth(this.infoHeader.BitsPerPixel) * 4;
int colorMapSizeBytes = this.fileHeader.Offset - BmpFileHeader.Size - this.infoHeader.HeaderSize;
int colorCountForBitDepth = ImageMaths.GetColorCountForBitDepth(this.infoHeader.BitsPerPixel);
bytesPerColorMapEntry = colorMapSizeBytes / colorCountForBitDepth;
// Edge case for less-than-full-sized palette: bytesPerColorMapEntry should be at least 3.
bytesPerColorMapEntry = Math.Max(bytesPerColorMapEntry, 3);
colorMapSize = colorMapSizeBytes;
}
}
else
{
colorMapSize = this.infoHeader.ClrUsed * 4;
colorMapSize = this.infoHeader.ClrUsed * bytesPerColorMapEntry;
}
palette = null;
@ -602,7 +1106,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
// 256 * 4
if (colorMapSize > 1024)
{
throw new ImageFormatException($"Invalid bmp colormap size '{colorMapSize}'");
BmpThrowHelper.ThrowImageFormatException($"Invalid bmp colormap size '{colorMapSize}'");
}
palette = new byte[colorMapSize];
@ -611,6 +1115,19 @@ namespace SixLabors.ImageSharp.Formats.Bmp
}
this.infoHeader.VerifyDimensions();
int skipAmount = this.fileHeader.Offset - (int)this.stream.Position;
if ((skipAmount + (int)this.stream.Position) > this.stream.Length)
{
BmpThrowHelper.ThrowImageFormatException($"Invalid fileheader offset found. Offset is greater than the stream length.");
}
if (skipAmount > 0)
{
this.stream.Skip(skipAmount);
}
return bytesPerColorMapEntry;
}
}
}

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

@ -3,9 +3,11 @@
using System;
using System.IO;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Common.Helpers;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.MetaData;
using SixLabors.ImageSharp.Metadata;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Memory;
@ -21,8 +23,30 @@ namespace SixLabors.ImageSharp.Formats.Bmp
/// </summary>
private int padding;
/// <summary>
/// The mask for the alpha channel of the color for a 32 bit rgba bitmaps.
/// </summary>
private const int Rgba32AlphaMask = 0xFF << 24;
/// <summary>
/// The mask for the red part of the color for a 32 bit rgba bitmaps.
/// </summary>
private const int Rgba32RedMask = 0xFF << 16;
/// <summary>
/// The mask for the green part of the color for a 32 bit rgba bitmaps.
/// </summary>
private const int Rgba32GreenMask = 0xFF << 8;
/// <summary>
/// The mask for the blue part of the color for a 32 bit rgba bitmaps.
/// </summary>
private const int Rgba32BlueMask = 0xFF;
private readonly MemoryAllocator memoryAllocator;
private Configuration configuration;
private BmpBitsPerPixel? bitsPerPixel;
/// <summary>
@ -48,9 +72,10 @@ namespace SixLabors.ImageSharp.Formats.Bmp
Guard.NotNull(image, nameof(image));
Guard.NotNull(stream, nameof(stream));
ImageMetaData metaData = image.MetaData;
BmpMetaData bmpMetaData = metaData.GetFormatMetaData(BmpFormat.Instance);
this.bitsPerPixel = this.bitsPerPixel ?? bmpMetaData.BitsPerPixel;
this.configuration = image.GetConfiguration();
ImageMetadata metadata = image.Metadata;
BmpMetadata bmpMetadata = metadata.GetFormatMetadata(BmpFormat.Instance);
this.bitsPerPixel = this.bitsPerPixel ?? bmpMetadata.BitsPerPixel;
short bpp = (short)this.bitsPerPixel;
int bytesPerLine = 4 * (((image.Width * bpp) + 31) / 32);
@ -60,35 +85,36 @@ namespace SixLabors.ImageSharp.Formats.Bmp
int hResolution = 0;
int vResolution = 0;
if (metaData.ResolutionUnits != PixelResolutionUnit.AspectRatio)
if (metadata.ResolutionUnits != PixelResolutionUnit.AspectRatio)
{
if (metaData.HorizontalResolution > 0 && metaData.VerticalResolution > 0)
if (metadata.HorizontalResolution > 0 && metadata.VerticalResolution > 0)
{
switch (metaData.ResolutionUnits)
switch (metadata.ResolutionUnits)
{
case PixelResolutionUnit.PixelsPerInch:
hResolution = (int)Math.Round(UnitConverter.InchToMeter(metaData.HorizontalResolution));
vResolution = (int)Math.Round(UnitConverter.InchToMeter(metaData.VerticalResolution));
hResolution = (int)Math.Round(UnitConverter.InchToMeter(metadata.HorizontalResolution));
vResolution = (int)Math.Round(UnitConverter.InchToMeter(metadata.VerticalResolution));
break;
case PixelResolutionUnit.PixelsPerCentimeter:
hResolution = (int)Math.Round(UnitConverter.CmToMeter(metaData.HorizontalResolution));
vResolution = (int)Math.Round(UnitConverter.CmToMeter(metaData.VerticalResolution));
hResolution = (int)Math.Round(UnitConverter.CmToMeter(metadata.HorizontalResolution));
vResolution = (int)Math.Round(UnitConverter.CmToMeter(metadata.VerticalResolution));
break;
case PixelResolutionUnit.PixelsPerMeter:
hResolution = (int)Math.Round(metaData.HorizontalResolution);
vResolution = (int)Math.Round(metaData.VerticalResolution);
hResolution = (int)Math.Round(metadata.HorizontalResolution);
vResolution = (int)Math.Round(metadata.VerticalResolution);
break;
}
}
}
int infoHeaderSize = BmpInfoHeader.SizeV4;
var infoHeader = new BmpInfoHeader(
headerSize: BmpInfoHeader.Size,
headerSize: infoHeaderSize,
height: image.Height,
width: image.Width,
bitsPerPixel: bpp,
@ -97,26 +123,37 @@ namespace SixLabors.ImageSharp.Formats.Bmp
clrUsed: 0,
clrImportant: 0,
xPelsPerMeter: hResolution,
yPelsPerMeter: vResolution);
yPelsPerMeter: vResolution)
{
RedMask = Rgba32RedMask,
GreenMask = Rgba32GreenMask,
BlueMask = Rgba32BlueMask,
Compression = BmpCompression.BitFields
};
if (this.bitsPerPixel == BmpBitsPerPixel.Pixel32)
{
infoHeader.AlphaMask = Rgba32AlphaMask;
}
var fileHeader = new BmpFileHeader(
type: 19778, // BM
fileSize: 54 + infoHeader.ImageSize,
type: BmpConstants.TypeMarkers.Bitmap,
fileSize: BmpFileHeader.Size + infoHeaderSize + infoHeader.ImageSize,
reserved: 0,
offset: 54);
offset: BmpFileHeader.Size + infoHeaderSize);
#if NETCOREAPP2_1
Span<byte> buffer = stackalloc byte[40];
Span<byte> buffer = stackalloc byte[infoHeaderSize];
#else
byte[] buffer = new byte[40];
byte[] buffer = new byte[infoHeaderSize];
#endif
fileHeader.WriteTo(buffer);
stream.Write(buffer, 0, BmpFileHeader.Size);
infoHeader.WriteTo(buffer);
infoHeader.WriteV4Header(buffer);
stream.Write(buffer, 0, 40);
stream.Write(buffer, 0, infoHeaderSize);
this.WriteImage(stream, image.Frames.RootFrame);
@ -163,7 +200,11 @@ namespace SixLabors.ImageSharp.Formats.Bmp
for (int y = pixels.Height - 1; y >= 0; y--)
{
Span<TPixel> pixelSpan = pixels.GetRowSpan(y);
PixelOperations<TPixel>.Instance.ToBgra32Bytes(pixelSpan, row.GetSpan(), pixelSpan.Length);
PixelOperations<TPixel>.Instance.ToBgra32Bytes(
this.configuration,
pixelSpan,
row.GetSpan(),
pixelSpan.Length);
stream.Write(row.Array, 0, row.Length());
}
}
@ -183,7 +224,11 @@ namespace SixLabors.ImageSharp.Formats.Bmp
for (int y = pixels.Height - 1; y >= 0; y--)
{
Span<TPixel> pixelSpan = pixels.GetRowSpan(y);
PixelOperations<TPixel>.Instance.ToBgr24Bytes(pixelSpan, row.GetSpan(), pixelSpan.Length);
PixelOperations<TPixel>.Instance.ToBgr24Bytes(
this.configuration,
pixelSpan,
row.GetSpan(),
pixelSpan.Length);
stream.Write(row.Array, 0, row.Length());
}
}

4
src/ImageSharp/Formats/Bmp/BmpFormat.cs

@ -8,7 +8,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
/// <summary>
/// Registers the image encoders, decoders and mime type detectors for the bmp format.
/// </summary>
public sealed class BmpFormat : IImageFormat<BmpMetaData>
public sealed class BmpFormat : IImageFormat<BmpMetadata>
{
private BmpFormat()
{
@ -32,6 +32,6 @@ namespace SixLabors.ImageSharp.Formats.Bmp
public IEnumerable<string> FileExtensions => BmpConstants.FileExtensions;
/// <inheritdoc/>
public BmpMetaData CreateDefaultFormatMetaData() => new BmpMetaData();
public BmpMetadata CreateDefaultFormatMetadata() => new BmpMetadata();
}
}

8
src/ImageSharp/Formats/Bmp/BmpImageFormatDetector.cs

@ -6,7 +6,7 @@ using System;
namespace SixLabors.ImageSharp.Formats.Bmp
{
/// <summary>
/// Detects bmp file headers
/// Detects bmp file headers.
/// </summary>
public sealed class BmpImageFormatDetector : IImageFormatDetector
{
@ -22,9 +22,9 @@ namespace SixLabors.ImageSharp.Formats.Bmp
private bool IsSupportedFileFormat(ReadOnlySpan<byte> header)
{
// TODO: This should be in constants
return header.Length >= this.HeaderSize &&
header[0] == 0x42 && // B
header[1] == 0x4D; // M
return header.Length >= this.HeaderSize
&& header[0] == 0x42 // B
&& header[1] == 0x4D; // M
}
}
}

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

@ -17,19 +17,44 @@ namespace SixLabors.ImageSharp.Formats.Bmp
internal struct BmpInfoHeader
{
/// <summary>
/// Defines the size of the BITMAPINFOHEADER data structure in the bitmap file.
/// Defines the size of the BITMAPCOREHEADER data structure in the bitmap file.
/// </summary>
public const int Size = 40;
public const int CoreSize = 12;
/// <summary>
/// Defines the size of the BITMAPCOREHEADER data structure in the bitmap file.
/// Defines the size of the short variant of the OS22XBITMAPHEADER data structure in the bitmap file.
/// </summary>
public const int CoreSize = 12;
public const int Os22ShortSize = 16;
/// <summary>
/// Defines the size of the BITMAPINFOHEADER (BMP Version 3) data structure in the bitmap file.
/// </summary>
public const int SizeV3 = 40;
/// <summary>
/// Special case of the BITMAPINFOHEADER V3 used by adobe where the color bitmasks are part of the info header instead of following it.
/// </summary>
public const int AdobeV3Size = 52;
/// <summary>
/// Special case of the BITMAPINFOHEADER V3 used by adobe where the color bitmasks (including the alpha channel) are part of the info header instead of following it.
/// </summary>
public const int AdobeV3WithAlphaSize = 56;
/// <summary>
/// Size of a IBM OS/2 2.x bitmap header.
/// </summary>
public const int Os2v2Size = 64;
/// <summary>
/// Defines the size of the BITMAPINFOHEADER (BMP Version 4) data structure in the bitmap file.
/// </summary>
public const int SizeV4 = 108;
/// <summary>
/// Defines the size of the biggest supported header data structure in the bitmap file.
/// </summary>
public const int MaxHeaderSize = Size;
public const int MaxHeaderSize = SizeV4;
/// <summary>
/// Defines the size of the <see cref="HeaderSize"/> field.
@ -47,7 +72,24 @@ namespace SixLabors.ImageSharp.Formats.Bmp
int xPelsPerMeter = 0,
int yPelsPerMeter = 0,
int clrUsed = 0,
int clrImportant = 0)
int clrImportant = 0,
int redMask = 0,
int greenMask = 0,
int blueMask = 0,
int alphaMask = 0,
int csType = 0,
int redX = 0,
int redY = 0,
int redZ = 0,
int greenX = 0,
int greenY = 0,
int greenZ = 0,
int blueX = 0,
int blueY = 0,
int blueZ = 0,
int gammeRed = 0,
int gammeGreen = 0,
int gammeBlue = 0)
{
this.HeaderSize = headerSize;
this.Width = width;
@ -60,10 +102,27 @@ namespace SixLabors.ImageSharp.Formats.Bmp
this.YPelsPerMeter = yPelsPerMeter;
this.ClrUsed = clrUsed;
this.ClrImportant = clrImportant;
this.RedMask = redMask;
this.GreenMask = greenMask;
this.BlueMask = blueMask;
this.AlphaMask = alphaMask;
this.CsType = csType;
this.RedX = redX;
this.RedY = redY;
this.RedZ = redZ;
this.GreenX = greenX;
this.GreenY = greenY;
this.GreenZ = greenZ;
this.BlueX = blueX;
this.BlueY = blueY;
this.BlueZ = blueZ;
this.GammaRed = gammeRed;
this.GammaGreen = gammeGreen;
this.GammaBlue = gammeBlue;
}
/// <summary>
/// Gets or sets the size of this header
/// Gets or sets the size of this header.
/// </summary>
public int HeaderSize { get; set; }
@ -125,25 +184,94 @@ namespace SixLabors.ImageSharp.Formats.Bmp
public int ClrImportant { get; set; }
/// <summary>
/// Parses the full BITMAPINFOHEADER header (40 bytes).
/// Gets or sets red color mask. This is used with the BITFIELDS decoding.
/// </summary>
/// <param name="data">The data to parse.</param>
/// <returns>Parsed header</returns>
/// <seealso href="https://msdn.microsoft.com/en-us/library/windows/desktop/dd183376.aspx"/>
public static BmpInfoHeader Parse(ReadOnlySpan<byte> data)
{
if (data.Length != Size)
{
throw new ArgumentException(nameof(data), $"Must be {Size} bytes. Was {data.Length} bytes.");
}
public int RedMask { get; set; }
return MemoryMarshal.Cast<byte, BmpInfoHeader>(data)[0];
}
/// <summary>
/// Gets or sets green color mask. This is used with the BITFIELDS decoding.
/// </summary>
public int GreenMask { get; set; }
/// <summary>
/// Gets or sets blue color mask. This is used with the BITFIELDS decoding.
/// </summary>
public int BlueMask { get; set; }
/// <summary>
/// Parses the BITMAPCOREHEADER consisting of the headerSize, width, height, planes, and bitsPerPixel fields (12 bytes).
/// Gets or sets alpha color mask. This is not used yet.
/// </summary>
/// <param name="data">The data to parse,</param>
public int AlphaMask { get; set; }
/// <summary>
/// Gets or sets the Color space type. Not used yet.
/// </summary>
public int CsType { get; set; }
/// <summary>
/// Gets or sets the X coordinate of red endpoint. Not used yet.
/// </summary>
public int RedX { get; set; }
/// <summary>
/// Gets or sets the Y coordinate of red endpoint. Not used yet.
/// </summary>
public int RedY { get; set; }
/// <summary>
/// Gets or sets the Z coordinate of red endpoint. Not used yet.
/// </summary>
public int RedZ { get; set; }
/// <summary>
/// Gets or sets the X coordinate of green endpoint. Not used yet.
/// </summary>
public int GreenX { get; set; }
/// <summary>
/// Gets or sets the Y coordinate of green endpoint. Not used yet.
/// </summary>
public int GreenY { get; set; }
/// <summary>
/// Gets or sets the Z coordinate of green endpoint. Not used yet.
/// </summary>
public int GreenZ { get; set; }
/// <summary>
/// Gets or sets the X coordinate of blue endpoint. Not used yet.
/// </summary>
public int BlueX { get; set; }
/// <summary>
/// Gets or sets the Y coordinate of blue endpoint. Not used yet.
/// </summary>
public int BlueY { get; set; }
/// <summary>
/// Gets or sets the Z coordinate of blue endpoint. Not used yet.
/// </summary>
public int BlueZ { get; set; }
/// <summary>
/// Gets or sets the Gamma red coordinate scale value. Not used yet.
/// </summary>
public int GammaRed { get; set; }
/// <summary>
/// Gets or sets the Gamma green coordinate scale value. Not used yet.
/// </summary>
public int GammaGreen { get; set; }
/// <summary>
/// Gets or sets the Gamma blue coordinate scale value. Not used yet.
/// </summary>
public int GammaBlue { get; set; }
/// <summary>
/// Parses the BITMAPCOREHEADER (BMP Version 2) consisting of the headerSize, width, height, planes, and bitsPerPixel fields (12 bytes).
/// </summary>
/// <param name="data">The data to parse.</param>
/// <returns>Parsed header</returns>
/// <seealso href="https://msdn.microsoft.com/en-us/library/windows/desktop/dd183372.aspx"/>
public static BmpInfoHeader ParseCore(ReadOnlySpan<byte> data)
@ -156,7 +284,161 @@ namespace SixLabors.ImageSharp.Formats.Bmp
bitsPerPixel: BinaryPrimitives.ReadInt16LittleEndian(data.Slice(10, 2)));
}
public unsafe void WriteTo(Span<byte> buffer)
/// <summary>
/// Parses a short variant of the OS22XBITMAPHEADER. It is identical to the BITMAPCOREHEADER, except that the width and height
/// are 4 bytes instead of 2, resulting in 16 bytes total.
/// </summary>
/// <param name="data">The data to parse.</param>
/// <returns>Parsed header</returns>
/// <seealso href="https://www.fileformat.info/format/os2bmp/egff.htm"/>
public static BmpInfoHeader ParseOs22Short(ReadOnlySpan<byte> data)
{
return new BmpInfoHeader(
headerSize: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(0, 4)),
width: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(4, 4)),
height: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(8, 4)),
planes: BinaryPrimitives.ReadInt16LittleEndian(data.Slice(12, 2)),
bitsPerPixel: BinaryPrimitives.ReadInt16LittleEndian(data.Slice(14, 2)));
}
/// <summary>
/// Parses the full BMP Version 3 BITMAPINFOHEADER header (40 bytes).
/// </summary>
/// <param name="data">The data to parse.</param>
/// <returns>The parsed header.</returns>
/// <seealso href="http://www.fileformat.info/format/bmp/egff.htm"/>
public static BmpInfoHeader ParseV3(ReadOnlySpan<byte> data)
{
return new BmpInfoHeader(
headerSize: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(0, 4)),
width: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(4, 4)),
height: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(8, 4)),
planes: BinaryPrimitives.ReadInt16LittleEndian(data.Slice(12, 2)),
bitsPerPixel: BinaryPrimitives.ReadInt16LittleEndian(data.Slice(14, 2)),
compression: (BmpCompression)BinaryPrimitives.ReadInt32LittleEndian(data.Slice(16, 4)),
imageSize: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(20, 4)),
xPelsPerMeter: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(24, 4)),
yPelsPerMeter: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(28, 4)),
clrUsed: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(32, 4)),
clrImportant: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(36, 4)));
}
/// <summary>
/// Special case of the BITMAPINFOHEADER V3 used by adobe where the color bitmasks are part of the info header instead of following it.
/// 52 bytes without the alpha mask, 56 bytes with the alpha mask.
/// </summary>
/// <param name="data">The data to parse.</param>
/// <param name="withAlpha">Indicates, if the alpha bitmask is present.</param>
/// <returns>The parsed header.</returns>
/// <seealso href="https://forums.adobe.com/message/3272950#3272950"/>
public static BmpInfoHeader ParseAdobeV3(ReadOnlySpan<byte> data, bool withAlpha = true)
{
return new BmpInfoHeader(
headerSize: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(0, 4)),
width: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(4, 4)),
height: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(8, 4)),
planes: BinaryPrimitives.ReadInt16LittleEndian(data.Slice(12, 2)),
bitsPerPixel: BinaryPrimitives.ReadInt16LittleEndian(data.Slice(14, 2)),
compression: (BmpCompression)BinaryPrimitives.ReadInt32LittleEndian(data.Slice(16, 4)),
imageSize: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(20, 4)),
xPelsPerMeter: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(24, 4)),
yPelsPerMeter: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(28, 4)),
clrUsed: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(32, 4)),
clrImportant: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(36, 4)),
redMask: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(40, 4)),
greenMask: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(44, 4)),
blueMask: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(48, 4)),
alphaMask: withAlpha ? BinaryPrimitives.ReadInt32LittleEndian(data.Slice(52, 4)) : 0);
}
/// <summary>
/// Parses a OS/2 version 2 bitmap header (64 bytes). Only the first 40 bytes are parsed which are
/// very similar to the Bitmap v3 header. The other 24 bytes are ignored, but they do not hold any
/// useful information for decoding the image.
/// </summary>
/// <param name="data">The data to parse.</param>
/// <returns>The parsed header.</returns>
/// <seealso href="https://www.fileformat.info/format/os2bmp/egff.htm"/>
public static BmpInfoHeader ParseOs2Version2(ReadOnlySpan<byte> data)
{
var infoHeader = new BmpInfoHeader(
headerSize: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(0, 4)),
width: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(4, 4)),
height: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(8, 4)),
planes: BinaryPrimitives.ReadInt16LittleEndian(data.Slice(12, 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.
// Map the OS/2 value to the windows values.
switch (compression)
{
case 0:
infoHeader.Compression = BmpCompression.RGB;
break;
case 1:
infoHeader.Compression = BmpCompression.RLE8;
break;
case 2:
infoHeader.Compression = BmpCompression.RLE4;
break;
default:
BmpThrowHelper.ThrowImageFormatException($"Compression type is not supported. ImageSharp only supports uncompressed, RLE4 and RLE8.");
break;
}
infoHeader.ImageSize = BinaryPrimitives.ReadInt32LittleEndian(data.Slice(20, 4));
infoHeader.XPelsPerMeter = BinaryPrimitives.ReadInt32LittleEndian(data.Slice(24, 4));
infoHeader.YPelsPerMeter = BinaryPrimitives.ReadInt32LittleEndian(data.Slice(28, 4));
infoHeader.ClrUsed = BinaryPrimitives.ReadInt32LittleEndian(data.Slice(32, 4));
infoHeader.ClrImportant = BinaryPrimitives.ReadInt32LittleEndian(data.Slice(36, 4));
// The following 24 bytes of the header are omitted.
return infoHeader;
}
/// <summary>
/// Parses the full BMP Version 4 BITMAPINFOHEADER header (108 bytes).
/// </summary>
/// <param name="data">The data to parse.</param>
/// <returns>The parsed header.</returns>
/// <seealso href="http://www.fileformat.info/format/bmp/egff.htm"/>
public static BmpInfoHeader ParseV4(ReadOnlySpan<byte> data)
{
if (data.Length != SizeV4)
{
throw new ArgumentException(nameof(data), $"Must be {SizeV4} bytes. Was {data.Length} bytes.");
}
return MemoryMarshal.Cast<byte, BmpInfoHeader>(data)[0];
}
/// <summary>
/// Writes a bitmap version 3 (Microsoft Windows NT) header to a buffer (40 bytes).
/// </summary>
/// <param name="buffer">The buffer to write to.</param>
public void WriteV3Header(Span<byte> buffer)
{
buffer.Clear();
BinaryPrimitives.WriteInt32LittleEndian(buffer.Slice(0, 4), SizeV3);
BinaryPrimitives.WriteInt32LittleEndian(buffer.Slice(4, 4), this.Width);
BinaryPrimitives.WriteInt32LittleEndian(buffer.Slice(8, 4), this.Height);
BinaryPrimitives.WriteInt16LittleEndian(buffer.Slice(12, 2), this.Planes);
BinaryPrimitives.WriteInt16LittleEndian(buffer.Slice(14, 2), this.BitsPerPixel);
BinaryPrimitives.WriteInt32LittleEndian(buffer.Slice(16, 4), (int)this.Compression);
BinaryPrimitives.WriteInt32LittleEndian(buffer.Slice(20, 4), this.ImageSize);
BinaryPrimitives.WriteInt32LittleEndian(buffer.Slice(24, 4), this.XPelsPerMeter);
BinaryPrimitives.WriteInt32LittleEndian(buffer.Slice(28, 4), this.YPelsPerMeter);
BinaryPrimitives.WriteInt32LittleEndian(buffer.Slice(32, 4), this.ClrUsed);
BinaryPrimitives.WriteInt32LittleEndian(buffer.Slice(36, 4), this.ClrImportant);
}
/// <summary>
/// Writes a complete Bitmap V4 header to a buffer.
/// </summary>
/// <param name="buffer">The buffer to write to.</param>
public unsafe void WriteV4Header(Span<byte> buffer)
{
ref BmpInfoHeader dest = ref Unsafe.As<byte, BmpInfoHeader>(ref MemoryMarshal.GetReference(buffer));

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

@ -0,0 +1,51 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
namespace SixLabors.ImageSharp.Formats.Bmp
{
/// <summary>
/// Enum value for the different bitmap info header types. The enum value is the number of bytes for the specific bitmap header.
/// </summary>
public enum BmpInfoHeaderType
{
/// <summary>
/// Bitmap Core or BMP Version 2 header (Microsoft Windows 2.x).
/// </summary>
WinVersion2 = 12,
/// <summary>
/// Short variant of the OS/2 Version 2 bitmap header.
/// </summary>
Os2Version2Short = 16,
/// <summary>
/// BMP Version 3 header (Microsoft Windows 3.x or Microsoft Windows NT).
/// </summary>
WinVersion3 = 40,
/// <summary>
/// Adobe variant of the BMP Version 3 header.
/// </summary>
AdobeVersion3 = 52,
/// <summary>
/// Adobe variant of the BMP Version 3 header with an alpha mask.
/// </summary>
AdobeVersion3WithAlpha = 56,
/// <summary>
/// BMP Version 2.x header (IBM OS/2 2.x).
/// </summary>
Os2Version2 = 64,
/// <summary>
/// BMP Version 4 header (Microsoft Windows 95).
/// </summary>
WinVersion4 = 108,
/// <summary>
/// BMP Version 5 header (Windows NT 5.0, 98 or later).
/// </summary>
WinVersion5 = 124,
}
}

21
src/ImageSharp/Formats/Bmp/BmpMetaData.cs

@ -6,20 +6,29 @@ namespace SixLabors.ImageSharp.Formats.Bmp
/// <summary>
/// Provides Bmp specific metadata information for the image.
/// </summary>
public class BmpMetaData : IDeepCloneable
public class BmpMetadata : IDeepCloneable
{
/// <summary>
/// Initializes a new instance of the <see cref="BmpMetaData"/> class.
/// Initializes a new instance of the <see cref="BmpMetadata"/> class.
/// </summary>
public BmpMetaData()
public BmpMetadata()
{
}
/// <summary>
/// Initializes a new instance of the <see cref="BmpMetaData"/> class.
/// Initializes a new instance of the <see cref="BmpMetadata"/> class.
/// </summary>
/// <param name="other">The metadata to create an instance from.</param>
private BmpMetaData(BmpMetaData other) => this.BitsPerPixel = other.BitsPerPixel;
private BmpMetadata(BmpMetadata other)
{
this.BitsPerPixel = other.BitsPerPixel;
this.InfoHeaderType = other.InfoHeaderType;
}
/// <summary>
/// Gets or sets the bitmap info header type.
/// </summary>
public BmpInfoHeaderType InfoHeaderType { get; set; }
/// <summary>
/// Gets or sets the number of bits per pixel.
@ -27,7 +36,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
public BmpBitsPerPixel BitsPerPixel { get; set; } = BmpBitsPerPixel.Pixel24;
/// <inheritdoc/>
public IDeepCloneable DeepClone() => new BmpMetaData(this);
public IDeepCloneable DeepClone() => new BmpMetadata(this);
// TODO: Colors used once we support encoding palette bmps.
}

31
src/ImageSharp/Formats/Bmp/BmpThrowHelper.cs

@ -0,0 +1,31 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.Formats.Bmp
{
internal static class BmpThrowHelper
{
/// <summary>
/// Cold path optimization for throwing <see cref="ImageFormatException"/>-s
/// </summary>
/// <param name="errorMessage">The error message for the exception.</param>
[MethodImpl(MethodImplOptions.NoInlining)]
public static void ThrowImageFormatException(string errorMessage)
{
throw new ImageFormatException(errorMessage);
}
/// <summary>
/// Cold path optimization for throwing <see cref="NotSupportedException"/>-s
/// </summary>
/// <param name="errorMessage">The error message for the exception.</param>
[MethodImpl(MethodImplOptions.NoInlining)]
public static void ThrowNotSupportedException(string errorMessage)
{
throw new NotSupportedException(errorMessage);
}
}
}

2
src/ImageSharp/Formats/Bmp/IBmpDecoderOptions.cs

@ -8,6 +8,6 @@ namespace SixLabors.ImageSharp.Formats.Bmp
/// </summary>
internal interface IBmpDecoderOptions
{
// added this for consistancy so we can add stuff as required, no options currently availible
// added this for consistency so we can add stuff as required, no options currently available
}
}

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

Loading…
Cancel
Save