Browse Source

Merge branch 'master' into tiff-codec

pull/1570/head
James Jackson-South 8 years ago
committed by GitHub
parent
commit
d385156480
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      .travis.yml
  2. 2
      ImageSharp.ruleset
  3. 3
      ImageSharp.sln
  4. 5
      ImageSharp.sln.DotSettings
  5. 54
      README.md
  6. 47
      appveyor.yml
  7. 19
      build.ps1
  8. 112
      run-tests.ps1
  9. 10
      src/ImageSharp.Drawing/ImageSharp.Drawing.csproj
  10. 7
      src/ImageSharp.Drawing/Primitives/Region.cs
  11. 5
      src/ImageSharp.Drawing/Primitives/ShapePath.cs
  12. 24
      src/ImageSharp.Drawing/Primitives/ShapeRegion.cs
  13. 25
      src/ImageSharp.Drawing/Processing/BrushApplicator.cs
  14. 2
      src/ImageSharp.Drawing/Processing/Brushes.cs
  15. 39
      src/ImageSharp.Drawing/Processing/ColorStop{TPixel}.cs
  16. 28
      src/ImageSharp.Drawing/Processing/DrawBezierExtensions.cs
  17. 89
      src/ImageSharp.Drawing/Processing/DrawImageExtensions.cs
  18. 30
      src/ImageSharp.Drawing/Processing/DrawLineExtensions.cs
  19. 24
      src/ImageSharp.Drawing/Processing/DrawPathCollectionExtensions.cs
  20. 26
      src/ImageSharp.Drawing/Processing/DrawPathExtensions.cs
  21. 30
      src/ImageSharp.Drawing/Processing/DrawPolygonExtensions.cs
  22. 24
      src/ImageSharp.Drawing/Processing/DrawRectangleExtensions.cs
  23. 70
      src/ImageSharp.Drawing/Processing/DrawTextExtensions.cs
  24. 155
      src/ImageSharp.Drawing/Processing/Drawing/Processors/DrawImageProcessor.cs
  25. 170
      src/ImageSharp.Drawing/Processing/EllipticGradientBrush{TPixel}.cs
  26. 17
      src/ImageSharp.Drawing/Processing/FillPathBuilderExtensions.cs
  27. 17
      src/ImageSharp.Drawing/Processing/FillPathCollectionExtensions.cs
  28. 19
      src/ImageSharp.Drawing/Processing/FillPathExtensions.cs
  29. 19
      src/ImageSharp.Drawing/Processing/FillPolygonExtensions.cs
  30. 17
      src/ImageSharp.Drawing/Processing/FillRectangleExtensions.cs
  31. 23
      src/ImageSharp.Drawing/Processing/FillRegionExtensions.cs
  32. 177
      src/ImageSharp.Drawing/Processing/GradientBrushBase{TPixel}.cs
  33. 37
      src/ImageSharp.Drawing/Processing/GradientRepetitionMode.cs
  34. 2
      src/ImageSharp.Drawing/Processing/IBrush.cs
  35. 3
      src/ImageSharp.Drawing/Processing/IPen.cs
  36. 14
      src/ImageSharp.Drawing/Processing/ImageBrush{TPixel}.cs
  37. 155
      src/ImageSharp.Drawing/Processing/LinearGradientBrush{TPixel}.cs
  38. 16
      src/ImageSharp.Drawing/Processing/PatternBrush{TPixel}.cs
  39. 3
      src/ImageSharp.Drawing/Processing/Pens.cs
  40. 11
      src/ImageSharp.Drawing/Processing/Pen{TPixel}.cs
  41. 98
      src/ImageSharp.Drawing/Processing/Processors/Drawing/DrawImageProcessor.cs
  42. 84
      src/ImageSharp.Drawing/Processing/Processors/Drawing/FillProcessor.cs
  43. 89
      src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor.cs
  44. 471
      src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor.cs
  45. 105
      src/ImageSharp.Drawing/Processing/RadialGradientBrush{TPixel}.cs
  46. 18
      src/ImageSharp.Drawing/Processing/RecolorBrush{TPixel}.cs
  47. 36
      src/ImageSharp.Drawing/Processing/SolidBrush{TPixel}.cs
  48. 179
      src/ImageSharp.Drawing/Processing/Text/DrawTextExtensions.Path.cs
  49. 43
      src/ImageSharp.Drawing/Processing/TextGraphicsOptions.cs
  50. 84
      src/ImageSharp.Drawing/Utils/QuickSort.cs
  51. 114
      src/ImageSharp/Advanced/AdvancedImageExtensions.cs
  52. 2
      src/ImageSharp/Advanced/IConfigurable.cs
  53. 1
      src/ImageSharp/Advanced/IPixelSource.cs
  54. 47
      src/ImageSharp/ColorSpaces/CieLab.cs
  55. 46
      src/ImageSharp/ColorSpaces/CieLch.cs
  56. 50
      src/ImageSharp/ColorSpaces/CieLchuv.cs
  57. 47
      src/ImageSharp/ColorSpaces/CieLuv.cs
  58. 29
      src/ImageSharp/ColorSpaces/CieXyChromaticityCoordinates.cs
  59. 35
      src/ImageSharp/ColorSpaces/CieXyy.cs
  60. 36
      src/ImageSharp/ColorSpaces/CieXyz.cs
  61. 29
      src/ImageSharp/ColorSpaces/Cmyk.cs
  62. 34
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Adapt.cs
  63. 55
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLab.cs
  64. 52
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLch.cs
  65. 50
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLchuv.cs
  66. 52
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLuv.cs
  67. 50
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyy.cs
  68. 55
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyz.cs
  69. 53
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Cmyk.cs
  70. 51
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsl.cs
  71. 51
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsv.cs
  72. 52
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.HunterLab.cs
  73. 54
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.LinearRgb.cs
  74. 53
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Lms.cs
  75. 52
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Rgb.cs
  76. 53
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.YCbCr.cs
  77. 4
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.cs
  78. 4
      src/ImageSharp/ColorSpaces/Conversion/IChromaticAdaptation.cs
  79. 6
      src/ImageSharp/ColorSpaces/Conversion/IColorConversion.cs
  80. 4
      src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLab/CieLabToCieXyzConverter.cs
  81. 11
      src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLab/CieXyzToCieLabConverter.cs
  82. 5
      src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLch/CIeLchToCieLabConverter.cs
  83. 5
      src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLch/CieLabToCieLchConverter.cs
  84. 5
      src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLchuv/CieLchuvToCieLuvConverter.cs
  85. 5
      src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLchuv/CieLuvToCieLchuvConverter.cs
  86. 9
      src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLuv/CieLuvToCieXyzConverter.cs
  87. 14
      src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLuv/CieXyzToCieLuvConverter.cs
  88. 9
      src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyy/CieXyzAndCieXyyConverter.cs
  89. 5
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Cmyk/CmykAndRgbConverter.cs
  90. 9
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Hsl/HslAndRgbConverter.cs
  91. 9
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Hsv/HsvAndRgbConverter.cs
  92. 4
      src/ImageSharp/ColorSpaces/Conversion/Implementation/HunterLab/CieXyzAndHunterLabConverterBase.cs
  93. 11
      src/ImageSharp/ColorSpaces/Conversion/Implementation/HunterLab/CieXyzToHunterLabConverter.cs
  94. 5
      src/ImageSharp/ColorSpaces/Conversion/Implementation/HunterLab/HunterLabToCieXyzConverter.cs
  95. 9
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Lms/CieXyzAndLmsConverter.cs
  96. 2
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Lms/LmsAdaptationMatrix.cs
  97. 10
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Rgb/CieXyzToLinearRgbConverter.cs
  98. 2
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Rgb/GammaCompanding.cs
  99. 4
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Rgb/LCompanding.cs
  100. 7
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Rgb/LinearRgbAndCieXyzConverterBase.cs

4
.travis.yml

@ -6,7 +6,7 @@ matrix:
- os: linux # Ubuntu 14.04
dist: trusty
sudo: required
dotnet: 2.1.4
dotnet: 2.1.401
mono: latest
# - os: osx # OSX 10.11
# osx_image: xcode7.3.1
@ -21,7 +21,7 @@ branches:
script:
- git submodule -q update --init
- dotnet restore
- dotnet test tests/ImageSharp.Tests/ImageSharp.Tests.csproj -c Release -f "netcoreapp2.0"
- dotnet test tests/ImageSharp.Tests/ImageSharp.Tests.csproj -c Release -f "netcoreapp2.1"
env:
global:

2
ImageSharp.ruleset

@ -9,5 +9,7 @@
<Rule Id="SA1633" Action="None" />
<!--1.1.0-beta6 incorrectly throws a wobbler here for multiline matrices-->
<Rule Id="SA1500" Action="None" />
<!--Comments should end with a period. I like this but there's 3000+ errors to fix-->
<Rule Id="SA1629" Action="None" />
</Rules>
</RuleSet>

3
ImageSharp.sln

@ -1,6 +1,6 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.27130.2036
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
@ -17,6 +17,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SolutionItems", "SolutionIt
NuGet.config = NuGet.config
.github\PULL_REQUEST_TEMPLATE.md = .github\PULL_REQUEST_TEMPLATE.md
README.md = README.md
run-tests.ps1 = run-tests.ps1
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Source", "Source", "{815C0625-CD3D-440F-9F80-2D83856AB7AE}"

5
ImageSharp.sln.DotSettings

@ -343,8 +343,11 @@
&lt;Entry DisplayName="All other members" /&gt;&#xD;
&lt;/TypePattern&gt;&#xD;
&lt;/Patterns&gt;</s:String>
<s:Boolean x:Key="/Default/CodeStyle/CSharpUsing/AddImportsToDeepestScope/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CSharpUsing/AddImportsToDeepestScope/@EntryValue">False</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CSharpUsing/QualifiedUsingAtNestedScope/@EntryValue">True</s:Boolean>
<s:String x:Key="/Default/CodeStyle/FileHeader/FileHeaderText/@EntryValue">// Copyright (c) Six Labors and contributors.&#xD;
// Licensed under the Apache License, Version 2.0.&#xD;
</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=AC/@EntryIndexedValue">AC</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=DC/@EntryIndexedValue">DC</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=DCT/@EntryIndexedValue">DCT</s:String>

54
README.md

@ -1,16 +1,21 @@
<h1 align="center">
<img src="https://raw.githubusercontent.com/SixLabors/ImageSharp/master/build/icons/imagesharp-logo-256.png" alt="ImageSharp" width="175"/>
<br>
ImageSharp
<br>
<br>
<a href="https://raw.githubusercontent.com/SixLabors/ImageSharp/master/LICENSE"><img src="https://img.shields.io/badge/license-Apache%202-blue.svg" alt="GitHub license" data-canonical-src="https://img.shields.io/badge/license-Apache%202-blue.svg" style="max-width:100%;"></a>
<a href="https://gitter.im/ImageSharp/General?utm_source=badge&amp;utm_medium=badge&amp;utm_campaign=pr-badge&amp;utm_content=badge"><img src="https://badges.gitter.im/Join%20Chat.svg" alt="Gitter" data-canonical-src="https://badges.gitter.im/Join%20Chat.svg" style="max-width:100%;"></a>
<a href="https://twitter.com/intent/tweet?hashtags=imagesharp,dotnet,oss&amp;text=ImageSharp.+A+new+cross-platform+2D+graphics+API+in+C%23&amp;url=https%3a%2f%2fgithub.com%2fSixLabors%2fImageSharp&amp;via=sixlabors"><img src="https://img.shields.io/twitter/url/http/shields.io.svg?style=flat&logo=twitter" alt="Twitter" data-canonical-src="https://img.shields.io/twitter/url/http/shields.io.svg?style=flat&logo=twitter" style="max-width:100%;"></a>
<a href="#backers"><img src="https://opencollective.com/imagesharp/backers/badge.svg" alt="OpenCollective" data-canonical-src="https://opencollective.com/imagesharp/backers/badge.svg" style="max-width:100%;"></a>
<a href="#sponsors"><img src="https://opencollective.com/imagesharp/sponsors/badge.svg" alt="OpenCollective" data-canonical-src="https://opencollective.com/imagesharp/sponsors/badge.svg" style="max-width:100%;"></a>
<img src="https://raw.githubusercontent.com/SixLabors/Branding/master/icons/imagesharp/sixlabors.imagesharp.512.png" alt="SixLabors.ImageSharp" width="256"/>
<br/>
SixLabors.ImageSharp
</h1>
<div align="center">
[![GitHub license](https://img.shields.io/badge/license-Apache%202-blue.svg)](https://raw.githubusercontent.com/SixLabors/ImageSharp/master/LICENSE)
[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/ImageSharp/General?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[![Twitter](https://img.shields.io/twitter/url/http/shields.io.svg?style=flat&logo=twitter)](https://twitter.com/intent/tweet?hashtags=imagesharp,dotnet,oss&text=ImageSharp.+A+new+cross-platform+2D+graphics+API+in+C%23&url=https%3a%2f%2fgithub.com%2fSixLabors%2fImageSharp&via=sixlabors)
[![OpenCollective](https://opencollective.com/imagesharp/backers/badge.svg)](#backers)
[![OpenCollective](https://opencollective.com/imagesharp/sponsors/badge.svg)](#sponsors)
</div>
### **ImageSharp** is a new, fully featured, fully managed, cross-platform, 2D graphics API.
Designed to democratize image processing, ImageSharp brings you an incredibly powerful yet beautifully simple API.
@ -19,9 +24,13 @@ Compared to `System.Drawing` we have been able to develop something much more fl
Built against .Net Standard 1.1 ImageSharp can be used in device, cloud, and embedded/IoT scenarios.
### Documentation
For all SixLabors projects, including ImageSharp:
https://sixlabors.github.io/docs/
### Installation
Install stable releases via Nuget;evelopment releases are available via MyGet.
Install stable releases via Nuget; development releases are available via MyGet.
| Package Name | Release (NuGet) | Nightly (MyGet) |
|--------------------------------|-----------------|-----------------|
@ -51,12 +60,11 @@ The **ImageSharp** library is made up of multiple packages:
### Questions?
Do you have questions? We are happy to help! Please [join our gitter channel](https://gitter.im/ImageSharp/General), or ask them on [stackoverflow](https://stackoverflow.com) using the `ImageSharp` tag.
- Do you have questions? We are happy to help! Please [join our gitter channel](https://gitter.im/ImageSharp/General), or ask them on [stackoverflow](https://stackoverflow.com) using the `ImageSharp` tag. **Do not** open issues for questions!
- Please read our [Contribution Guide](https://github.com/SixLabors/ImageSharp/blob/master/.github/CONTRIBUTING.md) before opening issues or pull requests!
### API
API documentation is available at [https://sixlabors.github.io/docs/](https://sixlabors.github.io/docs/)
Our API is designed to be simple to consume. Here's an example of the code required to resize an image using the default Bicubic resampler then turn the colors into their grayscale equivalent using the BT709 standard matrix.
On platforms supporting netstandard 1.3+
@ -100,21 +108,25 @@ using (Image<Rgba32> image = new Image<Rgba32>(400, 400))
`Rgba32` is our default PixelFormat, equivalent to `System.Drawing Color`. For advanced pixel format usage there are multiple [PixelFormat implementations](https://github.com/SixLabors/ImageSharp/tree/master/src/ImageSharp/PixelFormats) available allowing developers to implement their own color models in the same manner as Microsoft XNA Game Studio and MonoGame.
**Check out this [blog post](https://sixlabors.com/blog/announcing-imagesharp-beta-1/) or our [Samples Repository](https://github.com/SixLabors/Samples/tree/master/ImageSharp) for more examples!**
For more examples check out:
- [Our Documentation](https://sixlabors.github.io/docs/)
- Our [Samples Repository](https://github.com/SixLabors/Samples/tree/master/ImageSharp)
- The [beta1 blog post](https://sixlabors.com/blog/announcing-imagesharp-beta-1/)
### Manual build
If you prefer, you can compile ImageSharp yourself (please do and help!), you'll need:
If you prefer, you can compile ImageSharp yourself (please do and help!)
- [Visual Studio 2017 (or above)](https://www.visualstudio.com/en-us/news/releasenotes/vs2017-relnotes)
- The [.NET Core SDK Installer](https://www.microsoft.com/net/core#windows) - Non VSCode link.
- Using [Visual Studio 2017](https://visualstudio.microsoft.com/vs/)
- Make sure you have the latest version installed
- Make sure you have [the .NET Core 2.1 SDK](https://www.microsoft.com/net/core#windows) installed
Alternatively on Linux you can use:
Alternatively, you can work from command line and/or with a lightweight editor on **both Linux/Unix and Windows**:
- [Visual Studio Code](https://code.visualstudio.com/) with [C# Extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode.csharp)
- [.Net Core](https://www.microsoft.com/net/core#linuxubuntu)
To clone it locally click the "Clone in Windows" button above or run the following git commands.
To clone ImageSharp locally click the "Clone in Windows" button above or run the following git commands.
```bash
git clone https://github.com/SixLabors/ImageSharp
@ -122,7 +134,7 @@ git clone https://github.com/SixLabors/ImageSharp
### How can you help?
Please... Spread the word, contribute algorithms, submit performance improvements, unit tests, no input is too little.
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.
### The ImageSharp Team

47
appveyor.yml

@ -1,18 +1,57 @@
version: 1.0.0.{build}
image: Visual Studio 2017
image: Previous Visual Studio 2017
# prevent the double build when a branch has an active PR
skip_branch_with_pr: true
environment:
matrix:
- target_framework: netcoreapp2.1
is_32bit: False
- target_framework: netcoreapp2.1
is_32bit: True
- target_framework: net471
is_32bit: False
- target_framework: net471
is_32bit: True
- target_framework: net462
is_32bit: False
- target_framework: net462
is_32bit: True
#- target_framework: mono
# is_32bit: False
#- target_framework: mono
# is_32bit: True
#- target_framework: net47
# is_32bit: False
#- target_framework: net47
# is_32bit: True
install:
- ps: |
if ($env:target_framework -eq "mono") {
if ($env:is_32bit -eq "True") {
cinst mono --x86
} else {
cinst mono
}
}
before_build:
- git submodule -q update --init
- cmd: dotnet --version
- cmd: dotnet --info
build_script:
- cmd: build.cmd
test_script:
- tests\CodeCoverage\CodeCoverage.cmd
- ps: .\run-tests.ps1 $env:target_framework $env:is_32bit
after_test:
- cmd: appveyor PushArtifact "artifacts\SixLabors.ImageSharp.%APPVEYOR_BUILD_VERSION%.nupkg"
@ -27,4 +66,4 @@ deploy:
secure: V/lEHP0UeMWIpWd0fiNlY2IgbCnJKQlGdRksECdJbOBdaE20Fl0RNL7WyqHe02o4
artifact: /.*\.nupkg/
on:
branch: master
branch: master

19
build.ps1

@ -8,7 +8,7 @@ $tagRegex = '^v?(\d+\.\d+\.\d+)(-([a-zA-Z]+)\.?(\d*))?$'
# we are running on the build server
$isVersionTag = $env:APPVEYOR_REPO_TAG_NAME -match $tagRegex
if($isVersionTag){
if($isVersionTag) {
Write-Debug "Building commit tagged with a compatable version number"
@ -26,7 +26,8 @@ $isVersionTag = $env:APPVEYOR_REPO_TAG_NAME -match $tagRegex
$version = "${version}${padded}"
}
}else {
}
else {
Write-Debug "Untagged"
$lastTag = (git tag --list --sort=-taggerdate) | Out-String
@ -100,9 +101,17 @@ dotnet build -c Release /p:packageversion=$version
if ($LASTEXITCODE ){ Exit $LASTEXITCODE }
if ( $env:CI -ne "True") {
dotnet test ./tests/ImageSharp.Tests/ImageSharp.Tests.csproj --no-build -c Release
}
#
# TODO: DO WE NEED TO RUN TESTS IMPLICITLY?
#
# if ( $env:CI -ne "True") {
# cd ./tests/ImageSharp.Tests/
# dotnet xunit -nobuild -c Release -f netcoreapp2.0 --fx-version 2.0.0
# ./RunExtendedTests.cmd
# cd ../..
# }
#
if ($LASTEXITCODE ){ Exit $LASTEXITCODE }
Write-Host "Packaging projects"

112
run-tests.ps1

@ -0,0 +1,112 @@
param(
[string]$targetFramework,
[string]$is32Bit = "False"
)
if (!$targetFramework){
Write-Host "run-tests.ps1 ERROR: targetFramework is undefined!"
exit 1
}
function VerifyPath($path, $errorMessage) {
if (!(Test-Path -Path $path)) {
Write-Host "run-tests.ps1 $errorMessage `n $xunitRunnerPath"
exit 1
}
}
function CheckSubmoduleStatus() {
$submoduleStatus = (git submodule status) | Out-String
# if the result string is empty, the command failed to run (we didn't capture the error stream)
if ($submoduleStatus) {
# git has been called successfully, what about the status?
if (($submoduleStatus -match "\-") -or ($submoduleStatus -match "\(\(null\)\)"))
{
# submodule has not been initialized!
return 2;
}
elseif ($submoduleStatus -match "\+")
{
# submodule is not synced:
return 1;
}
else {
# everything fine:
return 0;
}
} else {
# git call failed, so we should warn
return 3;
}
}
if ( ($targetFramework -eq "netcoreapp2.1") -and ($env:CI -eq "True") -and ($is32Bit -ne "True")) {
# We execute CodeCoverage.cmd only for one specific job on CI (netcoreapp2.1 + 64bit )
$testRunnerCmd = ".\tests\CodeCoverage\CodeCoverage.cmd"
}
elseif ($targetFramework -eq "mono") {
$testDllPath = "$PSScriptRoot\tests\ImageSharp.Tests\bin\Release\net462\SixLabors.ImageSharp.Tests.dll"
VerifyPath($testDllPath, "test dll missing:")
$xunitRunnerPath = "${env:HOMEPATH}\.nuget\packages\xunit.runner.console\2.3.1\tools\net452\"
VerifyPath($xunitRunnerPath, "xunit console runner is missing on path:")
cd "$xunitRunnerPath"
if ($is32Bit -ne "True") {
$monoPath = "${env:PROGRAMFILES}\Mono\bin\mono.exe"
}
else {
$monoPath = "${env:ProgramFiles(x86)}\Mono\bin\mono.exe"
}
VerifyPath($monoPath, "mono runtime missing:")
$testRunnerCmd = "& `"${monoPath}`" .\xunit.console.exe `"${testDllPath}`""
}
else {
cd .\tests\ImageSharp.Tests
$xunitArgs = "-nobuild -c Release -framework $targetFramework"
if ($targetFramework -eq "netcoreapp2.1") {
# There were issues matching the correct installed runtime if we do not specify it explicitly:
$xunitArgs += " --fx-version 2.1.0"
}
if ($is32Bit -eq "True") {
$xunitArgs += " -x86"
}
$testRunnerCmd = "dotnet xunit $xunitArgs"
}
Write-Host "running:"
Write-Host $testRunnerCmd
Write-Host "..."
Invoke-Expression $testRunnerCmd
cd $PSScriptRoot
$exitCodeOfTests = $LASTEXITCODE;
if (0 -ne ([int]$exitCodeOfTests)) {
# check submodule status
$submoduleStatus = CheckSubmoduleStatus
if ([int]$submoduleStatus -eq 1) {
# not synced
Write-Host -ForegroundColor Yellow "Check if submodules are up to date. You can use 'git submodule update' to fix this";
} elseif ($submoduleStatus -eq 2) {
# not initialized
Write-Host -ForegroundColor Yellow "Check if submodules are initialized. You can run 'git submodule init' to initialize them."
} elseif ($submoduleStatus -eq 3) {
# git not found, maybe submodules not synced?
Write-Host -ForegroundColor Yellow "Could not check if submodules are initialized correctly. Maybe git is not installed?"
} else {
#Write-Host "Submodules are up to date";
}
}
exit $exitCodeOfTests

10
src/ImageSharp.Drawing/ImageSharp.Drawing.csproj

@ -6,12 +6,13 @@
<VersionPrefix Condition="$(packageversion) == ''">0.0.1</VersionPrefix>
<Authors>SixLabors and contributors</Authors>
<TargetFrameworks>netstandard1.1;netstandard2.0</TargetFrameworks>
<LangVersion>7.2</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/ImageSharp/master/build/icons/imagesharp-logo-128.png</PackageIconUrl>
<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>
@ -36,11 +37,10 @@
<ProjectReference Include="..\ImageSharp\ImageSharp.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="SixLabors.Core" Version="1.0.0-ci0005" />
<PackageReference Include="SixLabors.Shapes.Text" Version="1.0.0-ci0005" />
<PackageReference Include="SixLabors.Shapes" Version="1.0.0-ci0005" />
<AdditionalFiles Include="..\..\stylecop.json" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.0-beta004">
<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>

7
src/ImageSharp.Drawing/Primitives/Region.cs

@ -1,6 +1,7 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Primitives
@ -19,7 +20,7 @@ namespace SixLabors.ImageSharp.Primitives
/// Gets the bounding box that entirely surrounds this region.
/// </summary>
/// <remarks>
/// This should always contains all possible points returned from <see cref="Scan(float, float[], int)"/>.
/// This should always contains all possible points returned from <see cref="Scan"/>.
/// </remarks>
public abstract Rectangle Bounds { get; }
@ -28,8 +29,8 @@ namespace SixLabors.ImageSharp.Primitives
/// </summary>
/// <param name="y">The position along the y axis to find intersections.</param>
/// <param name="buffer">The buffer.</param>
/// <param name="offset">The point in the buffer to start setting offset.</param>
/// <param name="configuration">A <see cref="Configuration"/> instance in the context of the caller.</param>
/// <returns>The number of intersections found.</returns>
public abstract int Scan(float y, float[] buffer, int offset);
public abstract int Scan(float y, Span<float> buffer, Configuration configuration);
}
}

5
src/ImageSharp.Drawing/Primitives/ShapePath.cs

@ -1,7 +1,7 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.Processing.Drawing.Pens;
using SixLabors.ImageSharp.Processing;
using SixLabors.Shapes;
namespace SixLabors.ImageSharp.Primitives
@ -16,9 +16,8 @@ namespace SixLabors.ImageSharp.Primitives
/// </summary>
/// <param name="shape">The shape.</param>
/// <param name="pen">The pen to apply to the shape.</param>
// TODO: SixLabors.shape will be moving to a Span/ReadOnlySpan based API shortly use ToArray for now.
public ShapePath(IPath shape, IPen pen)
: base(shape.GenerateOutline(pen.StrokeWidth, pen.StrokePattern.ToArray()))
: base(shape.GenerateOutline(pen.StrokeWidth, pen.StrokePattern))
{
}
}

24
src/ImageSharp.Drawing/Primitives/ShapeRegion.cs

@ -2,6 +2,10 @@
// Licensed under the Apache License, Version 2.0.
using System;
using System.Buffers;
using SixLabors.ImageSharp.Memory;
using SixLabors.Memory;
using SixLabors.Primitives;
using SixLabors.Shapes;
@ -39,21 +43,23 @@ namespace SixLabors.ImageSharp.Primitives
public override Rectangle Bounds { get; }
/// <inheritdoc/>
public override int Scan(float y, float[] buffer, int offset)
public override int Scan(float y, Span<float> buffer, Configuration configuration)
{
var start = new PointF(this.Bounds.Left - 1, y);
var end = new PointF(this.Bounds.Right + 1, y);
// TODO: This is a temporary workaround because of the lack of Span<T> API-s on IPath. We should use MemoryManager.Allocate() here!
var innerBuffer = new PointF[buffer.Length];
int count = this.Shape.FindIntersections(start, end, innerBuffer, 0);
for (int i = 0; i < count; i++)
using (IMemoryOwner<PointF> tempBuffer = configuration.MemoryAllocator.Allocate<PointF>(buffer.Length))
{
buffer[i + offset] = innerBuffer[i].X;
}
Span<PointF> innerBuffer = tempBuffer.GetSpan();
int count = this.Shape.FindIntersections(start, end, innerBuffer);
return count;
for (int i = 0; i < count; i++)
{
buffer[i] = innerBuffer[i].X;
}
return count;
}
}
}
}

25
src/ImageSharp.Drawing/Processing/Drawing/Brushes/BrushApplicator.cs → src/ImageSharp.Drawing/Processing/BrushApplicator.cs

@ -2,11 +2,14 @@
// Licensed under the Apache License, Version 2.0.
using System;
using System.Buffers;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Memory;
namespace SixLabors.ImageSharp.Processing.Drawing.Brushes
namespace SixLabors.ImageSharp.Processing
{
/// <summary>
/// primitive that converts a point in to a color for discovering the fill color based on an implementation
@ -24,10 +27,8 @@ namespace SixLabors.ImageSharp.Processing.Drawing.Brushes
internal BrushApplicator(ImageFrame<TPixel> target, GraphicsOptions options)
{
this.Target = target;
this.Options = options;
this.Blender = PixelOperations<TPixel>.Instance.GetPixelBlender(options.BlenderMode);
this.Blender = PixelOperations<TPixel>.Instance.GetPixelBlender(options);
}
/// <summary>
@ -65,13 +66,13 @@ namespace SixLabors.ImageSharp.Processing.Drawing.Brushes
/// <remarks>scanlineBuffer will be > scanlineWidth but provide and offset in case we want to share a larger buffer across runs.</remarks>
internal virtual void Apply(Span<float> scanline, int x, int y)
{
MemoryManager memoryManager = this.Target.MemoryManager;
MemoryAllocator memoryAllocator = this.Target.MemoryAllocator;
using (IBuffer<float> amountBuffer = memoryManager.Allocate<float>(scanline.Length))
using (IBuffer<TPixel> overlay = memoryManager.Allocate<TPixel>(scanline.Length))
using (IMemoryOwner<float> amountBuffer = memoryAllocator.Allocate<float>(scanline.Length))
using (IMemoryOwner<TPixel> overlay = memoryAllocator.Allocate<TPixel>(scanline.Length))
{
Span<float> amountSpan = amountBuffer.Span;
Span<TPixel> overlaySpan = overlay.Span;
Span<float> amountSpan = amountBuffer.GetSpan();
Span<TPixel> overlaySpan = overlay.GetSpan();
for (int i = 0; i < scanline.Length; i++)
{
@ -79,12 +80,16 @@ namespace SixLabors.ImageSharp.Processing.Drawing.Brushes
{
amountSpan[i] = scanline[i] * this.Options.BlendPercentage;
}
else
{
amountSpan[i] = scanline[i];
}
overlaySpan[i] = this[x + i, y];
}
Span<TPixel> destinationRow = this.Target.GetPixelRowSpan(y).Slice(x, scanline.Length);
this.Blender.Blend(memoryManager, destinationRow, destinationRow, overlaySpan, amountSpan);
this.Blender.Blend(memoryAllocator, destinationRow, destinationRow, overlaySpan, amountSpan);
}
}
}

2
src/ImageSharp.Drawing/Processing/Drawing/Brushes/Brushes.cs → src/ImageSharp.Drawing/Processing/Brushes.cs

@ -3,7 +3,7 @@
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Processing.Drawing.Brushes
namespace SixLabors.ImageSharp.Processing
{
/// <summary>
/// A collection of methods for creating generic brushes.

39
src/ImageSharp.Drawing/Processing/ColorStop{TPixel}.cs

@ -0,0 +1,39 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System.Diagnostics;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Processing
{
/// <summary>
/// A struct that defines a single color stop.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
[DebuggerDisplay("ColorStop({Ratio} -> {Color}")]
public struct ColorStop<TPixel>
where TPixel : struct, IPixel<TPixel>
{
/// <summary>
/// Initializes a new instance of the <see cref="ColorStop{TPixel}" /> struct.
/// </summary>
/// <param name="ratio">Where should it be? 0 is at the start, 1 at the end of the Gradient.</param>
/// <param name="color">What color should be used at that point?</param>
public ColorStop(float ratio, TPixel color)
{
this.Ratio = ratio;
this.Color = color;
}
/// <summary>
/// Gets the point along the defined gradient axis.
/// </summary>
public float Ratio { get; }
/// <summary>
/// Gets the color to be used.
/// </summary>
public TPixel Color { get; }
}
}

28
src/ImageSharp.Drawing/Processing/Drawing/DrawBezierExtensions.cs → src/ImageSharp.Drawing/Processing/DrawBezierExtensions.cs

@ -2,12 +2,10 @@
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Drawing.Brushes;
using SixLabors.ImageSharp.Processing.Drawing.Pens;
using SixLabors.Primitives;
using SixLabors.Shapes;
namespace SixLabors.ImageSharp.Processing.Drawing
namespace SixLabors.ImageSharp.Processing
{
/// <summary>
/// Adds extensions that allow the drawing of Bezier paths to the <see cref="Image{TPixel}"/> type.
@ -19,14 +17,14 @@ namespace SixLabors.ImageSharp.Processing.Drawing
/// </summary>
/// <typeparam name="TPixel">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="options">The options.</param>
/// <param name="brush">The brush.</param>
/// <param name="thickness">The thickness.</param>
/// <param name="points">The points.</param>
/// <param name="options">The options.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> DrawBeziers<TPixel>(this IImageProcessingContext<TPixel> source, IBrush<TPixel> brush, float thickness, PointF[] points, GraphicsOptions options)
public static IImageProcessingContext<TPixel> DrawBeziers<TPixel>(this IImageProcessingContext<TPixel> source, GraphicsOptions options, IBrush<TPixel> brush, float thickness, params PointF[] points)
where TPixel : struct, IPixel<TPixel>
=> source.Draw(new Pen<TPixel>(brush, thickness), new Path(new CubicBezierLineSegment(points)), options);
=> source.Draw(options, new Pen<TPixel>(brush, thickness), new Path(new CubicBezierLineSegment(points)));
/// <summary>
/// Draws the provided points as an open Bezier path at the provided thickness with the supplied brush
@ -37,7 +35,7 @@ namespace SixLabors.ImageSharp.Processing.Drawing
/// <param name="thickness">The thickness.</param>
/// <param name="points">The points.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> DrawBeziers<TPixel>(this IImageProcessingContext<TPixel> source, IBrush<TPixel> brush, float thickness, PointF[] points)
public static IImageProcessingContext<TPixel> DrawBeziers<TPixel>(this IImageProcessingContext<TPixel> source, IBrush<TPixel> brush, float thickness, params PointF[] points)
where TPixel : struct, IPixel<TPixel>
=> source.Draw(new Pen<TPixel>(brush, thickness), new Path(new CubicBezierLineSegment(points)));
@ -50,7 +48,7 @@ namespace SixLabors.ImageSharp.Processing.Drawing
/// <param name="thickness">The thickness.</param>
/// <param name="points">The points.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> DrawBeziers<TPixel>(this IImageProcessingContext<TPixel> source, TPixel color, float thickness, PointF[] points)
public static IImageProcessingContext<TPixel> DrawBeziers<TPixel>(this IImageProcessingContext<TPixel> source, TPixel color, float thickness, params PointF[] points)
where TPixel : struct, IPixel<TPixel>
=> source.DrawBeziers(new SolidBrush<TPixel>(color), thickness, points);
@ -59,27 +57,27 @@ namespace SixLabors.ImageSharp.Processing.Drawing
/// </summary>
/// <typeparam name="TPixel">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="options">The options.</param>
/// <param name="color">The color.</param>
/// <param name="thickness">The thickness.</param>
/// <param name="points">The points.</param>
/// <param name="options">The options.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> DrawBeziers<TPixel>(this IImageProcessingContext<TPixel> source, TPixel color, float thickness, PointF[] points, GraphicsOptions options)
public static IImageProcessingContext<TPixel> DrawBeziers<TPixel>(this IImageProcessingContext<TPixel> source, GraphicsOptions options, TPixel color, float thickness, params PointF[] points)
where TPixel : struct, IPixel<TPixel>
=> source.DrawBeziers(new SolidBrush<TPixel>(color), thickness, points, options);
=> source.DrawBeziers(options, new SolidBrush<TPixel>(color), thickness, points);
/// <summary>
/// Draws the provided points as an open Bezier path with the supplied pen
/// </summary>
/// <typeparam name="TPixel">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="options">The options.</param>
/// <param name="pen">The pen.</param>
/// <param name="points">The points.</param>
/// <param name="options">The options.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> DrawBeziers<TPixel>(this IImageProcessingContext<TPixel> source, IPen<TPixel> pen, PointF[] points, GraphicsOptions options)
public static IImageProcessingContext<TPixel> DrawBeziers<TPixel>(this IImageProcessingContext<TPixel> source, GraphicsOptions options, IPen<TPixel> pen, params PointF[] points)
where TPixel : struct, IPixel<TPixel>
=> source.Draw(pen, new Path(new CubicBezierLineSegment(points)), options);
=> source.Draw(options, pen, new Path(new CubicBezierLineSegment(points)));
/// <summary>
/// Draws the provided points as an open Bezier path with the supplied pen
@ -89,7 +87,7 @@ namespace SixLabors.ImageSharp.Processing.Drawing
/// <param name="pen">The pen.</param>
/// <param name="points">The points.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> DrawBeziers<TPixel>(this IImageProcessingContext<TPixel> source, IPen<TPixel> pen, PointF[] points)
public static IImageProcessingContext<TPixel> DrawBeziers<TPixel>(this IImageProcessingContext<TPixel> source, IPen<TPixel> pen, params PointF[] points)
where TPixel : struct, IPixel<TPixel>
=> source.Draw(pen, new Path(new CubicBezierLineSegment(points)));
}

89
src/ImageSharp.Drawing/Processing/Drawing/DrawImageExtensions.cs → src/ImageSharp.Drawing/Processing/DrawImageExtensions.cs

@ -2,10 +2,10 @@
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Drawing.Processors;
using SixLabors.ImageSharp.Processing.Processors.Drawing;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Drawing
namespace SixLabors.ImageSharp.Processing
{
/// <summary>
/// Adds extensions that allow the drawing of images to the <see cref="Image{TPixel}"/> type.
@ -20,9 +20,9 @@ namespace SixLabors.ImageSharp.Processing.Drawing
/// <param name="image">The image to blend with the currently processing image.</param>
/// <param name="opacity">The opacity of the image to blend. Must be between 0 and 1.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> Blend<TPixel>(this IImageProcessingContext<TPixel> source, Image<TPixel> image, float opacity)
public static IImageProcessingContext<TPixel> DrawImage<TPixel>(this IImageProcessingContext<TPixel> source, Image<TPixel> image, float opacity)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new DrawImageProcessor<TPixel>(image, opacity));
=> source.ApplyProcessor(new DrawImageProcessor<TPixel>(image, Point.Empty, GraphicsOptions.Default.ColorBlendingMode, GraphicsOptions.Default.AlphaCompositionMode, opacity));
/// <summary>
/// Draws the given image together with the current one by blending their pixels.
@ -30,65 +30,92 @@ namespace SixLabors.ImageSharp.Processing.Drawing
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="image">The image to blend with the currently processing image.</param>
/// <param name="blender">The blending mode.</param>
/// <param name="colorBlending">The blending mode.</param>
/// <param name="opacity">The opacity of the image to blend. Must be between 0 and 1.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> Blend<TPixel>(this IImageProcessingContext<TPixel> source, Image<TPixel> image, PixelBlenderMode blender, float opacity)
public static IImageProcessingContext<TPixel> DrawImage<TPixel>(this IImageProcessingContext<TPixel> source, Image<TPixel> image, PixelColorBlendingMode colorBlending, float opacity)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new DrawImageProcessor<TPixel>(image, opacity, blender));
=> source.ApplyProcessor(new DrawImageProcessor<TPixel>(image, Point.Empty, colorBlending, GraphicsOptions.Default.AlphaCompositionMode, opacity));
/// <summary>
/// Draws the given image together with the current one by blending their pixels.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="image">The image to blend with the currently processing image.</param>
/// <param name="options">The options, including the blending type and blending amount.</param>
/// <param name="colorBlending">The color blending mode.</param>
/// <param name="alphaComposition">The alpha composition mode.</param>
/// <param name="opacity">The opacity of the image to blend. Must be between 0 and 1.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> Blend<TPixel>(this IImageProcessingContext<TPixel> source, Image<TPixel> image, GraphicsOptions options)
public static IImageProcessingContext<TPixel> DrawImage<TPixel>(this IImageProcessingContext<TPixel> source, Image<TPixel> image, PixelColorBlendingMode colorBlending, PixelAlphaCompositionMode alphaComposition, float opacity)
where TPixel : struct, IPixel<TPixel>
{
return source.ApplyProcessor(new DrawImageProcessor<TPixel>(image, options));
}
=> source.ApplyProcessor(new DrawImageProcessor<TPixel>(image, Point.Empty, colorBlending, alphaComposition, opacity));
/// <summary>
/// Draws the given image together with the current one by blending their pixels.
/// </summary>
/// <param name="source">The image this method extends.</param>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="image">The image to blend with the currently processing image.</param>
/// <param name="options">The options, including the blending type and blending amount.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> DrawImage<TPixel>(this IImageProcessingContext<TPixel> source, Image<TPixel> image, GraphicsOptions options)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new DrawImageProcessor<TPixel>(image, Point.Empty, options.ColorBlendingMode, options.AlphaCompositionMode, options.BlendPercentage));
/// <summary>
/// Draws the given image together with the current one by blending their pixels.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="opacity">The opacity of the image to blend. Must be between 0 and 1.</param>
/// <param name="source">The image this method extends.</param>
/// <param name="image">The image to blend with the currently processing image.</param>
/// <param name="location">The location to draw the blended image.</param>
/// <param name="opacity">The opacity of the image to blend. Must be between 0 and 1.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> DrawImage<TPixel>(this IImageProcessingContext<TPixel> source, Image<TPixel> image, float opacity, Point location)
public static IImageProcessingContext<TPixel> DrawImage<TPixel>(this IImageProcessingContext<TPixel> source, Image<TPixel> image, Point location, float opacity)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new DrawImageProcessor<TPixel>(image, location, opacity));
=> source.ApplyProcessor(new DrawImageProcessor<TPixel>(image, location, GraphicsOptions.Default.ColorBlendingMode, GraphicsOptions.Default.AlphaCompositionMode, opacity));
/// <summary>
/// Draws the given image together with the current one by blending their pixels.
/// </summary>
/// <param name="source">The image this method extends.</param>
/// <param name="image">The image to blend with the currently processing image.</param>
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="blender">The type of bending to apply.</param>
/// <param name="opacity">The opacity of the image to blend. Must be between 0 and 1.</param>
/// <param name="source">The image this method extends.</param>
/// <param name="image">The image to blend with the currently processing image.</param>
/// <param name="location">The location to draw the blended image.</param>
/// <param name="colorBlending">The color blending to apply.</param>
/// <param name="opacity">The opacity of the image to blend. Must be between 0 and 1.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> DrawImage<TPixel>(this IImageProcessingContext<TPixel> source, Image<TPixel> image, PixelBlenderMode blender, float opacity, Point location)
public static IImageProcessingContext<TPixel> DrawImage<TPixel>(this IImageProcessingContext<TPixel> source, Image<TPixel> image, Point location, PixelColorBlendingMode colorBlending, float opacity)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new DrawImageProcessor<TPixel>(image, location, opacity, blender));
=> source.ApplyProcessor(new DrawImageProcessor<TPixel>(image, location, colorBlending, GraphicsOptions.Default.AlphaCompositionMode, opacity));
/// <summary>
/// Draws the given image together with the current one by blending their pixels.
/// </summary>
/// <param name="source">The image this method extends.</param>
/// <param name="image">The image to blend with the currently processing image.</param>
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="image">The image to blend with the currently processing image.</param>
/// <param name="location">The location to draw the blended image.</param>
/// <param name="colorBlending">The color blending to apply.</param>
/// <param name="alphaComposition">The alpha composition mode.</param>
/// <param name="opacity">The opacity of the image to blend. Must be between 0 and 1.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> DrawImage<TPixel>(this IImageProcessingContext<TPixel> source, Image<TPixel> image, Point location, PixelColorBlendingMode colorBlending, PixelAlphaCompositionMode alphaComposition, float opacity)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new DrawImageProcessor<TPixel>(image, location, colorBlending, alphaComposition, opacity));
/// <summary>
/// Draws the given image together with the current one by blending their pixels.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="image">The image to blend with the currently processing image.</param>
/// <param name="location">The location to draw the blended image.</param>
/// <param name="options">The options containing the blend mode and opacity.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> DrawImage<TPixel>(this IImageProcessingContext<TPixel> source, Image<TPixel> image, Point location, GraphicsOptions options)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new DrawImageProcessor<TPixel>(image, location, options));
=> source.ApplyProcessor(new DrawImageProcessor<TPixel>(image, location, options.ColorBlendingMode, options.AlphaCompositionMode, options.BlendPercentage));
}
}

30
src/ImageSharp.Drawing/Processing/Drawing/DrawLineExtensions.cs → src/ImageSharp.Drawing/Processing/DrawLineExtensions.cs

@ -2,12 +2,10 @@
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Drawing.Brushes;
using SixLabors.ImageSharp.Processing.Drawing.Pens;
using SixLabors.Primitives;
using SixLabors.Shapes;
namespace SixLabors.ImageSharp.Processing.Drawing
namespace SixLabors.ImageSharp.Processing
{
/// <summary>
/// Adds extensions that allow the drawing of lines to the <see cref="Image{TPixel}"/> type.
@ -19,14 +17,14 @@ namespace SixLabors.ImageSharp.Processing.Drawing
/// </summary>
/// <typeparam name="TPixel">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="options">The options.</param>
/// <param name="brush">The brush.</param>
/// <param name="thickness">The thickness.</param>
/// <param name="points">The points.</param>
/// <param name="options">The options.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> DrawLines<TPixel>(this IImageProcessingContext<TPixel> source, IBrush<TPixel> brush, float thickness, PointF[] points, GraphicsOptions options)
public static IImageProcessingContext<TPixel> DrawLines<TPixel>(this IImageProcessingContext<TPixel> source, GraphicsOptions options, IBrush<TPixel> brush, float thickness, params PointF[] points)
where TPixel : struct, IPixel<TPixel>
=> source.Draw(new Pen<TPixel>(brush, thickness), new Path(new LinearLineSegment(points)), options);
=> source.Draw(options, new Pen<TPixel>(brush, thickness), new Path(new LinearLineSegment(points)));
/// <summary>
/// Draws the provided Points as an open Linear path at the provided thickness with the supplied brush
@ -37,7 +35,7 @@ namespace SixLabors.ImageSharp.Processing.Drawing
/// <param name="thickness">The thickness.</param>
/// <param name="points">The points.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> DrawLines<TPixel>(this IImageProcessingContext<TPixel> source, IBrush<TPixel> brush, float thickness, PointF[] points)
public static IImageProcessingContext<TPixel> DrawLines<TPixel>(this IImageProcessingContext<TPixel> source, IBrush<TPixel> brush, float thickness, params PointF[] points)
where TPixel : struct, IPixel<TPixel>
=> source.Draw(new Pen<TPixel>(brush, thickness), new Path(new LinearLineSegment(points)));
@ -50,7 +48,7 @@ namespace SixLabors.ImageSharp.Processing.Drawing
/// <param name="thickness">The thickness.</param>
/// <param name="points">The points.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> DrawLines<TPixel>(this IImageProcessingContext<TPixel> source, TPixel color, float thickness, PointF[] points)
public static IImageProcessingContext<TPixel> DrawLines<TPixel>(this IImageProcessingContext<TPixel> source, TPixel color, float thickness, params PointF[] points)
where TPixel : struct, IPixel<TPixel>
=> source.DrawLines(new SolidBrush<TPixel>(color), thickness, points);
@ -59,27 +57,27 @@ namespace SixLabors.ImageSharp.Processing.Drawing
/// </summary>
/// <typeparam name="TPixel">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="options">The options.</param>
/// <param name="color">The color.</param>
/// <param name="thickness">The thickness.</param>
/// <param name="points">The points.</param>
/// <param name="options">The options.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>>
public static IImageProcessingContext<TPixel> DrawLines<TPixel>(this IImageProcessingContext<TPixel> source, TPixel color, float thickness, PointF[] points, GraphicsOptions options)
public static IImageProcessingContext<TPixel> DrawLines<TPixel>(this IImageProcessingContext<TPixel> source, GraphicsOptions options, TPixel color, float thickness, params PointF[] points)
where TPixel : struct, IPixel<TPixel>
=> source.DrawLines(new SolidBrush<TPixel>(color), thickness, points, options);
=> source.DrawLines(options, new SolidBrush<TPixel>(color), thickness, points);
/// <summary>
/// Draws the provided Points as an open Linear path with the supplied pen
/// </summary>
/// <typeparam name="TPixel">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="options">The options.</param>
/// <param name="pen">The pen.</param>
/// <param name="points">The points.</param>
/// <param name="options">The options.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> DrawLines<TPixel>(this IImageProcessingContext<TPixel> source, IPen<TPixel> pen, PointF[] points, GraphicsOptions options)
public static IImageProcessingContext<TPixel> DrawLines<TPixel>(this IImageProcessingContext<TPixel> source, GraphicsOptions options, IPen<TPixel> pen, params PointF[] points)
where TPixel : struct, IPixel<TPixel>
=> source.Draw(pen, new Path(new LinearLineSegment(points)), options);
=> source.Draw(options, pen, new Path(new LinearLineSegment(points)));
/// <summary>
/// Draws the provided Points as an open Linear path with the supplied pen
@ -89,8 +87,8 @@ namespace SixLabors.ImageSharp.Processing.Drawing
/// <param name="pen">The pen.</param>
/// <param name="points">The points.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> DrawLines<TPixel>(this IImageProcessingContext<TPixel> source, IPen<TPixel> pen, PointF[] points)
public static IImageProcessingContext<TPixel> DrawLines<TPixel>(this IImageProcessingContext<TPixel> source, IPen<TPixel> pen, params PointF[] points)
where TPixel : struct, IPixel<TPixel>
=> source.Draw(pen, new Path(new LinearLineSegment(points)));
}
}
}

24
src/ImageSharp.Drawing/Processing/Drawing/DrawPathCollectionExtensions.cs → src/ImageSharp.Drawing/Processing/DrawPathCollectionExtensions.cs

@ -2,11 +2,9 @@
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Drawing.Brushes;
using SixLabors.ImageSharp.Processing.Drawing.Pens;
using SixLabors.Shapes;
namespace SixLabors.ImageSharp.Processing.Drawing
namespace SixLabors.ImageSharp.Processing
{
/// <summary>
/// Adds extensions that allow the drawing of collections of polygon outlines to the <see cref="Image{TPixel}"/> type.
@ -18,16 +16,16 @@ namespace SixLabors.ImageSharp.Processing.Drawing
/// </summary>
/// <typeparam name="TPixel">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="options">The options.</param>
/// <param name="pen">The pen.</param>
/// <param name="paths">The paths.</param>
/// <param name="options">The options.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> Draw<TPixel>(this IImageProcessingContext<TPixel> source, IPen<TPixel> pen, IPathCollection paths, GraphicsOptions options)
public static IImageProcessingContext<TPixel> Draw<TPixel>(this IImageProcessingContext<TPixel> source, GraphicsOptions options, IPen<TPixel> pen, IPathCollection paths)
where TPixel : struct, IPixel<TPixel>
{
foreach (IPath path in paths)
{
source.Draw(pen, path, options);
source.Draw(options, pen, path);
}
return source;
@ -43,21 +41,21 @@ namespace SixLabors.ImageSharp.Processing.Drawing
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> Draw<TPixel>(this IImageProcessingContext<TPixel> source, IPen<TPixel> pen, IPathCollection paths)
where TPixel : struct, IPixel<TPixel>
=> source.Draw(pen, paths, GraphicsOptions.Default);
=> source.Draw(GraphicsOptions.Default, pen, paths);
/// <summary>
/// Draws the outline of the polygon with the provided brush at the provided thickness.
/// </summary>
/// <typeparam name="TPixel">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="options">The options.</param>
/// <param name="brush">The brush.</param>
/// <param name="thickness">The thickness.</param>
/// <param name="paths">The shapes.</param>
/// <param name="options">The options.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> Draw<TPixel>(this IImageProcessingContext<TPixel> source, IBrush<TPixel> brush, float thickness, IPathCollection paths, GraphicsOptions options)
public static IImageProcessingContext<TPixel> Draw<TPixel>(this IImageProcessingContext<TPixel> source, GraphicsOptions options, IBrush<TPixel> brush, float thickness, IPathCollection paths)
where TPixel : struct, IPixel<TPixel>
=> source.Draw(new Pen<TPixel>(brush, thickness), paths, options);
=> source.Draw(options, new Pen<TPixel>(brush, thickness), paths);
/// <summary>
/// Draws the outline of the polygon with the provided brush at the provided thickness.
@ -77,14 +75,14 @@ namespace SixLabors.ImageSharp.Processing.Drawing
/// </summary>
/// <typeparam name="TPixel">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="options">The options.</param>
/// <param name="color">The color.</param>
/// <param name="thickness">The thickness.</param>
/// <param name="paths">The paths.</param>
/// <param name="options">The options.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> Draw<TPixel>(this IImageProcessingContext<TPixel> source, TPixel color, float thickness, IPathCollection paths, GraphicsOptions options)
public static IImageProcessingContext<TPixel> Draw<TPixel>(this IImageProcessingContext<TPixel> source, GraphicsOptions options, TPixel color, float thickness, IPathCollection paths)
where TPixel : struct, IPixel<TPixel>
=> source.Draw(new SolidBrush<TPixel>(color), thickness, paths, options);
=> source.Draw(options, new SolidBrush<TPixel>(color), thickness, paths);
/// <summary>
/// Draws the outline of the polygon with the provided brush at the provided thickness.

26
src/ImageSharp.Drawing/Processing/Drawing/DrawPathExtensions.cs → src/ImageSharp.Drawing/Processing/DrawPathExtensions.cs

@ -3,11 +3,9 @@
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Primitives;
using SixLabors.ImageSharp.Processing.Drawing.Brushes;
using SixLabors.ImageSharp.Processing.Drawing.Pens;
using SixLabors.Shapes;
namespace SixLabors.ImageSharp.Processing.Drawing
namespace SixLabors.ImageSharp.Processing
{
/// <summary>
/// Adds extensions that allow the drawing of polygon outlines to the <see cref="Image{TPixel}"/> type.
@ -19,13 +17,13 @@ namespace SixLabors.ImageSharp.Processing.Drawing
/// </summary>
/// <typeparam name="TPixel">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="options">The options.</param>
/// <param name="pen">The pen.</param>
/// <param name="path">The path.</param>
/// <param name="options">The options.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> Draw<TPixel>(this IImageProcessingContext<TPixel> source, IPen<TPixel> pen, IPath path, GraphicsOptions options)
public static IImageProcessingContext<TPixel> Draw<TPixel>(this IImageProcessingContext<TPixel> source, GraphicsOptions options, IPen<TPixel> pen, IPath path)
where TPixel : struct, IPixel<TPixel>
=> source.Fill(pen.StrokeFill, new ShapePath(path, pen), options);
=> source.Fill(options, pen.StrokeFill, new ShapePath(path, pen));
/// <summary>
/// Draws the outline of the polygon with the provided pen.
@ -37,21 +35,21 @@ namespace SixLabors.ImageSharp.Processing.Drawing
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> Draw<TPixel>(this IImageProcessingContext<TPixel> source, IPen<TPixel> pen, IPath path)
where TPixel : struct, IPixel<TPixel>
=> source.Draw(pen, path, GraphicsOptions.Default);
=> source.Draw(GraphicsOptions.Default, pen, path);
/// <summary>
/// Draws the outline of the polygon with the provided brush at the provided thickness.
/// </summary>
/// <typeparam name="TPixel">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="options">The options.</param>
/// <param name="brush">The brush.</param>
/// <param name="thickness">The thickness.</param>
/// <param name="path">The shape.</param>
/// <param name="options">The options.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> Draw<TPixel>(this IImageProcessingContext<TPixel> source, IBrush<TPixel> brush, float thickness, IPath path, GraphicsOptions options)
public static IImageProcessingContext<TPixel> Draw<TPixel>(this IImageProcessingContext<TPixel> source, GraphicsOptions options, IBrush<TPixel> brush, float thickness, IPath path)
where TPixel : struct, IPixel<TPixel>
=> source.Draw(new Pen<TPixel>(brush, thickness), path, options);
=> source.Draw(options, new Pen<TPixel>(brush, thickness), path);
/// <summary>
/// Draws the outline of the polygon with the provided brush at the provided thickness.
@ -71,14 +69,14 @@ namespace SixLabors.ImageSharp.Processing.Drawing
/// </summary>
/// <typeparam name="TPixel">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="options">The options.</param>
/// <param name="color">The color.</param>
/// <param name="thickness">The thickness.</param>
/// <param name="path">The path.</param>
/// <param name="options">The options.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> Draw<TPixel>(this IImageProcessingContext<TPixel> source, TPixel color, float thickness, IPath path, GraphicsOptions options)
public static IImageProcessingContext<TPixel> Draw<TPixel>(this IImageProcessingContext<TPixel> source, GraphicsOptions options, TPixel color, float thickness, IPath path)
where TPixel : struct, IPixel<TPixel>
=> source.Draw(new SolidBrush<TPixel>(color), thickness, path, options);
=> source.Draw(options, new SolidBrush<TPixel>(color), thickness, path);
/// <summary>
/// Draws the outline of the polygon with the provided brush at the provided thickness.
@ -93,4 +91,4 @@ namespace SixLabors.ImageSharp.Processing.Drawing
where TPixel : struct, IPixel<TPixel>
=> source.Draw(new SolidBrush<TPixel>(color), thickness, path);
}
}
}

30
src/ImageSharp.Drawing/Processing/Drawing/DrawPolygonExtensions.cs → src/ImageSharp.Drawing/Processing/DrawPolygonExtensions.cs

@ -2,12 +2,10 @@
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Drawing.Brushes;
using SixLabors.ImageSharp.Processing.Drawing.Pens;
using SixLabors.Primitives;
using SixLabors.Shapes;
namespace SixLabors.ImageSharp.Processing.Drawing
namespace SixLabors.ImageSharp.Processing
{
/// <summary>
/// Adds extensions that allow the drawing of closed linear polygons to the <see cref="Image{TPixel}"/> type.
@ -19,14 +17,14 @@ namespace SixLabors.ImageSharp.Processing.Drawing
/// </summary>
/// <typeparam name="TPixel">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="options">The options.</param>
/// <param name="brush">The brush.</param>
/// <param name="thickness">The thickness.</param>
/// <param name="points">The points.</param>
/// <param name="options">The options.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> DrawPolygon<TPixel>(this IImageProcessingContext<TPixel> source, IBrush<TPixel> brush, float thickness, PointF[] points, GraphicsOptions options)
public static IImageProcessingContext<TPixel> DrawPolygon<TPixel>(this IImageProcessingContext<TPixel> source, GraphicsOptions options, IBrush<TPixel> brush, float thickness, params PointF[] points)
where TPixel : struct, IPixel<TPixel>
=> source.Draw(new Pen<TPixel>(brush, thickness), new Polygon(new LinearLineSegment(points)), options);
=> source.Draw(options, new Pen<TPixel>(brush, thickness), new Polygon(new LinearLineSegment(points)));
/// <summary>
/// Draws the provided Points as a closed Linear Polygon with the provided brush at the provided thickness.
@ -37,7 +35,7 @@ namespace SixLabors.ImageSharp.Processing.Drawing
/// <param name="thickness">The thickness.</param>
/// <param name="points">The points.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> DrawPolygon<TPixel>(this IImageProcessingContext<TPixel> source, IBrush<TPixel> brush, float thickness, PointF[] points)
public static IImageProcessingContext<TPixel> DrawPolygon<TPixel>(this IImageProcessingContext<TPixel> source, IBrush<TPixel> brush, float thickness, params PointF[] points)
where TPixel : struct, IPixel<TPixel>
=> source.Draw(new Pen<TPixel>(brush, thickness), new Polygon(new LinearLineSegment(points)));
@ -50,7 +48,7 @@ namespace SixLabors.ImageSharp.Processing.Drawing
/// <param name="thickness">The thickness.</param>
/// <param name="points">The points.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> DrawPolygon<TPixel>(this IImageProcessingContext<TPixel> source, TPixel color, float thickness, PointF[] points)
public static IImageProcessingContext<TPixel> DrawPolygon<TPixel>(this IImageProcessingContext<TPixel> source, TPixel color, float thickness, params PointF[] points)
where TPixel : struct, IPixel<TPixel>
=> source.DrawPolygon(new SolidBrush<TPixel>(color), thickness, points);
@ -59,14 +57,14 @@ namespace SixLabors.ImageSharp.Processing.Drawing
/// </summary>
/// <typeparam name="TPixel">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="options">The options.</param>
/// <param name="color">The color.</param>
/// <param name="thickness">The thickness.</param>
/// <param name="points">The points.</param>
/// <param name="options">The options.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> DrawPolygon<TPixel>(this IImageProcessingContext<TPixel> source, TPixel color, float thickness, PointF[] points, GraphicsOptions options)
public static IImageProcessingContext<TPixel> DrawPolygon<TPixel>(this IImageProcessingContext<TPixel> source, GraphicsOptions options, TPixel color, float thickness, params PointF[] points)
where TPixel : struct, IPixel<TPixel>
=> source.DrawPolygon(new SolidBrush<TPixel>(color), thickness, points, options);
=> source.DrawPolygon(options, new SolidBrush<TPixel>(color), thickness, points);
/// <summary>
/// Draws the provided Points as a closed Linear Polygon with the provided Pen.
@ -76,21 +74,21 @@ namespace SixLabors.ImageSharp.Processing.Drawing
/// <param name="pen">The pen.</param>
/// <param name="points">The points.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> DrawPolygon<TPixel>(this IImageProcessingContext<TPixel> source, IPen<TPixel> pen, PointF[] points)
public static IImageProcessingContext<TPixel> DrawPolygon<TPixel>(this IImageProcessingContext<TPixel> source, IPen<TPixel> pen, params PointF[] points)
where TPixel : struct, IPixel<TPixel>
=> source.Draw(pen, new Polygon(new LinearLineSegment(points)), GraphicsOptions.Default);
=> source.Draw(GraphicsOptions.Default, pen, new Polygon(new LinearLineSegment(points)));
/// <summary>
/// Draws the provided Points as a closed Linear Polygon with the provided Pen.
/// </summary>
/// <typeparam name="TPixel">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="options">The options.</param>
/// <param name="pen">The pen.</param>
/// <param name="points">The points.</param>
/// <param name="options">The options.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> DrawPolygon<TPixel>(this IImageProcessingContext<TPixel> source, IPen<TPixel> pen, PointF[] points, GraphicsOptions options)
public static IImageProcessingContext<TPixel> DrawPolygon<TPixel>(this IImageProcessingContext<TPixel> source, GraphicsOptions options, IPen<TPixel> pen, params PointF[] points)
where TPixel : struct, IPixel<TPixel>
=> source.Draw(pen, new Polygon(new LinearLineSegment(points)), options);
=> source.Draw(options, pen, new Polygon(new LinearLineSegment(points)));
}
}

24
src/ImageSharp.Drawing/Processing/Drawing/DrawRectangleExtensions.cs → src/ImageSharp.Drawing/Processing/DrawRectangleExtensions.cs

@ -2,12 +2,10 @@
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Drawing.Brushes;
using SixLabors.ImageSharp.Processing.Drawing.Pens;
using SixLabors.Primitives;
using SixLabors.Shapes;
namespace SixLabors.ImageSharp.Processing.Drawing
namespace SixLabors.ImageSharp.Processing
{
/// <summary>
/// Adds extensions that allow the drawing of rectangles to the <see cref="Image{TPixel}"/> type.
@ -19,13 +17,13 @@ namespace SixLabors.ImageSharp.Processing.Drawing
/// </summary>
/// <typeparam name="TPixel">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="options">The options.</param>
/// <param name="pen">The pen.</param>
/// <param name="shape">The shape.</param>
/// <param name="options">The options.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> Draw<TPixel>(this IImageProcessingContext<TPixel> source, IPen<TPixel> pen, RectangleF shape, GraphicsOptions options)
public static IImageProcessingContext<TPixel> Draw<TPixel>(this IImageProcessingContext<TPixel> source, GraphicsOptions options, IPen<TPixel> pen, RectangleF shape)
where TPixel : struct, IPixel<TPixel>
=> source.Draw(pen, new RectangularePolygon(shape.X, shape.Y, shape.Width, shape.Height), options);
=> source.Draw(options, pen, new RectangularPolygon(shape.X, shape.Y, shape.Width, shape.Height));
/// <summary>
/// Draws the outline of the rectangle with the provided pen.
@ -37,21 +35,21 @@ namespace SixLabors.ImageSharp.Processing.Drawing
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> Draw<TPixel>(this IImageProcessingContext<TPixel> source, IPen<TPixel> pen, RectangleF shape)
where TPixel : struct, IPixel<TPixel>
=> source.Draw(pen, shape, GraphicsOptions.Default);
=> source.Draw(GraphicsOptions.Default, pen, shape);
/// <summary>
/// Draws the outline of the rectangle with the provided brush at the provided thickness.
/// </summary>
/// <typeparam name="TPixel">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="options">The options.</param>
/// <param name="brush">The brush.</param>
/// <param name="thickness">The thickness.</param>
/// <param name="shape">The shape.</param>
/// <param name="options">The options.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> Draw<TPixel>(this IImageProcessingContext<TPixel> source, IBrush<TPixel> brush, float thickness, RectangleF shape, GraphicsOptions options)
public static IImageProcessingContext<TPixel> Draw<TPixel>(this IImageProcessingContext<TPixel> source, GraphicsOptions options, IBrush<TPixel> brush, float thickness, RectangleF shape)
where TPixel : struct, IPixel<TPixel>
=> source.Draw(new Pen<TPixel>(brush, thickness), shape, options);
=> source.Draw(options, new Pen<TPixel>(brush, thickness), shape);
/// <summary>
/// Draws the outline of the rectangle with the provided brush at the provided thickness.
@ -71,14 +69,14 @@ namespace SixLabors.ImageSharp.Processing.Drawing
/// </summary>
/// <typeparam name="TPixel">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="options">The options.</param>
/// <param name="color">The color.</param>
/// <param name="thickness">The thickness.</param>
/// <param name="shape">The shape.</param>
/// <param name="options">The options.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> Draw<TPixel>(this IImageProcessingContext<TPixel> source, TPixel color, float thickness, RectangleF shape, GraphicsOptions options)
public static IImageProcessingContext<TPixel> Draw<TPixel>(this IImageProcessingContext<TPixel> source, GraphicsOptions options, TPixel color, float thickness, RectangleF shape)
where TPixel : struct, IPixel<TPixel>
=> source.Draw(new SolidBrush<TPixel>(color), thickness, shape, options);
=> source.Draw(options, new SolidBrush<TPixel>(color), thickness, shape);
/// <summary>
/// Draws the outline of the rectangle with the provided brush at the provided thickness.

70
src/ImageSharp.Drawing/Processing/Text/DrawTextExtensions.cs → src/ImageSharp.Drawing/Processing/DrawTextExtensions.cs

@ -3,21 +3,16 @@
using SixLabors.Fonts;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Drawing;
using SixLabors.ImageSharp.Processing.Drawing.Brushes;
using SixLabors.ImageSharp.Processing.Drawing.Pens;
using SixLabors.ImageSharp.Processing.Processors.Text;
using SixLabors.Primitives;
using SixLabors.Shapes;
namespace SixLabors.ImageSharp.Processing.Text
namespace SixLabors.ImageSharp.Processing
{
/// <summary>
/// Adds extensions that allow the drawing of text to the <see cref="Image{TPixel}"/> type.
/// </summary>
public static partial class DrawTextExtensions
public static class DrawTextExtensions
{
private static readonly int DefaultTextDpi = 72;
/// <summary>
/// Draws the text onto the the image filled via the brush.
/// </summary>
@ -32,24 +27,24 @@ namespace SixLabors.ImageSharp.Processing.Text
/// </returns>
public static IImageProcessingContext<TPixel> DrawText<TPixel>(this IImageProcessingContext<TPixel> source, string text, Font font, TPixel color, PointF location)
where TPixel : struct, IPixel<TPixel>
=> source.DrawText(text, font, color, location, TextGraphicsOptions.Default);
=> source.DrawText(TextGraphicsOptions.Default, text, font, color, location);
/// <summary>
/// Draws the text onto the the image filled via the brush.
/// </summary>
/// <typeparam name="TPixel">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="options">The options.</param>
/// <param name="text">The text.</param>
/// <param name="font">The font.</param>
/// <param name="color">The color.</param>
/// <param name="location">The location.</param>
/// <param name="options">The options.</param>
/// <returns>
/// The <see cref="Image{TPixel}" />.
/// </returns>
public static IImageProcessingContext<TPixel> DrawText<TPixel>(this IImageProcessingContext<TPixel> source, string text, Font font, TPixel color, PointF location, TextGraphicsOptions options)
public static IImageProcessingContext<TPixel> DrawText<TPixel>(this IImageProcessingContext<TPixel> source, TextGraphicsOptions options, string text, Font font, TPixel color, PointF location)
where TPixel : struct, IPixel<TPixel>
=> source.DrawText(text, font, Brushes.Solid(color), null, location, options);
=> source.DrawText(options, text, font, Brushes.Solid(color), null, location);
/// <summary>
/// Draws the text onto the the image filled via the brush.
@ -65,24 +60,24 @@ namespace SixLabors.ImageSharp.Processing.Text
/// </returns>
public static IImageProcessingContext<TPixel> DrawText<TPixel>(this IImageProcessingContext<TPixel> source, string text, Font font, IBrush<TPixel> brush, PointF location)
where TPixel : struct, IPixel<TPixel>
=> source.DrawText(text, font, brush, location, TextGraphicsOptions.Default);
=> source.DrawText(TextGraphicsOptions.Default, text, font, brush, location);
/// <summary>
/// Draws the text onto the the image filled via the brush.
/// </summary>
/// <typeparam name="TPixel">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="options">The options.</param>
/// <param name="text">The text.</param>
/// <param name="font">The font.</param>
/// <param name="brush">The brush.</param>
/// <param name="location">The location.</param>
/// <param name="options">The options.</param>
/// <returns>
/// The <see cref="Image{TPixel}" />.
/// </returns>
public static IImageProcessingContext<TPixel> DrawText<TPixel>(this IImageProcessingContext<TPixel> source, string text, Font font, IBrush<TPixel> brush, PointF location, TextGraphicsOptions options)
public static IImageProcessingContext<TPixel> DrawText<TPixel>(this IImageProcessingContext<TPixel> source, TextGraphicsOptions options, string text, Font font, IBrush<TPixel> brush, PointF location)
where TPixel : struct, IPixel<TPixel>
=> source.DrawText(text, font, brush, null, location, options);
=> source.DrawText(options, text, font, brush, null, location);
/// <summary>
/// Draws the text onto the the image outlined via the pen.
@ -98,24 +93,24 @@ namespace SixLabors.ImageSharp.Processing.Text
/// </returns>
public static IImageProcessingContext<TPixel> DrawText<TPixel>(this IImageProcessingContext<TPixel> source, string text, Font font, IPen<TPixel> pen, PointF location)
where TPixel : struct, IPixel<TPixel>
=> source.DrawText(text, font, pen, location, TextGraphicsOptions.Default);
=> source.DrawText(TextGraphicsOptions.Default, text, font, pen, location);
/// <summary>
/// Draws the text onto the the image outlined via the pen.
/// </summary>
/// <typeparam name="TPixel">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="options">The options.</param>
/// <param name="text">The text.</param>
/// <param name="font">The font.</param>
/// <param name="pen">The pen.</param>
/// <param name="location">The location.</param>
/// <param name="options">The options.</param>
/// <returns>
/// The <see cref="Image{TPixel}" />.
/// </returns>
public static IImageProcessingContext<TPixel> DrawText<TPixel>(this IImageProcessingContext<TPixel> source, string text, Font font, IPen<TPixel> pen, PointF location, TextGraphicsOptions options)
public static IImageProcessingContext<TPixel> DrawText<TPixel>(this IImageProcessingContext<TPixel> source, TextGraphicsOptions options, string text, Font font, IPen<TPixel> pen, PointF location)
where TPixel : struct, IPixel<TPixel>
=> source.DrawText(text, font, null, pen, location, options);
=> source.DrawText(options, text, font, null, pen, location);
/// <summary>
/// Draws the text onto the the image filled via the brush then outlined via the pen.
@ -132,51 +127,24 @@ namespace SixLabors.ImageSharp.Processing.Text
/// </returns>
public static IImageProcessingContext<TPixel> DrawText<TPixel>(this IImageProcessingContext<TPixel> source, string text, Font font, IBrush<TPixel> brush, IPen<TPixel> pen, PointF location)
where TPixel : struct, IPixel<TPixel>
=> source.DrawText(text, font, brush, pen, location, TextGraphicsOptions.Default);
=> source.DrawText(TextGraphicsOptions.Default, text, font, brush, pen, location);
/// <summary>
/// Draws the text using the default resolution of <value>72dpi</value> onto the the image filled via the brush then outlined via the pen.
/// </summary>
/// <typeparam name="TPixel">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="options">The options.</param>
/// <param name="text">The text.</param>
/// <param name="font">The font.</param>
/// <param name="brush">The brush.</param>
/// <param name="pen">The pen.</param>
/// <param name="location">The location.</param>
/// <param name="options">The options.</param>
/// <returns>
/// The <see cref="Image{TPixel}" />.
/// </returns>
public static IImageProcessingContext<TPixel> DrawText<TPixel>(this IImageProcessingContext<TPixel> source, string text, Font font, IBrush<TPixel> brush, IPen<TPixel> pen, PointF location, TextGraphicsOptions options)
public static IImageProcessingContext<TPixel> DrawText<TPixel>(this IImageProcessingContext<TPixel> source, TextGraphicsOptions options, string text, Font font, IBrush<TPixel> brush, IPen<TPixel> pen, PointF location)
where TPixel : struct, IPixel<TPixel>
{
float dpiX = DefaultTextDpi;
float dpiY = DefaultTextDpi;
var style = new RendererOptions(font, dpiX, dpiY, location)
{
ApplyKerning = options.ApplyKerning,
TabWidth = options.TabWidth,
WrappingWidth = options.WrapTextWidth,
HorizontalAlignment = options.HorizontalAlignment,
VerticalAlignment = options.VerticalAlignment
};
IPathCollection glyphs = TextBuilder.GenerateGlyphs(text, style);
var pathOptions = (GraphicsOptions)options;
if (brush != null)
{
source.Fill(brush, glyphs, pathOptions);
}
if (pen != null)
{
source.Draw(pen, glyphs, pathOptions);
}
return source;
}
=> source.ApplyProcessor(new DrawTextProcessor<TPixel>(options, text, font, brush, pen, location));
}
}

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

@ -1,155 +0,0 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Threading.Tasks;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Processors;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Drawing.Processors
{
/// <summary>
/// Combines two images together by blending the pixels.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
internal class DrawImageProcessor<TPixel> : ImageProcessor<TPixel>
where TPixel : struct, IPixel<TPixel>
{
/// <summary>
/// Initializes a new instance of the <see cref="DrawImageProcessor{TPixel}"/> class.
/// </summary>
/// <param name="image">The image to blend with the currently processing image.</param>
/// <param name="opacity">The opacity of the image to blend. Must be between 0 and 1.</param>
public DrawImageProcessor(Image<TPixel> image, float opacity)
: this(image, Point.Empty, opacity)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="DrawImageProcessor{TPixel}"/> class.
/// </summary>
/// <param name="image">The image to blend with the currently processing image.</param>
/// <param name="options">
/// The options containing the opacity of the image to blend and blending mode.
/// Opacity must be between 0 and 1.
/// </param>
public DrawImageProcessor(Image<TPixel> image, GraphicsOptions options)
: this(image, Point.Empty, options)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="DrawImageProcessor{TPixel}"/> class.
/// </summary>
/// <param name="image">The image to blend with the currently processing image.</param>
/// <param name="location">The location to draw the blended image.</param>
/// <param name="opacity">The opacity of the image to blend. Must be between 0 and 1.</param>
public DrawImageProcessor(Image<TPixel> image, Point location, float opacity)
: this(image, location, opacity, GraphicsOptions.Default.BlenderMode)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="DrawImageProcessor{TPixel}"/> class.
/// </summary>
/// <param name="image">The image to blend with the currently processing image.</param>
/// <param name="location">The location to draw the blended image.</param>
/// <param name="options">
/// The options containing the opacity of the image to blend and blending mode.
/// Opacity must be between 0 and 1.
/// </param>
public DrawImageProcessor(Image<TPixel> image, Point location, GraphicsOptions options)
: this(image, location, options.BlendPercentage, options.BlenderMode)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="DrawImageProcessor{TPixel}"/> class.
/// </summary>
/// <param name="image">The image to blend with the currently processing image.</param>
/// <param name="opacity">The opacity of the image to blend. Must be between 0 and 1.</param>
/// <param name="blenderMode">The blending mode to use when drawing the image.</param>
public DrawImageProcessor(Image<TPixel> image, float opacity, PixelBlenderMode blenderMode)
: this(image, Point.Empty, opacity, blenderMode)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="DrawImageProcessor{TPixel}"/> class.
/// </summary>
/// <param name="image">The image to blend with the currently processing image.</param>
/// <param name="location">The location to draw the blended image.</param>
/// <param name="opacity">The opacity of the image to blend. Must be between 0 and 1.</param>
/// <param name="blenderMode">The blending mode to use when drawing the image.</param>
public DrawImageProcessor(Image<TPixel> image, Point location, float opacity, PixelBlenderMode blenderMode)
{
Guard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity));
this.Image = image;
this.Opacity = opacity;
this.Blender = PixelOperations<TPixel>.Instance.GetPixelBlender(blenderMode);
this.Location = location;
}
/// <summary>
/// Gets the image to blend
/// </summary>
public Image<TPixel> Image { get; }
/// <summary>
/// Gets the opacity of the image to blend
/// </summary>
public float Opacity { get; }
/// <summary>
/// Gets the pixel blender
/// </summary>
public PixelBlender<TPixel> Blender { get; }
/// <summary>
/// Gets the location to draw the blended image
/// </summary>
public Point Location { get; }
/// <inheritdoc/>
protected override void OnFrameApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
{
Image<TPixel> targetImage = this.Image;
PixelBlender<TPixel> blender = this.Blender;
int locationY = this.Location.Y;
// Align start/end positions.
Rectangle bounds = targetImage.Bounds();
int minX = Math.Max(this.Location.X, sourceRectangle.X);
int maxX = Math.Min(this.Location.X + bounds.Width, sourceRectangle.Width);
int targetX = minX - this.Location.X;
int minY = Math.Max(this.Location.Y, sourceRectangle.Y);
int maxY = Math.Min(this.Location.Y + bounds.Height, sourceRectangle.Bottom);
int width = maxX - minX;
MemoryManager memoryManager = this.Image.GetConfiguration().MemoryManager;
using (IBuffer<float> amount = memoryManager.Allocate<float>(width))
{
amount.Span.Fill(this.Opacity);
Parallel.For(
minY,
maxY,
configuration.ParallelOptions,
y =>
{
Span<TPixel> background = source.GetPixelRowSpan(y).Slice(minX, width);
Span<TPixel> foreground = targetImage.GetPixelRowSpan(y - locationY).Slice(targetX, width);
blender.Blend(memoryManager, background, background, foreground, amount.Span);
});
}
}
}
}

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

@ -0,0 +1,170 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing
{
/// <summary>
/// Gradient Brush with elliptic shape.
/// The ellipse is defined by a center point,
/// a point on the longest extension of the ellipse and
/// the ratio between longest and shortest extension.
/// </summary>
/// <typeparam name="TPixel">The Pixel format that is used.</typeparam>
public sealed class EllipticGradientBrush<TPixel> : GradientBrushBase<TPixel>
where TPixel : struct, IPixel<TPixel>
{
private readonly Point center;
private readonly Point referenceAxisEnd;
private readonly float axisRatio;
/// <inheritdoc cref="GradientBrushBase{TPixel}" />
/// <param name="center">The center of the elliptical gradient and 0 for the color stops.</param>
/// <param name="referenceAxisEnd">The end point of the reference axis of the ellipse.</param>
/// <param name="axisRatio">
/// The ratio of the axis widths.
/// The second axis' is perpendicular to the reference axis and
/// it's length is the reference axis' length multiplied by this factor.
/// </param>
/// <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,
float axisRatio,
GradientRepetitionMode repetitionMode,
params ColorStop<TPixel>[] colorStops)
: base(repetitionMode, colorStops)
{
this.center = center;
this.referenceAxisEnd = referenceAxisEnd;
this.axisRatio = axisRatio;
}
/// <inheritdoc cref="CreateApplicator" />
public override BrushApplicator<TPixel> CreateApplicator(
ImageFrame<TPixel> source,
RectangleF region,
GraphicsOptions options) =>
new RadialGradientBrushApplicator(
source,
options,
this.center,
this.referenceAxisEnd,
this.axisRatio,
this.ColorStops,
this.RepetitionMode);
/// <inheritdoc />
private sealed class RadialGradientBrushApplicator : GradientBrushApplicatorBase
{
private readonly Point center;
private readonly Point referenceAxisEnd;
private readonly float axisRatio;
private readonly double rotation;
private readonly float referenceRadius;
private readonly float secondRadius;
private readonly float cosRotation;
private readonly float sinRotation;
private readonly float secondRadiusSquared;
private readonly float referenceRadiusSquared;
/// <summary>
/// Initializes a new instance of the <see cref="RadialGradientBrushApplicator" /> class.
/// </summary>
/// <param name="target">The target image</param>
/// <param name="options">The options</param>
/// <param name="center">Center of the ellipse</param>
/// <param name="referenceAxisEnd">Point on one angular points of the ellipse.</param>
/// <param name="axisRatio">
/// Ratio of the axis length's. Used to determine the length of the second axis,
/// the first is defined by <see cref="center"/> and <see cref="referenceAxisEnd"/>.</param>
/// <param name="colorStops">Definition of colors</param>
/// <param name="repetitionMode">Defines how the gradient colors are repeated.</param>
public RadialGradientBrushApplicator(
ImageFrame<TPixel> target,
GraphicsOptions options,
Point center,
Point referenceAxisEnd,
float axisRatio,
ColorStop<TPixel>[] colorStops,
GradientRepetitionMode repetitionMode)
: base(target, options, colorStops, repetitionMode)
{
this.center = center;
this.referenceAxisEnd = referenceAxisEnd;
this.axisRatio = axisRatio;
this.rotation = this.AngleBetween(
this.center,
new PointF(this.center.X + 1, this.center.Y),
this.referenceAxisEnd);
this.referenceRadius = this.DistanceBetween(this.center, this.referenceAxisEnd);
this.secondRadius = this.referenceRadius * this.axisRatio;
this.referenceRadiusSquared = this.referenceRadius * this.referenceRadius;
this.secondRadiusSquared = this.secondRadius * this.secondRadius;
this.sinRotation = (float)Math.Sin(this.rotation);
this.cosRotation = (float)Math.Cos(this.rotation);
}
/// <inheritdoc />
public override void Dispose()
{
}
/// <inheritdoc />
protected override float PositionOnGradient(int xt, int yt)
{
float x0 = xt - this.center.X;
float y0 = yt - this.center.Y;
float x = (x0 * this.cosRotation) - (y0 * this.sinRotation);
float y = (x0 * this.sinRotation) + (y0 * this.cosRotation);
float xSquared = x * x;
float ySquared = y * y;
var inBoundaryChecker = (xSquared / this.referenceRadiusSquared)
+ (ySquared / this.secondRadiusSquared);
return inBoundaryChecker;
}
private float AngleBetween(PointF junction, PointF a, PointF b)
{
var vA = a - junction;
var vB = b - junction;
return (float)(Math.Atan2(vB.Y, vB.X)
- Math.Atan2(vA.Y, vA.X));
}
private float DistanceBetween(
PointF p1,
PointF p2)
{
float dX = p1.X - p2.X;
float dXsquared = dX * dX;
float dY = p1.Y - p2.Y;
float dYsquared = dY * dY;
return (float)Math.Sqrt(dXsquared + dYsquared);
}
}
}
}

17
src/ImageSharp.Drawing/Processing/Drawing/FillPathBuilderExtensions.cs → src/ImageSharp.Drawing/Processing/FillPathBuilderExtensions.cs

@ -3,10 +3,9 @@
using System;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Drawing.Brushes;
using SixLabors.Shapes;
namespace SixLabors.ImageSharp.Processing.Drawing
namespace SixLabors.ImageSharp.Processing
{
/// <summary>
/// Adds extensions that allow the filling of polygons with various brushes to the <see cref="Image{TPixel}"/> type.
@ -18,17 +17,17 @@ namespace SixLabors.ImageSharp.Processing.Drawing
/// </summary>
/// <typeparam name="TPixel">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="options">The graphics options.</param>
/// <param name="brush">The brush.</param>
/// <param name="path">The shape.</param>
/// <param name="options">The graphics options.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> Fill<TPixel>(this IImageProcessingContext<TPixel> source, IBrush<TPixel> brush, Action<PathBuilder> path, GraphicsOptions options)
public static IImageProcessingContext<TPixel> Fill<TPixel>(this IImageProcessingContext<TPixel> source, GraphicsOptions options, IBrush<TPixel> brush, Action<PathBuilder> path)
where TPixel : struct, IPixel<TPixel>
{
var pb = new PathBuilder();
path(pb);
return source.Fill(brush, pb.Build(), options);
return source.Fill(options, brush, pb.Build());
}
/// <summary>
@ -41,20 +40,20 @@ namespace SixLabors.ImageSharp.Processing.Drawing
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> Fill<TPixel>(this IImageProcessingContext<TPixel> source, IBrush<TPixel> brush, Action<PathBuilder> path)
where TPixel : struct, IPixel<TPixel>
=> source.Fill(brush, path, GraphicsOptions.Default);
=> source.Fill(GraphicsOptions.Default, brush, path);
/// <summary>
/// Flood fills the image in the shape of the provided polygon with the specified brush.
/// </summary>
/// <typeparam name="TPixel">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="options">The options.</param>
/// <param name="color">The color.</param>
/// <param name="path">The path.</param>
/// <param name="options">The options.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> Fill<TPixel>(this IImageProcessingContext<TPixel> source, TPixel color, Action<PathBuilder> path, GraphicsOptions options)
public static IImageProcessingContext<TPixel> Fill<TPixel>(this IImageProcessingContext<TPixel> source, GraphicsOptions options, TPixel color, Action<PathBuilder> path)
where TPixel : struct, IPixel<TPixel>
=> source.Fill(new SolidBrush<TPixel>(color), path, options);
=> source.Fill(options, new SolidBrush<TPixel>(color), path);
/// <summary>
/// Flood fills the image in the shape of the provided polygon with the specified brush.

17
src/ImageSharp.Drawing/Processing/Drawing/FillPathCollectionExtensions.cs → src/ImageSharp.Drawing/Processing/FillPathCollectionExtensions.cs

@ -2,10 +2,9 @@
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Drawing.Brushes;
using SixLabors.Shapes;
namespace SixLabors.ImageSharp.Processing.Drawing
namespace SixLabors.ImageSharp.Processing
{
/// <summary>
/// Adds extensions that allow the filling of collections of polygon outlines to the <see cref="Image{TPixel}"/> type.
@ -17,16 +16,16 @@ namespace SixLabors.ImageSharp.Processing.Drawing
/// </summary>
/// <typeparam name="TPixel">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="options">The graphics options.</param>
/// <param name="brush">The brush.</param>
/// <param name="paths">The shapes.</param>
/// <param name="options">The graphics options.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> Fill<TPixel>(this IImageProcessingContext<TPixel> source, IBrush<TPixel> brush, IPathCollection paths, GraphicsOptions options)
public static IImageProcessingContext<TPixel> Fill<TPixel>(this IImageProcessingContext<TPixel> source, GraphicsOptions options, IBrush<TPixel> brush, IPathCollection paths)
where TPixel : struct, IPixel<TPixel>
{
foreach (IPath s in paths)
{
source.Fill(brush, s, options);
source.Fill(options, brush, s);
}
return source;
@ -42,20 +41,20 @@ namespace SixLabors.ImageSharp.Processing.Drawing
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> Fill<TPixel>(this IImageProcessingContext<TPixel> source, IBrush<TPixel> brush, IPathCollection paths)
where TPixel : struct, IPixel<TPixel>
=> source.Fill(brush, paths, GraphicsOptions.Default);
=> source.Fill(GraphicsOptions.Default, brush, paths);
/// <summary>
/// Flood fills the image in the shape of the provided polygon with the specified brush.
/// </summary>
/// <typeparam name="TPixel">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="options">The options.</param>
/// <param name="color">The color.</param>
/// <param name="paths">The paths.</param>
/// <param name="options">The options.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> Fill<TPixel>(this IImageProcessingContext<TPixel> source, TPixel color, IPathCollection paths, GraphicsOptions options)
public static IImageProcessingContext<TPixel> Fill<TPixel>(this IImageProcessingContext<TPixel> source, GraphicsOptions options, TPixel color, IPathCollection paths)
where TPixel : struct, IPixel<TPixel>
=> source.Fill(new SolidBrush<TPixel>(color), paths, options);
=> source.Fill(options, new SolidBrush<TPixel>(color), paths);
/// <summary>
/// Flood fills the image in the shape of the provided polygon with the specified brush.

19
src/ImageSharp.Drawing/Processing/Drawing/FillPathExtensions.cs → src/ImageSharp.Drawing/Processing/FillPathExtensions.cs

@ -3,10 +3,9 @@
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Primitives;
using SixLabors.ImageSharp.Processing.Drawing.Brushes;
using SixLabors.Shapes;
namespace SixLabors.ImageSharp.Processing.Drawing
namespace SixLabors.ImageSharp.Processing
{
/// <summary>
/// Adds extensions that allow the filling of polygon outlines to the <see cref="Image{TPixel}"/> type.
@ -14,17 +13,17 @@ namespace SixLabors.ImageSharp.Processing.Drawing
public static class FillPathExtensions
{
/// <summary>
/// Flood fills the image in the shape of the provided polygon with the specified brush..
/// Flood fills the image in the shape of the provided polygon with the specified brush.
/// </summary>
/// <typeparam name="TPixel">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="options">The graphics options.</param>
/// <param name="brush">The brush.</param>
/// <param name="path">The shape.</param>
/// <param name="options">The graphics options.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> Fill<TPixel>(this IImageProcessingContext<TPixel> source, IBrush<TPixel> brush, IPath path, GraphicsOptions options)
public static IImageProcessingContext<TPixel> Fill<TPixel>(this IImageProcessingContext<TPixel> source, GraphicsOptions options, IBrush<TPixel> brush, IPath path)
where TPixel : struct, IPixel<TPixel>
=> source.Fill(brush, new ShapeRegion(path), options);
=> source.Fill(options, brush, new ShapeRegion(path));
/// <summary>
/// Flood fills the image in the shape of the provided polygon with the specified brush.
@ -36,20 +35,20 @@ namespace SixLabors.ImageSharp.Processing.Drawing
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> Fill<TPixel>(this IImageProcessingContext<TPixel> source, IBrush<TPixel> brush, IPath path)
where TPixel : struct, IPixel<TPixel>
=> source.Fill(brush, new ShapeRegion(path), GraphicsOptions.Default);
=> source.Fill(GraphicsOptions.Default, brush, new ShapeRegion(path));
/// <summary>
/// Flood fills the image in the shape of the provided polygon with the specified brush..
/// </summary>
/// <typeparam name="TPixel">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="options">The options.</param>
/// <param name="color">The color.</param>
/// <param name="path">The path.</param>
/// <param name="options">The options.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> Fill<TPixel>(this IImageProcessingContext<TPixel> source, TPixel color, IPath path, GraphicsOptions options)
public static IImageProcessingContext<TPixel> Fill<TPixel>(this IImageProcessingContext<TPixel> source, GraphicsOptions options, TPixel color, IPath path)
where TPixel : struct, IPixel<TPixel>
=> source.Fill(new SolidBrush<TPixel>(color), path, options);
=> source.Fill(options, new SolidBrush<TPixel>(color), path);
/// <summary>
/// Flood fills the image in the shape of the provided polygon with the specified brush..

19
src/ImageSharp.Drawing/Processing/Drawing/FillPolygonExtensions.cs → src/ImageSharp.Drawing/Processing/FillPolygonExtensions.cs

@ -2,11 +2,10 @@
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Drawing.Brushes;
using SixLabors.Primitives;
using SixLabors.Shapes;
namespace SixLabors.ImageSharp.Processing.Drawing
namespace SixLabors.ImageSharp.Processing
{
/// <summary>
/// Adds extensions that allow the filling of closed linear polygons to the <see cref="Image{TPixel}"/> type.
@ -18,13 +17,13 @@ namespace SixLabors.ImageSharp.Processing.Drawing
/// </summary>
/// <typeparam name="TPixel">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="options">The options.</param>
/// <param name="brush">The brush.</param>
/// <param name="points">The points.</param>
/// <param name="options">The options.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> FillPolygon<TPixel>(this IImageProcessingContext<TPixel> source, IBrush<TPixel> brush, PointF[] points, GraphicsOptions options)
public static IImageProcessingContext<TPixel> FillPolygon<TPixel>(this IImageProcessingContext<TPixel> source, GraphicsOptions options, IBrush<TPixel> brush, params PointF[] points)
where TPixel : struct, IPixel<TPixel>
=> source.Fill(brush, new Polygon(new LinearLineSegment(points)), options);
=> source.Fill(options, brush, new Polygon(new LinearLineSegment(points)));
/// <summary>
/// Flood fills the image in the shape of a Linear polygon described by the points
@ -34,7 +33,7 @@ namespace SixLabors.ImageSharp.Processing.Drawing
/// <param name="brush">The brush.</param>
/// <param name="points">The points.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> FillPolygon<TPixel>(this IImageProcessingContext<TPixel> source, IBrush<TPixel> brush, PointF[] points)
public static IImageProcessingContext<TPixel> FillPolygon<TPixel>(this IImageProcessingContext<TPixel> source, IBrush<TPixel> brush, params PointF[] points)
where TPixel : struct, IPixel<TPixel>
=> source.Fill(brush, new Polygon(new LinearLineSegment(points)));
@ -43,13 +42,13 @@ namespace SixLabors.ImageSharp.Processing.Drawing
/// </summary>
/// <typeparam name="TPixel">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="options">The options.</param>
/// <param name="color">The color.</param>
/// <param name="points">The points.</param>
/// <param name="options">The options.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> FillPolygon<TPixel>(this IImageProcessingContext<TPixel> source, TPixel color, PointF[] points, GraphicsOptions options)
public static IImageProcessingContext<TPixel> FillPolygon<TPixel>(this IImageProcessingContext<TPixel> source, GraphicsOptions options, TPixel color, params PointF[] points)
where TPixel : struct, IPixel<TPixel>
=> source.Fill(new SolidBrush<TPixel>(color), new Polygon(new LinearLineSegment(points)), options);
=> source.Fill(options, new SolidBrush<TPixel>(color), new Polygon(new LinearLineSegment(points)));
/// <summary>
/// Flood fills the image in the shape of a Linear polygon described by the points
@ -59,7 +58,7 @@ namespace SixLabors.ImageSharp.Processing.Drawing
/// <param name="color">The color.</param>
/// <param name="points">The points.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> FillPolygon<TPixel>(this IImageProcessingContext<TPixel> source, TPixel color, PointF[] points)
public static IImageProcessingContext<TPixel> FillPolygon<TPixel>(this IImageProcessingContext<TPixel> source, TPixel color, params PointF[] points)
where TPixel : struct, IPixel<TPixel>
=> source.Fill(new SolidBrush<TPixel>(color), new Polygon(new LinearLineSegment(points)));
}

17
src/ImageSharp.Drawing/Processing/Drawing/FillRectangleExtensions.cs → src/ImageSharp.Drawing/Processing/FillRectangleExtensions.cs

@ -2,11 +2,10 @@
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Drawing.Brushes;
using SixLabors.Primitives;
using SixLabors.Shapes;
namespace SixLabors.ImageSharp.Processing.Drawing
namespace SixLabors.ImageSharp.Processing
{
/// <summary>
/// Adds extensions that allow the filling of rectangles to the <see cref="Image{TPixel}"/> type.
@ -18,13 +17,13 @@ namespace SixLabors.ImageSharp.Processing.Drawing
/// </summary>
/// <typeparam name="TPixel">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="options">The options.</param>
/// <param name="brush">The brush.</param>
/// <param name="shape">The shape.</param>
/// <param name="options">The options.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> Fill<TPixel>(this IImageProcessingContext<TPixel> source, IBrush<TPixel> brush, RectangleF shape, GraphicsOptions options)
public static IImageProcessingContext<TPixel> Fill<TPixel>(this IImageProcessingContext<TPixel> source, GraphicsOptions options, IBrush<TPixel> brush, RectangleF shape)
where TPixel : struct, IPixel<TPixel>
=> source.Fill(brush, new RectangularePolygon(shape.X, shape.Y, shape.Width, shape.Height), options);
=> source.Fill(options, brush, new RectangularPolygon(shape.X, shape.Y, shape.Width, shape.Height));
/// <summary>
/// Flood fills the image in the shape of the provided rectangle with the specified brush.
@ -36,20 +35,20 @@ namespace SixLabors.ImageSharp.Processing.Drawing
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> Fill<TPixel>(this IImageProcessingContext<TPixel> source, IBrush<TPixel> brush, RectangleF shape)
where TPixel : struct, IPixel<TPixel>
=> source.Fill(brush, new RectangularePolygon(shape.X, shape.Y, shape.Width, shape.Height));
=> source.Fill(brush, new RectangularPolygon(shape.X, shape.Y, shape.Width, shape.Height));
/// <summary>
/// Flood fills the image in the shape of the provided rectangle with the specified brush.
/// </summary>
/// <typeparam name="TPixel">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="options">The options.</param>
/// <param name="color">The color.</param>
/// <param name="shape">The shape.</param>
/// <param name="options">The options.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> Fill<TPixel>(this IImageProcessingContext<TPixel> source, TPixel color, RectangleF shape, GraphicsOptions options)
public static IImageProcessingContext<TPixel> Fill<TPixel>(this IImageProcessingContext<TPixel> source, GraphicsOptions options, TPixel color, RectangleF shape)
where TPixel : struct, IPixel<TPixel>
=> source.Fill(new SolidBrush<TPixel>(color), shape, options);
=> source.Fill(options, new SolidBrush<TPixel>(color), shape);
/// <summary>
/// Flood fills the image in the shape of the provided rectangle with the specified brush.

23
src/ImageSharp.Drawing/Processing/Drawing/FillRegionExtensions.cs → src/ImageSharp.Drawing/Processing/FillRegionExtensions.cs

@ -3,10 +3,9 @@
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Primitives;
using SixLabors.ImageSharp.Processing.Drawing.Brushes;
using SixLabors.ImageSharp.Processing.Drawing.Processors;
using SixLabors.ImageSharp.Processing.Processors.Drawing;
namespace SixLabors.ImageSharp.Processing.Drawing
namespace SixLabors.ImageSharp.Processing
{
/// <summary>
/// Adds extensions that allow the filling of regions with various brushes to the <see cref="Image{TPixel}"/> type.
@ -22,7 +21,7 @@ namespace SixLabors.ImageSharp.Processing.Drawing
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> Fill<TPixel>(this IImageProcessingContext<TPixel> source, IBrush<TPixel> brush)
where TPixel : struct, IPixel<TPixel>
=> source.Fill(brush, GraphicsOptions.Default);
=> source.Fill(GraphicsOptions.Default, brush);
/// <summary>
/// Flood fills the image with the specified color.
@ -45,20 +44,20 @@ namespace SixLabors.ImageSharp.Processing.Drawing
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> Fill<TPixel>(this IImageProcessingContext<TPixel> source, IBrush<TPixel> brush, Region region)
where TPixel : struct, IPixel<TPixel>
=> source.Fill(brush, region, GraphicsOptions.Default);
=> source.Fill(GraphicsOptions.Default, brush, region);
/// <summary>
/// Flood fills the image with in the region with the specified color.
/// </summary>
/// <typeparam name="TPixel">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="options">The options.</param>
/// <param name="color">The color.</param>
/// <param name="region">The region.</param>
/// <param name="options">The options.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> Fill<TPixel>(this IImageProcessingContext<TPixel> source, TPixel color, Region region, GraphicsOptions options)
public static IImageProcessingContext<TPixel> Fill<TPixel>(this IImageProcessingContext<TPixel> source, GraphicsOptions options, TPixel color, Region region)
where TPixel : struct, IPixel<TPixel>
=> source.Fill(new SolidBrush<TPixel>(color), region, options);
=> source.Fill(options, new SolidBrush<TPixel>(color), region);
/// <summary>
/// Flood fills the image with in the region with the specified color.
@ -77,11 +76,11 @@ namespace SixLabors.ImageSharp.Processing.Drawing
/// </summary>
/// <typeparam name="TPixel">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="options">The graphics options.</param>
/// <param name="brush">The brush.</param>
/// <param name="region">The region.</param>
/// <param name="options">The graphics options.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> Fill<TPixel>(this IImageProcessingContext<TPixel> source, IBrush<TPixel> brush, Region region, GraphicsOptions options)
public static IImageProcessingContext<TPixel> Fill<TPixel>(this IImageProcessingContext<TPixel> source, GraphicsOptions options, IBrush<TPixel> brush, Region region)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new FillRegionProcessor<TPixel>(brush, region, options));
@ -90,10 +89,10 @@ namespace SixLabors.ImageSharp.Processing.Drawing
/// </summary>
/// <typeparam name="TPixel">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="brush">The details how to fill the region of interest.</param>
/// <param name="options">The graphics options.</param>
/// <param name="brush">The details how to fill the region of interest.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> Fill<TPixel>(this IImageProcessingContext<TPixel> source, IBrush<TPixel> brush, GraphicsOptions options)
public static IImageProcessingContext<TPixel> Fill<TPixel>(this IImageProcessingContext<TPixel> source, GraphicsOptions options, IBrush<TPixel> brush)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new FillProcessor<TPixel>(brush, options));
}

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

@ -0,0 +1,177 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Numerics;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.PixelFormats.PixelBlenders;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing
{
/// <summary>
/// Base class for Gradient brushes
/// </summary>
/// <typeparam name="TPixel">The pixel format</typeparam>
public abstract class GradientBrushBase<TPixel> : IBrush<TPixel>
where TPixel : struct, IPixel<TPixel>
{
/// <inheritdoc cref="IBrush{TPixel}"/>
/// <param name="repetitionMode">Defines how the colors are repeated beyond the interval [0..1]</param>
/// <param name="colorStops">The gradient colors.</param>
protected GradientBrushBase(
GradientRepetitionMode repetitionMode,
params ColorStop<TPixel>[] colorStops)
{
this.RepetitionMode = repetitionMode;
this.ColorStops = colorStops;
}
/// <summary>
/// Gets how the colors are repeated beyond the interval [0..1].
/// </summary>
protected GradientRepetitionMode RepetitionMode { get; }
/// <summary>
/// Gets the list of color stops for this gradient.
/// </summary>
protected ColorStop<TPixel>[] ColorStops { get; }
/// <inheritdoc cref="IBrush{TPixel}" />
public abstract BrushApplicator<TPixel> CreateApplicator(
ImageFrame<TPixel> source,
RectangleF region,
GraphicsOptions options);
/// <summary>
/// Base class for gradient brush applicators
/// </summary>
protected abstract class GradientBrushApplicatorBase : BrushApplicator<TPixel>
{
private readonly ColorStop<TPixel>[] colorStops;
private readonly GradientRepetitionMode repetitionMode;
/// <summary>
/// Initializes a new instance of the <see cref="GradientBrushApplicatorBase"/> class.
/// </summary>
/// <param name="target">The target.</param>
/// <param name="options">The options.</param>
/// <param name="colorStops">An array of color stops sorted by their position.</param>
/// <param name="repetitionMode">Defines if and how the gradient should be repeated.</param>
protected GradientBrushApplicatorBase(
ImageFrame<TPixel> target,
GraphicsOptions options,
ColorStop<TPixel>[] colorStops,
GradientRepetitionMode repetitionMode)
: base(target, options)
{
this.colorStops = colorStops; // TODO: requires colorStops to be sorted by position - should that be checked?
this.repetitionMode = repetitionMode;
}
/// <summary>
/// Base implementation of the indexer for gradients
/// (follows the facade pattern, using abstract methods)
/// </summary>
/// <param name="x">X coordinate of the Pixel.</param>
/// <param name="y">Y coordinate of the Pixel.</param>
internal override TPixel this[int x, int y]
{
get
{
float positionOnCompleteGradient = this.PositionOnGradient(x, y);
switch (this.repetitionMode)
{
case GradientRepetitionMode.None:
// do nothing. The following could be done, but is not necessary:
// onLocalGradient = Math.Min(0, Math.Max(1, onLocalGradient));
break;
case GradientRepetitionMode.Repeat:
positionOnCompleteGradient = positionOnCompleteGradient % 1;
break;
case GradientRepetitionMode.Reflect:
positionOnCompleteGradient = positionOnCompleteGradient % 2;
if (positionOnCompleteGradient > 1)
{
positionOnCompleteGradient = 2 - positionOnCompleteGradient;
}
break;
case GradientRepetitionMode.DontFill:
if (positionOnCompleteGradient > 1 || positionOnCompleteGradient < 0)
{
return NamedColors<TPixel>.Transparent;
}
break;
default:
throw new ArgumentOutOfRangeException();
}
(ColorStop<TPixel> from, ColorStop<TPixel> to) = this.GetGradientSegment(positionOnCompleteGradient);
if (from.Color.Equals(to.Color))
{
return from.Color;
}
else
{
var fromAsVector = from.Color.ToVector4();
var toAsVector = to.Color.ToVector4();
float onLocalGradient = (positionOnCompleteGradient - from.Ratio) / to.Ratio;
// TODO: this should be changeble for different gradienting functions
Vector4 result = PorterDuffFunctions.NormalSrcOver(
fromAsVector,
toAsVector,
onLocalGradient);
TPixel resultColor = default;
resultColor.PackFromVector4(result);
return resultColor;
}
}
}
/// <summary>
/// calculates the position on the gradient for a given pixel.
/// 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>
/// <returns>
/// The position the given pixel 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);
private (ColorStop<TPixel> from, ColorStop<TPixel> to) GetGradientSegment(
float positionOnCompleteGradient)
{
ColorStop<TPixel> localGradientFrom = this.colorStops[0];
ColorStop<TPixel> localGradientTo = default;
// TODO: ensure colorStops has at least 2 items (technically 1 would be okay, but that's no gradient)
foreach (ColorStop<TPixel> colorStop in this.colorStops)
{
localGradientTo = colorStop;
if (colorStop.Ratio > positionOnCompleteGradient)
{
// we're done here, so break it!
break;
}
localGradientFrom = localGradientTo;
}
return (localGradientFrom, localGradientTo);
}
}
}
}

37
src/ImageSharp.Drawing/Processing/GradientRepetitionMode.cs

@ -0,0 +1,37 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
namespace SixLabors.ImageSharp.Processing
{
/// <summary>
/// Modes to repeat a gradient.
/// </summary>
public enum GradientRepetitionMode
{
/// <summary>
/// don't repeat, keep the color of start and end beyond those points stable.
/// </summary>
None,
/// <summary>
/// Repeat the gradient.
/// If it's a black-white gradient, with Repeat it will be Black->{gray}->White|Black->{gray}->White|...
/// </summary>
Repeat,
/// <summary>
/// Reflect the gradient.
/// Similar to <see cref="Repeat"/>, but each other repetition uses inverse order of <see cref="ColorStop{TPixel}"/>s.
/// Used on a Black-White gradient, Reflect leads to Black->{gray}->White->{gray}->White...
/// </summary>
Reflect,
/// <summary>
/// With DontFill a gradient does not touch any pixel beyond it's borders.
/// For the <see cref="LinearGradientBrush{TPixel}" /> this is beyond the orthogonal through start and end,
/// TODO For the cref="PolygonalGradientBrush" it's outside the polygon,
/// For <see cref="RadialGradientBrush{TPixel}" /> and <see cref="EllipticGradientBrush{TPixel}" /> it's beyond 1.0.
/// </summary>
DontFill
}
}

2
src/ImageSharp.Drawing/Processing/Drawing/Brushes/IBrush.cs → src/ImageSharp.Drawing/Processing/IBrush.cs

@ -4,7 +4,7 @@
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Drawing.Brushes
namespace SixLabors.ImageSharp.Processing
{
/// <summary>
/// Brush represents a logical configuration of a brush which can be used to source pixel colors

3
src/ImageSharp.Drawing/Processing/Drawing/Pens/IPen.cs → src/ImageSharp.Drawing/Processing/IPen.cs

@ -3,9 +3,8 @@
using System;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Drawing.Brushes;
namespace SixLabors.ImageSharp.Processing.Drawing.Pens
namespace SixLabors.ImageSharp.Processing
{
/// <summary>
/// Interface representing a Pen

14
src/ImageSharp.Drawing/Processing/Drawing/Brushes/ImageBrush{TPixel}.cs → src/ImageSharp.Drawing/Processing/ImageBrush{TPixel}.cs

@ -2,12 +2,14 @@
// Licensed under the Apache License, Version 2.0.
using System;
using System.Buffers;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Memory;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Drawing.Brushes
namespace SixLabors.ImageSharp.Processing
{
/// <summary>
/// Provides an implementation of an image brush for painting images within areas.
@ -118,11 +120,11 @@ namespace SixLabors.ImageSharp.Processing.Drawing.Brushes
internal override void Apply(Span<float> scanline, int x, int y)
{
// Create a span for colors
using (IBuffer<float> amountBuffer = this.Target.MemoryManager.Allocate<float>(scanline.Length))
using (IBuffer<TPixel> overlay = this.Target.MemoryManager.Allocate<TPixel>(scanline.Length))
using (IMemoryOwner<float> amountBuffer = this.Target.MemoryAllocator.Allocate<float>(scanline.Length))
using (IMemoryOwner<TPixel> overlay = this.Target.MemoryAllocator.Allocate<TPixel>(scanline.Length))
{
Span<float> amountSpan = amountBuffer.Span;
Span<TPixel> overlaySpan = overlay.Span;
Span<float> amountSpan = amountBuffer.GetSpan();
Span<TPixel> overlaySpan = overlay.GetSpan();
int sourceY = (y - this.offsetY) % this.yLength;
int offsetX = x - this.offsetX;
@ -138,7 +140,7 @@ namespace SixLabors.ImageSharp.Processing.Drawing.Brushes
}
Span<TPixel> destinationRow = this.Target.GetPixelRowSpan(y).Slice(x, scanline.Length);
this.Blender.Blend(this.source.MemoryManager, destinationRow, destinationRow, overlaySpan, amountSpan);
this.Blender.Blend(this.source.MemoryAllocator, destinationRow, destinationRow, overlaySpan, amountSpan);
}
}
}

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

@ -0,0 +1,155 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing
{
/// <summary>
/// Provides an implementation of a brush for painting linear gradients within areas.
/// Supported right now:
/// - a set of colors in relative distances to each other.
/// </summary>
/// <typeparam name="TPixel">The pixel format</typeparam>
public sealed class LinearGradientBrush<TPixel> : GradientBrushBase<TPixel>
where TPixel : struct, IPixel<TPixel>
{
private readonly Point p1;
private readonly Point p2;
/// <summary>
/// Initializes a new instance of the <see cref="LinearGradientBrush{TPixel}"/> class.
/// </summary>
/// <param name="p1">Start point</param>
/// <param name="p2">End point</param>
/// <param name="repetitionMode">defines how colors are repeated.</param>
/// <param name="colorStops"><inheritdoc /></param>
public LinearGradientBrush(
Point p1,
Point p2,
GradientRepetitionMode repetitionMode,
params ColorStop<TPixel>[] colorStops)
: base(repetitionMode, colorStops)
{
this.p1 = p1;
this.p2 = p2;
}
/// <inheritdoc />
public override BrushApplicator<TPixel> CreateApplicator(ImageFrame<TPixel> source, RectangleF region, GraphicsOptions options)
=> new LinearGradientBrushApplicator(source, this.p1, this.p2, this.ColorStops, this.RepetitionMode, options);
/// <summary>
/// The linear gradient brush applicator.
/// </summary>
private sealed class LinearGradientBrushApplicator : GradientBrushApplicatorBase
{
private readonly Point start;
private readonly Point end;
/// <summary>
/// the vector along the gradient, x component
/// </summary>
private readonly float alongX;
/// <summary>
/// the vector along the gradient, y component
/// </summary>
private readonly float alongY;
/// <summary>
/// the vector perpendicular to the gradient, y component
/// </summary>
private readonly float acrossY;
/// <summary>
/// the vector perpendicular to the gradient, x component
/// </summary>
private readonly float acrossX;
/// <summary>
/// the result of <see cref="alongX"/>^2 + <see cref="alongY"/>^2
/// </summary>
private readonly float alongsSquared;
/// <summary>
/// the length of the defined gradient (between source and end)
/// </summary>
private readonly float length;
/// <summary>
/// Initializes a new instance of the <see cref="LinearGradientBrushApplicator" /> class.
/// </summary>
/// <param name="source">The source</param>
/// <param name="start">start point of the gradient</param>
/// <param name="end">end point of the gradient</param>
/// <param name="colorStops">tuple list of colors and their respective position between 0 and 1 on the line</param>
/// <param name="repetitionMode">defines how the gradient colors are repeated.</param>
/// <param name="options">the graphics options</param>
public LinearGradientBrushApplicator(
ImageFrame<TPixel> source,
Point start,
Point end,
ColorStop<TPixel>[] colorStops,
GradientRepetitionMode repetitionMode,
GraphicsOptions options)
: base(source, options, colorStops, repetitionMode)
{
this.start = start;
this.end = end;
// the along vector:
this.alongX = this.end.X - this.start.X;
this.alongY = this.end.Y - this.start.Y;
// the cross vector:
this.acrossX = this.alongY;
this.acrossY = -this.alongX;
// some helpers:
this.alongsSquared = (this.alongX * this.alongX) + (this.alongY * this.alongY);
this.length = (float)Math.Sqrt(this.alongsSquared);
}
protected override float PositionOnGradient(int x, int y)
{
if (this.acrossX == 0)
{
return (x - this.start.X) / (float)(this.end.X - this.start.X);
}
else if (this.acrossY == 0)
{
return (y - this.start.Y) / (float)(this.end.Y - this.start.Y);
}
else
{
float deltaX = x - this.start.X;
float deltaY = y - this.start.Y;
float k = ((this.alongY * deltaX) - (this.alongX * deltaY)) / this.alongsSquared;
// point on the line:
float x4 = x - (k * this.alongY);
float y4 = y + (k * this.alongX);
// get distance from (x4,y4) to start
float distance = (float)Math.Sqrt(
Math.Pow(x4 - this.start.X, 2)
+ Math.Pow(y4 - this.start.Y, 2));
// get and return ratio
float ratio = distance / this.length;
return ratio;
}
}
public override void Dispose()
{
}
}
}
}

16
src/ImageSharp.Drawing/Processing/Drawing/Brushes/PatternBrush{TPixel}.cs → src/ImageSharp.Drawing/Processing/PatternBrush{TPixel}.cs

@ -2,14 +2,16 @@
// Licensed under the Apache License, Version 2.0.
using System;
using System.Buffers;
using System.Numerics;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Primitives;
using SixLabors.Memory;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Drawing.Brushes
namespace SixLabors.ImageSharp.Processing
{
/// <summary>
/// Provides an implementation of a pattern brush for painting patterns.
@ -151,13 +153,13 @@ namespace SixLabors.ImageSharp.Processing.Drawing.Brushes
internal override void Apply(Span<float> scanline, int x, int y)
{
int patternY = y % this.pattern.Rows;
MemoryManager memoryManager = this.Target.MemoryManager;
MemoryAllocator memoryAllocator = this.Target.MemoryAllocator;
using (IBuffer<float> amountBuffer = memoryManager.Allocate<float>(scanline.Length))
using (IBuffer<TPixel> overlay = memoryManager.Allocate<TPixel>(scanline.Length))
using (IMemoryOwner<float> amountBuffer = memoryAllocator.Allocate<float>(scanline.Length))
using (IMemoryOwner<TPixel> overlay = memoryAllocator.Allocate<TPixel>(scanline.Length))
{
Span<float> amountSpan = amountBuffer.Span;
Span<TPixel> overlaySpan = overlay.Span;
Span<float> amountSpan = amountBuffer.GetSpan();
Span<TPixel> overlaySpan = overlay.GetSpan();
for (int i = 0; i < scanline.Length; i++)
{
@ -168,7 +170,7 @@ namespace SixLabors.ImageSharp.Processing.Drawing.Brushes
}
Span<TPixel> destinationRow = this.Target.GetPixelRowSpan(y).Slice(x, scanline.Length);
this.Blender.Blend(memoryManager, destinationRow, destinationRow, overlaySpan, amountSpan);
this.Blender.Blend(memoryAllocator, destinationRow, destinationRow, overlaySpan, amountSpan);
}
}
}

3
src/ImageSharp.Drawing/Processing/Drawing/Pens/Pens.cs → src/ImageSharp.Drawing/Processing/Pens.cs

@ -2,9 +2,8 @@
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Drawing.Brushes;
namespace SixLabors.ImageSharp.Processing.Drawing.Pens
namespace SixLabors.ImageSharp.Processing
{
/// <summary>
/// Contains a collection of common Pen styles

11
src/ImageSharp.Drawing/Processing/Drawing/Pens/Pen{TPixel}.cs → src/ImageSharp.Drawing/Processing/Pen{TPixel}.cs

@ -3,9 +3,8 @@
using System;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Drawing.Brushes;
namespace SixLabors.ImageSharp.Processing.Drawing.Pens
namespace SixLabors.ImageSharp.Processing
{
/// <summary>
/// Provides a pen that can apply a pattern to a line with a set brush and thickness
@ -25,7 +24,7 @@ namespace SixLabors.ImageSharp.Processing.Drawing.Pens
private readonly float[] pattern;
/// <summary>
/// Initializes a new instance of the <see cref="Drawing.Pens.Pen{TPixel}"/> class.
/// Initializes a new instance of the <see cref="Pen{TPixel}"/> class.
/// </summary>
/// <param name="color">The color.</param>
/// <param name="width">The width.</param>
@ -36,7 +35,7 @@ namespace SixLabors.ImageSharp.Processing.Drawing.Pens
}
/// <summary>
/// Initializes a new instance of the <see cref="Drawing.Pens.Pen{TPixel}"/> class.
/// Initializes a new instance of the <see cref="Pen{TPixel}"/> class.
/// </summary>
/// <param name="brush">The brush.</param>
/// <param name="width">The width.</param>
@ -49,7 +48,7 @@ namespace SixLabors.ImageSharp.Processing.Drawing.Pens
}
/// <summary>
/// Initializes a new instance of the <see cref="Drawing.Pens.Pen{TPixel}"/> class.
/// Initializes a new instance of the <see cref="Pen{TPixel}"/> class.
/// </summary>
/// <param name="color">The color.</param>
/// <param name="width">The width.</param>
@ -59,7 +58,7 @@ namespace SixLabors.ImageSharp.Processing.Drawing.Pens
}
/// <summary>
/// Initializes a new instance of the <see cref="Drawing.Pens.Pen{TPixel}"/> class.
/// Initializes a new instance of the <see cref="Pen{TPixel}"/> class.
/// </summary>
/// <param name="brush">The brush.</param>
/// <param name="width">The width.</param>

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

@ -0,0 +1,98 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Buffers;
using System.Threading.Tasks;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Memory;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Processors.Drawing
{
/// <summary>
/// Combines two images together by blending the pixels.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
internal class DrawImageProcessor<TPixel> : ImageProcessor<TPixel>
where TPixel : struct, IPixel<TPixel>
{
/// <summary>
/// Initializes a new instance of the <see cref="DrawImageProcessor{TPixel}"/> class.
/// </summary>
/// <param name="image">The image to blend with the currently processing image.</param>
/// <param name="location">The location to draw the blended image.</param>
/// <param name="colorBlendingMode">The blending mode to use when drawing the image.</param>
/// <param name="alphaCompositionMode">The Alpha blending mode to use when drawing the image.</param>
/// <param name="opacity">The opacity of the image to blend. Must be between 0 and 1.</param>
public DrawImageProcessor(Image<TPixel> image, Point location, PixelColorBlendingMode colorBlendingMode, PixelAlphaCompositionMode alphaCompositionMode, float opacity)
{
Guard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity));
this.Image = image;
this.Opacity = opacity;
this.Blender = PixelOperations<TPixel>.Instance.GetPixelBlender(colorBlendingMode, alphaCompositionMode);
this.Location = location;
}
/// <summary>
/// Gets the image to blend
/// </summary>
public Image<TPixel> Image { get; }
/// <summary>
/// Gets the opacity of the image to blend
/// </summary>
public float Opacity { get; }
/// <summary>
/// Gets the pixel blender
/// </summary>
public PixelBlender<TPixel> Blender { get; }
/// <summary>
/// Gets the location to draw the blended image
/// </summary>
public Point Location { get; }
/// <inheritdoc/>
protected override void OnFrameApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
{
Image<TPixel> targetImage = this.Image;
PixelBlender<TPixel> blender = this.Blender;
int locationY = this.Location.Y;
// Align start/end positions.
Rectangle bounds = targetImage.Bounds();
int minX = Math.Max(this.Location.X, sourceRectangle.X);
int maxX = Math.Min(this.Location.X + bounds.Width, sourceRectangle.Width);
int targetX = minX - this.Location.X;
int minY = Math.Max(this.Location.Y, sourceRectangle.Y);
int maxY = Math.Min(this.Location.Y + bounds.Height, sourceRectangle.Bottom);
int width = maxX - minX;
MemoryAllocator memoryAllocator = this.Image.GetConfiguration().MemoryAllocator;
using (IMemoryOwner<float> amount = memoryAllocator.Allocate<float>(width))
{
amount.GetSpan().Fill(this.Opacity);
ParallelFor.WithConfiguration(
minY,
maxY,
configuration,
y =>
{
Span<TPixel> background = source.GetPixelRowSpan(y).Slice(minX, width);
Span<TPixel> foreground = targetImage.GetPixelRowSpan(y - locationY).Slice(targetX, width);
blender.Blend(memoryAllocator, background, background, foreground, amount.GetSpan());
});
}
}
}
}

84
src/ImageSharp.Drawing/Processing/Drawing/Processors/FillProcessor.cs → src/ImageSharp.Drawing/Processing/Processors/Drawing/FillProcessor.cs

@ -2,14 +2,15 @@
// Licensed under the Apache License, Version 2.0.
using System;
using System.Buffers;
using System.Threading.Tasks;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Drawing.Brushes;
using SixLabors.ImageSharp.Processing.Processors;
using SixLabors.Memory;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Drawing.Processors
namespace SixLabors.ImageSharp.Processing.Processors.Drawing
{
/// <summary>
/// Using the brush as a source of pixels colors blends the brush color with source.
@ -49,39 +50,66 @@ namespace SixLabors.ImageSharp.Processing.Drawing.Processors
int minY = Math.Max(0, startY);
int maxY = Math.Min(source.Height, endY);
// Reset offset if necessary.
if (minX > 0)
{
startX = 0;
}
if (minY > 0)
{
startY = 0;
}
int width = maxX - minX;
using (IBuffer<float> amount = source.MemoryManager.Allocate<float>(width))
using (BrushApplicator<TPixel> applicator = this.brush.CreateApplicator(
source,
sourceRectangle,
this.options))
// If there's no reason for blending, then avoid it.
if (this.IsSolidBrushWithoutBlending(out SolidBrush<TPixel> solidBrush))
{
amount.Span.Fill(this.options.BlendPercentage);
Parallel.For(
ParallelFor.WithConfiguration(
minY,
maxY,
configuration.ParallelOptions,
configuration,
y =>
{
int offsetY = y - startY;
int offsetX = minX - startX;
{
source.GetPixelRowSpan(y).Slice(minX, width).Fill(solidBrush.Color);
});
}
else
{
// Reset offset if necessary.
if (minX > 0)
{
startX = 0;
}
if (minY > 0)
{
startY = 0;
}
using (IMemoryOwner<float> amount = source.MemoryAllocator.Allocate<float>(width))
using (BrushApplicator<TPixel> applicator = this.brush.CreateApplicator(
source,
sourceRectangle,
this.options))
{
amount.GetSpan().Fill(1f);
ParallelFor.WithConfiguration(
minY,
maxY,
configuration,
y =>
{
int offsetY = y - startY;
int offsetX = minX - startX;
applicator.Apply(amount.Span, offsetX, offsetY);
});
applicator.Apply(amount.GetSpan(), offsetX, offsetY);
});
}
}
}
private bool IsSolidBrushWithoutBlending(out SolidBrush<TPixel> solidBrush)
{
solidBrush = this.brush as SolidBrush<TPixel>;
if (solidBrush == null)
{
return false;
}
return this.options.IsOpaqueColorWithoutBlending(solidBrush.Color);
}
}
}

89
src/ImageSharp.Drawing/Processing/Drawing/Processors/FillRegionProcessor.cs → src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor.cs

@ -2,15 +2,16 @@
// Licensed under the Apache License, Version 2.0.
using System;
using System.Runtime.CompilerServices;
using System.Buffers;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Primitives;
using SixLabors.ImageSharp.Processing.Drawing.Brushes;
using SixLabors.ImageSharp.Processing.Processors;
using SixLabors.ImageSharp.Utils;
using SixLabors.Memory;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Drawing.Processors
namespace SixLabors.ImageSharp.Processing.Processors.Drawing
{
/// <summary>
/// Using a brush and a shape fills shape with contents of brush the
@ -96,35 +97,35 @@ namespace SixLabors.ImageSharp.Processing.Drawing.Processors
using (BrushApplicator<TPixel> applicator = this.Brush.CreateApplicator(source, rect, this.Options))
{
int scanlineWidth = maxX - minX;
using (BasicArrayBuffer<float> buffer = source.MemoryManager.AllocateFake<float>(maxIntersections))
using (BasicArrayBuffer<float> scanline = source.MemoryManager.AllocateFake<float>(scanlineWidth))
using (IMemoryOwner<float> bBuffer = source.MemoryAllocator.Allocate<float>(maxIntersections))
using (IMemoryOwner<float> bScanline = source.MemoryAllocator.Allocate<float>(scanlineWidth))
{
bool scanlineDirty = true;
float subpixelFraction = 1f / subpixelCount;
float subpixelFractionPoint = subpixelFraction / subpixelCount;
Span<float> buffer = bBuffer.GetSpan();
Span<float> scanline = bScanline.GetSpan();
for (int y = minY; y < maxY; y++)
{
if (scanlineDirty)
{
// clear the buffer
for (int x = 0; x < scanlineWidth; x++)
{
scanline[x] = 0;
}
scanline.Clear();
scanlineDirty = false;
}
float subpixelFraction = 1f / subpixelCount;
float subpixelFractionPoint = subpixelFraction / subpixelCount;
for (float subPixel = (float)y; subPixel < y + 1; subPixel += subpixelFraction)
float yPlusOne = y + 1;
for (float subPixel = (float)y; subPixel < yPlusOne; subPixel += subpixelFraction)
{
int pointsFound = region.Scan(subPixel + offset, buffer.Array, 0);
int pointsFound = region.Scan(subPixel + offset, buffer, configuration);
if (pointsFound == 0)
{
// nothing on this line skip
continue;
}
QuickSort(new Span<float>(buffer.Array, 0, pointsFound));
QuickSort.Sort(buffer.Slice(0, pointsFound));
for (int point = 0; point < pointsFound; point += 2)
{
@ -180,63 +181,11 @@ namespace SixLabors.ImageSharp.Processing.Drawing.Processors
}
}
applicator.Apply(scanline.Span, minX, y);
applicator.Apply(scanline, minX, y);
}
}
}
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void Swap(Span<float> data, int left, int right)
{
float tmp = data[left];
data[left] = data[right];
data[right] = tmp;
}
private static void QuickSort(Span<float> data)
{
int hi = Math.Min(data.Length - 1, data.Length - 1);
QuickSort(data, 0, hi);
}
private static void QuickSort(Span<float> data, int lo, int hi)
{
if (lo < hi)
{
int p = Partition(data, lo, hi);
QuickSort(data, lo, p);
QuickSort(data, p + 1, hi);
}
}
private static int Partition(Span<float> data, int lo, int hi)
{
float pivot = data[lo];
int i = lo - 1;
int j = hi + 1;
while (true)
{
do
{
i = i + 1;
}
while (data[i] < pivot && i < hi);
do
{
j = j - 1;
}
while (data[j] > pivot && j > lo);
if (i >= j)
{
return j;
}
Swap(data, i, j);
}
}
}
}

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

@ -0,0 +1,471 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Buffers;
using System.Collections.Generic;
using SixLabors.Fonts;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Utils;
using SixLabors.Memory;
using SixLabors.Primitives;
using SixLabors.Shapes;
namespace SixLabors.ImageSharp.Processing.Processors.Text
{
/// <summary>
/// Using the brush as a source of pixels colors blends the brush color with source.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
internal class DrawTextProcessor<TPixel> : ImageProcessor<TPixel>
where TPixel : struct, IPixel<TPixel>
{
private CachingGlyphRenderer textRenderer;
/// <summary>
/// Initializes a new instance of the <see cref="DrawTextProcessor{TPixel}"/> class.
/// </summary>
/// <param name="options">The options</param>
/// <param name="text">The text we want to render</param>
/// <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>
public DrawTextProcessor(TextGraphicsOptions options, string text, Font font, IBrush<TPixel> brush, IPen<TPixel> pen, PointF location)
{
Guard.NotNull(text, nameof(text));
Guard.NotNull(font, nameof(font));
if (brush is null && pen is null)
{
throw new ArgumentNullException($"Expected a {nameof(brush)} or {nameof(pen)}. Both were null");
}
this.Options = options;
this.Text = text;
this.Font = font;
this.Location = location;
this.Brush = brush;
this.Pen = pen;
}
/// <summary>
/// Gets the brush.
/// </summary>
public IBrush<TPixel> Brush { get; }
/// <summary>
/// Gets the options
/// </summary>
public TextGraphicsOptions Options { get; }
/// <summary>
/// Gets the text
/// </summary>
public string Text { get; }
/// <summary>
/// Gets the pen used for outlining the text, if Null then we will not outline
/// </summary>
public IPen<TPixel> Pen { get; }
/// <summary>
/// Gets the font used to render the text.
/// </summary>
public Font Font { get; }
/// <summary>
/// Gets the location to draw the text at.
/// </summary>
public PointF Location { get; }
protected override void BeforeImageApply(Image<TPixel> source, Rectangle sourceRectangle)
{
base.BeforeImageApply(source, sourceRectangle);
// do everythign at the image level as we are deligating the processing down to other processors
var style = new RendererOptions(this.Font, this.Options.DpiX, this.Options.DpiY, this.Location)
{
ApplyKerning = this.Options.ApplyKerning,
TabWidth = this.Options.TabWidth,
WrappingWidth = this.Options.WrapTextWidth,
HorizontalAlignment = this.Options.HorizontalAlignment,
VerticalAlignment = this.Options.VerticalAlignment
};
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);
}
protected override void AfterImageApply(Image<TPixel> source, Rectangle sourceRectangle)
{
base.AfterImageApply(source, sourceRectangle);
this.textRenderer?.Dispose();
this.textRenderer = null;
}
/// <inheritdoc/>
protected override void OnFrameApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
{
// this is a no-op as we have processes all as an image, we should be able to pass out of before email apply a skip frames outcome
Draw(this.textRenderer.FillOperations, this.Brush);
Draw(this.textRenderer.OutlineOperations, this.Pen?.StrokeFill);
void Draw(List<DrawingOperation> operations, IBrush<TPixel> brush)
{
if (operations?.Count > 0)
{
using (BrushApplicator<TPixel> app = brush.CreateApplicator(source, sourceRectangle, this.textRenderer.Options))
{
foreach (DrawingOperation operation in operations)
{
Buffer2D<float> buffer = operation.Map;
int startY = operation.Location.Y;
int startX = operation.Location.X;
int offSetSpan = 0;
if (startX < 0)
{
offSetSpan = -startX;
startX = 0;
}
int fistRow = 0;
if (startY < 0)
{
fistRow = -startY;
}
int end = operation.Map.Height;
int maxHeight = source.Height - startY;
end = Math.Min(end, maxHeight);
for (int row = fistRow; row < end; row++)
{
int y = startY + row;
Span<float> span = buffer.GetRowSpan(row).Slice(offSetSpan);
app.Apply(span, startX, y);
}
}
}
}
}
}
private struct DrawingOperation
{
public Buffer2D<float> Map { get; set; }
public Point Location { get; set; }
}
private class CachingGlyphRenderer : IGlyphRenderer, IDisposable
{
private PathBuilder builder;
private Point currentRenderPosition = default;
private GlyphRendererParameters currentGlyphRenderParams = default;
private int offset = 0;
private PointF currentPoint = default(PointF);
private readonly Dictionary<GlyphRendererParameters, GlyphRenderData> glyphData = new Dictionary<GlyphRendererParameters, GlyphRenderData>();
private bool renderOutline = false;
private bool renderFill = false;
private bool raterizationRequired = false;
public CachingGlyphRenderer(MemoryAllocator memoryAllocator, int size, IPen pen, bool renderFill)
{
this.MemoryAllocator = memoryAllocator;
this.Pen = pen;
this.renderFill = renderFill;
this.renderOutline = pen != null;
this.offset = 2;
if (this.renderFill)
{
this.FillOperations = new List<DrawingOperation>(size);
}
if (this.renderOutline)
{
this.offset = (int)MathF.Ceiling((pen.StrokeWidth * 2) + 2);
this.OutlineOperations = new List<DrawingOperation>(size);
}
this.builder = new PathBuilder();
}
public List<DrawingOperation> FillOperations { get; }
public List<DrawingOperation> OutlineOperations { get; }
public MemoryAllocator MemoryAllocator { get; internal set; }
public IPen Pen { get; internal set; }
public GraphicsOptions Options { get; internal set; }
public void BeginFigure()
{
this.builder.StartFigure();
}
public bool BeginGlyph(RectangleF bounds, GlyphRendererParameters paramters)
{
this.currentRenderPosition = Point.Truncate(bounds.Location);
// 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))
{
// we have already drawn the glyph vectors skip trying again
this.raterizationRequired = false;
return false;
}
// we check to see if we have a render cache and if we do then we render else
this.builder.Clear();
// 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;
return true;
}
public void BeginText(RectangleF bounds)
{
// not concerned about this one
this.OutlineOperations?.Clear();
this.FillOperations?.Clear();
}
public void CubicBezierTo(PointF secondControlPoint, PointF thirdControlPoint, PointF point)
{
this.builder.AddBezier(this.currentPoint, secondControlPoint, thirdControlPoint, point);
this.currentPoint = point;
}
public void Dispose()
{
foreach (KeyValuePair<GlyphRendererParameters, GlyphRenderData> kv in this.glyphData)
{
kv.Value.Dispose();
}
this.glyphData.Clear();
}
public void EndFigure()
{
this.builder.CloseFigure();
}
public void EndGlyph()
{
GlyphRenderData renderData = default;
// has the glyoh been rendedered already????
if (this.raterizationRequired)
{
IPath path = this.builder.Build();
if (this.renderFill)
{
renderData.FillMap = this.Render(path);
}
if (this.renderOutline)
{
if (this.Pen.StrokePattern.Length == 0)
{
path = path.GenerateOutline(this.Pen.StrokeWidth);
}
else
{
path = path.GenerateOutline(this.Pen.StrokeWidth, this.Pen.StrokePattern);
}
renderData.OutlineMap = this.Render(path);
}
this.glyphData[this.currentGlyphRenderParams] = renderData;
}
else
{
renderData = this.glyphData[this.currentGlyphRenderParams];
}
if (this.renderFill)
{
this.FillOperations.Add(new DrawingOperation
{
Location = this.currentRenderPosition,
Map = renderData.FillMap
});
}
if (this.renderOutline)
{
this.OutlineOperations.Add(new DrawingOperation
{
Location = this.currentRenderPosition,
Map = renderData.OutlineMap
});
}
}
private Buffer2D<float> Render(IPath path)
{
Size size = Rectangle.Ceiling(path.Bounds).Size;
size = new Size(size.Width + (this.offset * 2), size.Height + (this.offset * 2));
float subpixelCount = 4;
float offset = 0.5f;
if (this.Options.Antialias)
{
offset = 0f; // we are antialising skip offsetting as real antalising should take care of offset.
subpixelCount = this.Options.AntialiasSubpixelDepth;
if (subpixelCount < 4)
{
subpixelCount = 4;
}
}
// take the path inside the path builder, scan thing and generate a Buffer2d representing the glyph and cache it.
Buffer2D<float> fullBuffer = this.MemoryAllocator.Allocate2D<float>(size.Width + 1, size.Height + 1, AllocationOptions.Clean);
using (IMemoryOwner<float> bufferBacking = this.MemoryAllocator.Allocate<float>(path.MaxIntersections))
using (IMemoryOwner<PointF> rowIntersectionBuffer = this.MemoryAllocator.Allocate<PointF>(size.Width))
{
float subpixelFraction = 1f / subpixelCount;
float subpixelFractionPoint = subpixelFraction / subpixelCount;
for (int y = 0; y <= size.Height; y++)
{
Span<float> scanline = fullBuffer.GetRowSpan(y);
bool scanlineDirty = false;
float yPlusOne = y + 1;
for (float subPixel = (float)y; subPixel < yPlusOne; subPixel += subpixelFraction)
{
var start = new PointF(path.Bounds.Left - 1, subPixel);
var end = new PointF(path.Bounds.Right + 1, subPixel);
Span<PointF> intersectionSpan = rowIntersectionBuffer.GetSpan();
Span<float> buffer = bufferBacking.GetSpan();
int pointsFound = path.FindIntersections(start, end, intersectionSpan);
if (pointsFound == 0)
{
// nothing on this line skip
continue;
}
for (int i = 0; i < pointsFound && i < intersectionSpan.Length; i++)
{
buffer[i] = intersectionSpan[i].X;
}
QuickSort.Sort(buffer.Slice(0, pointsFound));
for (int point = 0; point < pointsFound; point += 2)
{
// points will be paired up
float scanStart = buffer[point];
float scanEnd = buffer[point + 1];
int startX = (int)MathF.Floor(scanStart + offset);
int endX = (int)MathF.Floor(scanEnd + offset);
if (startX >= 0 && startX < scanline.Length)
{
for (float x = scanStart; x < startX + 1; x += subpixelFraction)
{
scanline[startX] += subpixelFractionPoint;
scanlineDirty = true;
}
}
if (endX >= 0 && endX < scanline.Length)
{
for (float x = endX; x < scanEnd; x += subpixelFraction)
{
scanline[endX] += subpixelFractionPoint;
scanlineDirty = true;
}
}
int nextX = startX + 1;
endX = Math.Min(endX, scanline.Length); // reduce to end to the right edge
nextX = Math.Max(nextX, 0);
for (int x = nextX; x < endX; x++)
{
scanline[x] += subpixelFraction;
scanlineDirty = true;
}
}
}
if (scanlineDirty)
{
if (!this.Options.Antialias)
{
for (int x = 0; x < size.Width; x++)
{
if (scanline[x] >= 0.5)
{
scanline[x] = 1;
}
else
{
scanline[x] = 0;
}
}
}
}
}
}
return fullBuffer;
}
public void EndText()
{
}
public void LineTo(PointF point)
{
this.builder.AddLine(this.currentPoint, point);
this.currentPoint = point;
}
public void MoveTo(PointF point)
{
this.builder.StartFigure();
this.currentPoint = point;
}
public void QuadraticBezierTo(PointF secondControlPoint, PointF point)
{
this.builder.AddBezier(this.currentPoint, secondControlPoint, point);
this.currentPoint = point;
}
private struct GlyphRenderData : IDisposable
{
public Buffer2D<float> FillMap;
public Buffer2D<float> OutlineMap;
public void Dispose()
{
this.FillMap?.Dispose();
this.OutlineMap?.Dispose();
}
}
}
}
}

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

@ -0,0 +1,105 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing
{
/// <summary>
/// A Circular Gradient Brush, defined by center point and radius.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
public sealed class RadialGradientBrush<TPixel> : GradientBrushBase<TPixel>
where TPixel : struct, IPixel<TPixel>
{
private readonly Point center;
private readonly float radius;
/// <inheritdoc cref="GradientBrushBase{TPixel}" />
/// <param name="center">The center of the circular gradient and 0 for the color stops.</param>
/// <param name="radius">The radius of the circular gradient and 1 for the color stops.</param>
/// <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,
float radius,
GradientRepetitionMode repetitionMode,
params ColorStop<TPixel>[] colorStops)
: base(repetitionMode, colorStops)
{
this.center = center;
this.radius = radius;
}
/// <inheritdoc cref="CreateApplicator" />
public override BrushApplicator<TPixel> CreateApplicator(
ImageFrame<TPixel> source,
RectangleF region,
GraphicsOptions options) =>
new RadialGradientBrushApplicator(
source,
options,
this.center,
this.radius,
this.ColorStops,
this.RepetitionMode);
/// <inheritdoc />
private sealed class RadialGradientBrushApplicator : GradientBrushApplicatorBase
{
private readonly Point center;
private readonly float radius;
/// <summary>
/// Initializes a new instance of the <see cref="RadialGradientBrushApplicator" /> class.
/// </summary>
/// <param name="target">The target image</param>
/// <param name="options">The options.</param>
/// <param name="center">Center point of the gradient.</param>
/// <param name="radius">Radius of the gradient.</param>
/// <param name="colorStops">Definition of colors.</param>
/// <param name="repetitionMode">How the colors are repeated beyond the first gradient.</param>
public RadialGradientBrushApplicator(
ImageFrame<TPixel> target,
GraphicsOptions options,
Point center,
float radius,
ColorStop<TPixel>[] colorStops,
GradientRepetitionMode repetitionMode)
: base(target, options, colorStops, repetitionMode)
{
this.center = center;
this.radius = radius;
}
/// <inheritdoc cref="Dispose" />
public override void Dispose()
{
}
/// <summary>
/// As this is a circular gradient, the position on the gradient is based on
/// the distance of the point to the center.
/// </summary>
/// <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)
{
float distance = (float)Math.Sqrt(Math.Pow(this.center.X - x, 2) + Math.Pow(this.center.Y - y, 2));
return distance / this.radius;
}
internal override void Apply(Span<float> scanline, int x, int y)
{
// TODO: each row is symmetric across center, so we can calculate half of it and mirror it to improve performance.
base.Apply(scanline, x, y);
}
}
}
}

18
src/ImageSharp.Drawing/Processing/Drawing/Brushes/RecolorBrush{TPixel}.cs → src/ImageSharp.Drawing/Processing/RecolorBrush{TPixel}.cs

@ -2,20 +2,22 @@
// Licensed under the Apache License, Version 2.0.
using System;
using System.Buffers;
using System.Numerics;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Memory;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Drawing.Brushes
namespace SixLabors.ImageSharp.Processing
{
/// <summary>
/// Provides an implementation of a brush that can recolor an image
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
public class RecolorBrush<TPixel> : IBrush<TPixel>
where TPixel : struct, IPixel<TPixel>
where TPixel : struct, IPixel<TPixel>
{
/// <summary>
/// Initializes a new instance of the <see cref="RecolorBrush{TPixel}" /> class.
@ -136,13 +138,13 @@ namespace SixLabors.ImageSharp.Processing.Drawing.Brushes
/// <inheritdoc />
internal override void Apply(Span<float> scanline, int x, int y)
{
MemoryManager memoryManager = this.Target.MemoryManager;
MemoryAllocator memoryAllocator = this.Target.MemoryAllocator;
using (IBuffer<float> amountBuffer = memoryManager.Allocate<float>(scanline.Length))
using (IBuffer<TPixel> overlay = memoryManager.Allocate<TPixel>(scanline.Length))
using (IMemoryOwner<float> amountBuffer = memoryAllocator.Allocate<float>(scanline.Length))
using (IMemoryOwner<TPixel> overlay = memoryAllocator.Allocate<TPixel>(scanline.Length))
{
Span<float> amountSpan = amountBuffer.Span;
Span<TPixel> overlaySpan = overlay.Span;
Span<float> amountSpan = amountBuffer.GetSpan();
Span<TPixel> overlaySpan = overlay.GetSpan();
for (int i = 0; i < scanline.Length; i++)
{
@ -156,7 +158,7 @@ namespace SixLabors.ImageSharp.Processing.Drawing.Brushes
}
Span<TPixel> destinationRow = this.Target.GetPixelRowSpan(y).Slice(x, scanline.Length);
this.Blender.Blend(memoryManager, destinationRow, destinationRow, overlaySpan, amountSpan);
this.Blender.Blend(memoryAllocator, destinationRow, destinationRow, overlaySpan, amountSpan);
}
}
}

36
src/ImageSharp.Drawing/Processing/Drawing/Brushes/SolidBrush{TPixel}.cs → src/ImageSharp.Drawing/Processing/SolidBrush{TPixel}.cs

@ -2,12 +2,15 @@
// Licensed under the Apache License, Version 2.0.
using System;
using System.Buffers;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Memory;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Drawing.Brushes
namespace SixLabors.ImageSharp.Processing
{
/// <summary>
/// Provides an implementation of a solid brush for painting solid color areas.
@ -58,14 +61,14 @@ namespace SixLabors.ImageSharp.Processing.Drawing.Brushes
public SolidBrushApplicator(ImageFrame<TPixel> source, TPixel color, GraphicsOptions options)
: base(source, options)
{
this.Colors = source.MemoryManager.Allocate<TPixel>(source.Width);
this.Colors.Span.Fill(color);
this.Colors = source.MemoryAllocator.Allocate<TPixel>(source.Width);
this.Colors.GetSpan().Fill(color);
}
/// <summary>
/// Gets the colors.
/// </summary>
protected IBuffer<TPixel> Colors { get; }
protected IMemoryOwner<TPixel> Colors { get; }
/// <summary>
/// Gets the color for a single pixel.
@ -75,7 +78,7 @@ namespace SixLabors.ImageSharp.Processing.Drawing.Brushes
/// <returns>
/// The color
/// </returns>
internal override TPixel this[int x, int y] => this.Colors.Span[x];
internal override TPixel this[int x, int y] => this.Colors.GetSpan()[x];
/// <inheritdoc />
public override void Dispose()
@ -88,18 +91,25 @@ namespace SixLabors.ImageSharp.Processing.Drawing.Brushes
{
Span<TPixel> destinationRow = this.Target.GetPixelRowSpan(y).Slice(x, scanline.Length);
MemoryManager memoryManager = this.Target.MemoryManager;
MemoryAllocator memoryAllocator = this.Target.MemoryAllocator;
using (IBuffer<float> amountBuffer = memoryManager.Allocate<float>(scanline.Length))
if (this.Options.BlendPercentage == 1f)
{
Span<float> amountSpan = amountBuffer.Span;
for (int i = 0; i < scanline.Length; i++)
this.Blender.Blend(memoryAllocator, destinationRow, destinationRow, this.Colors.GetSpan(), scanline);
}
else
{
using (IMemoryOwner<float> amountBuffer = memoryAllocator.Allocate<float>(scanline.Length))
{
amountSpan[i] = scanline[i] * this.Options.BlendPercentage;
}
Span<float> amountSpan = amountBuffer.GetSpan();
for (int i = 0; i < scanline.Length; i++)
{
amountSpan[i] = scanline[i] * this.Options.BlendPercentage;
}
this.Blender.Blend(memoryManager, destinationRow, destinationRow, this.Colors.Span, amountSpan);
this.Blender.Blend(memoryAllocator, destinationRow, destinationRow, this.Colors.GetSpan(), amountSpan);
}
}
}
}

179
src/ImageSharp.Drawing/Processing/Text/DrawTextExtensions.Path.cs

@ -1,179 +0,0 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.Fonts;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Drawing;
using SixLabors.ImageSharp.Processing.Drawing.Brushes;
using SixLabors.ImageSharp.Processing.Drawing.Pens;
using SixLabors.Shapes;
namespace SixLabors.ImageSharp.Processing.Text
{
/// <summary>
/// Adds extensions that allow the drawing of text along given paths to the <see cref="Image{TPixel}"/> type.
/// </summary>
public static partial class DrawTextExtensions
{
/// <summary>
/// Draws the text onto the the image filled via the brush.
/// </summary>
/// <typeparam name="TPixel">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="text">The text.</param>
/// <param name="font">The font.</param>
/// <param name="color">The color.</param>
/// <param name="path">The path.</param>
/// <returns>
/// The <see cref="Image{TPixel}" />.
/// </returns>
public static IImageProcessingContext<TPixel> DrawText<TPixel>(this IImageProcessingContext<TPixel> source, string text, Font font, TPixel color, IPath path)
where TPixel : struct, IPixel<TPixel>
=> source.DrawText(text, font, color, path, TextGraphicsOptions.Default);
/// <summary>
/// Draws the text onto the the image filled via the brush.
/// </summary>
/// <typeparam name="TPixel">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="text">The text.</param>
/// <param name="font">The font.</param>
/// <param name="color">The color.</param>
/// <param name="path">The path.</param>
/// <param name="options">The options.</param>
/// <returns>
/// The <see cref="Image{TPixel}" />.
/// </returns>
public static IImageProcessingContext<TPixel> DrawText<TPixel>(this IImageProcessingContext<TPixel> source, string text, Font font, TPixel color, IPath path, TextGraphicsOptions options)
where TPixel : struct, IPixel<TPixel>
=> source.DrawText(text, font, Brushes.Solid(color), null, path, options);
/// <summary>
/// Draws the text onto the the image filled via the brush.
/// </summary>
/// <typeparam name="TPixel">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="text">The text.</param>
/// <param name="font">The font.</param>
/// <param name="brush">The brush.</param>
/// <param name="path">The location.</param>
/// <returns>
/// The <see cref="Image{TPixel}" />.
/// </returns>
public static IImageProcessingContext<TPixel> DrawText<TPixel>(this IImageProcessingContext<TPixel> source, string text, Font font, IBrush<TPixel> brush, IPath path)
where TPixel : struct, IPixel<TPixel>
=> source.DrawText(text, font, brush, path, TextGraphicsOptions.Default);
/// <summary>
/// Draws the text onto the the image filled via the brush.
/// </summary>
/// <typeparam name="TPixel">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="text">The text.</param>
/// <param name="font">The font.</param>
/// <param name="brush">The brush.</param>
/// <param name="path">The path.</param>
/// <param name="options">The options.</param>
/// <returns>
/// The <see cref="Image{TPixel}" />.
/// </returns>
public static IImageProcessingContext<TPixel> DrawText<TPixel>(this IImageProcessingContext<TPixel> source, string text, Font font, IBrush<TPixel> brush, IPath path, TextGraphicsOptions options)
where TPixel : struct, IPixel<TPixel>
=> source.DrawText(text, font, brush, null, path, options);
/// <summary>
/// Draws the text onto the the image outlined via the pen.
/// </summary>
/// <typeparam name="TPixel">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="text">The text.</param>
/// <param name="font">The font.</param>
/// <param name="pen">The pen.</param>
/// <param name="path">The path.</param>
/// <returns>
/// The <see cref="Image{TPixel}" />.
/// </returns>
public static IImageProcessingContext<TPixel> DrawText<TPixel>(this IImageProcessingContext<TPixel> source, string text, Font font, IPen<TPixel> pen, IPath path)
where TPixel : struct, IPixel<TPixel>
=> source.DrawText(text, font, pen, path, TextGraphicsOptions.Default);
/// <summary>
/// Draws the text onto the the image outlined via the pen.
/// </summary>
/// <typeparam name="TPixel">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="text">The text.</param>
/// <param name="font">The font.</param>
/// <param name="pen">The pen.</param>
/// <param name="path">The path.</param>
/// <param name="options">The options.</param>
/// <returns>
/// The <see cref="Image{TPixel}" />.
/// </returns>
public static IImageProcessingContext<TPixel> DrawText<TPixel>(this IImageProcessingContext<TPixel> source, string text, Font font, IPen<TPixel> pen, IPath path, TextGraphicsOptions options)
where TPixel : struct, IPixel<TPixel>
=> source.DrawText(text, font, null, pen, path, options);
/// <summary>
/// Draws the text onto the the image filled via the brush then outlined via the pen.
/// </summary>
/// <typeparam name="TPixel">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="text">The text.</param>
/// <param name="font">The font.</param>
/// <param name="brush">The brush.</param>
/// <param name="pen">The pen.</param>
/// <param name="path">The path.</param>
/// <returns>
/// The <see cref="Image{TPixel}" />.
/// </returns>
public static IImageProcessingContext<TPixel> DrawText<TPixel>(this IImageProcessingContext<TPixel> source, string text, Font font, IBrush<TPixel> brush, IPen<TPixel> pen, IPath path)
where TPixel : struct, IPixel<TPixel>
=> source.DrawText(text, font, brush, pen, path, TextGraphicsOptions.Default);
/// <summary>
/// Draws the text onto the the image filled via the brush then outlined via the pen.
/// </summary>
/// <typeparam name="TPixel">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="text">The text.</param>
/// <param name="font">The font.</param>
/// <param name="brush">The brush.</param>
/// <param name="pen">The pen.</param>
/// <param name="path">The path.</param>
/// <param name="options">The options.</param>
/// <returns>
/// The <see cref="Image{TPixel}" />.
/// </returns>
public static IImageProcessingContext<TPixel> DrawText<TPixel>(this IImageProcessingContext<TPixel> source, string text, Font font, IBrush<TPixel> brush, IPen<TPixel> pen, IPath path, TextGraphicsOptions options)
where TPixel : struct, IPixel<TPixel>
{
float dpiX = DefaultTextDpi;
float dpiY = DefaultTextDpi;
var style = new RendererOptions(font, dpiX, dpiY)
{
ApplyKerning = options.ApplyKerning,
TabWidth = options.TabWidth,
WrappingWidth = options.WrapTextWidth,
HorizontalAlignment = options.HorizontalAlignment,
VerticalAlignment = options.VerticalAlignment
};
IPathCollection glyphs = TextBuilder.GenerateGlyphs(text, path, style);
var pathOptions = (GraphicsOptions)options;
if (brush != null)
{
source.Fill(brush, glyphs, pathOptions);
}
if (pen != null)
{
source.Draw(pen, glyphs, pathOptions);
}
return source;
}
}
}

43
src/ImageSharp.Drawing/Processing/Text/TextGraphicsOptions.cs → src/ImageSharp.Drawing/Processing/TextGraphicsOptions.cs

@ -4,13 +4,15 @@
using SixLabors.Fonts;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Processing.Text
namespace SixLabors.ImageSharp.Processing
{
/// <summary>
/// Options for influencing the drawing functions.
/// </summary>
public struct TextGraphicsOptions
{
private const int DefaultTextDpi = 72;
/// <summary>
/// Represents the default <see cref="TextGraphicsOptions"/>.
/// </summary>
@ -26,11 +28,18 @@ namespace SixLabors.ImageSharp.Processing.Text
private float? tabWidth;
private PixelBlenderMode blenderMode;
private float? dpiX;
private float? dpiY;
private PixelColorBlendingMode colorBlendingMode;
private PixelAlphaCompositionMode alphaCompositionMode;
private float wrapTextWidth;
private HorizontalAlignment? horizontalAlignment;
private VerticalAlignment? verticalAlignment;
/// <summary>
@ -46,9 +55,12 @@ namespace SixLabors.ImageSharp.Processing.Text
this.verticalAlignment = VerticalAlignment.Top;
this.antialiasSubpixelDepth = 16;
this.blenderMode = PixelBlenderMode.Normal;
this.colorBlendingMode = PixelColorBlendingMode.Normal;
this.alphaCompositionMode = PixelAlphaCompositionMode.SrcOver;
this.blendPercentage = 1;
this.antialias = enableAntialiasing;
this.dpiX = DefaultTextDpi;
this.dpiY = DefaultTextDpi;
}
/// <summary>
@ -71,9 +83,14 @@ namespace SixLabors.ImageSharp.Processing.Text
// some API thought post V1.
/// <summary>
/// Gets or sets a value indicating the blending percentage to apply to the drawing operation
/// Gets or sets a value indicating the color blending percentage to apply to the drawing operation
/// </summary>
public PixelColorBlendingMode ColorBlendingMode { get => this.colorBlendingMode; set => this.colorBlendingMode = value; }
/// <summary>
/// Gets or sets a value indicating the color blending percentage to apply to the drawing operation
/// </summary>
public PixelBlenderMode BlenderMode { get => this.blenderMode; set => this.blenderMode = value; }
public PixelAlphaCompositionMode AlphaCompositionMode { get => this.alphaCompositionMode; set => this.alphaCompositionMode = value; }
/// <summary>
/// Gets or sets a value indicating whether the text should be drawing with kerning enabled.
@ -90,6 +107,16 @@ namespace SixLabors.ImageSharp.Processing.Text
/// </summary>
public float WrapTextWidth { get => this.wrapTextWidth; set => this.wrapTextWidth = value; }
/// <summary>
/// Gets or sets a value indicating the DPI to render text along the X axis.
/// </summary>
public float DpiX { get => this.dpiX ?? DefaultTextDpi; set => this.dpiX = value; }
/// <summary>
/// Gets or sets a value indicating the DPI to render text along the Y axis.
/// </summary>
public float DpiY { get => this.dpiY ?? DefaultTextDpi; set => this.dpiY = value; }
/// <summary>
/// Gets or sets a value indicating how to align the text relative to the rendering space.
/// If <see cref="WrapTextWidth"/> is greater than zero it will align relative to the space
@ -116,7 +143,8 @@ namespace SixLabors.ImageSharp.Processing.Text
{
AntialiasSubpixelDepth = options.AntialiasSubpixelDepth,
blendPercentage = options.BlendPercentage,
blenderMode = options.BlenderMode
colorBlendingMode = options.ColorBlendingMode,
alphaCompositionMode = options.AlphaCompositionMode
};
}
@ -132,7 +160,8 @@ namespace SixLabors.ImageSharp.Processing.Text
return new GraphicsOptions(options.Antialias)
{
AntialiasSubpixelDepth = options.AntialiasSubpixelDepth,
BlenderMode = options.BlenderMode,
ColorBlendingMode = options.ColorBlendingMode,
AlphaCompositionMode = options.AlphaCompositionMode,
BlendPercentage = options.BlendPercentage
};
}

84
src/ImageSharp.Drawing/Utils/QuickSort.cs

@ -0,0 +1,84 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.Utils
{
/// <summary>
/// Optimized quick sort implementation for Span{float} input
/// </summary>
internal class QuickSort
{
/// <summary>
/// Sorts the elements of <paramref name="data"/> in ascending order
/// </summary>
/// <param name="data">The items to sort</param>
public static void Sort(Span<float> data)
{
if (data.Length < 2)
{
return;
}
if (data.Length == 2)
{
if (data[0] > data[1])
{
Swap(ref data[0], ref data[1]);
}
return;
}
Sort(ref data[0], 0, data.Length - 1);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void Swap(ref float left, ref float right)
{
float tmp = left;
left = right;
right = tmp;
}
private static void Sort(ref float data0, int lo, int hi)
{
if (lo < hi)
{
int p = Partition(ref data0, lo, hi);
Sort(ref data0, lo, p);
Sort(ref data0, p + 1, hi);
}
}
private static int Partition(ref float data0, int lo, int hi)
{
float pivot = Unsafe.Add(ref data0, lo);
int i = lo - 1;
int j = hi + 1;
while (true)
{
do
{
i = i + 1;
}
while (Unsafe.Add(ref data0, i) < pivot && i < hi);
do
{
j = j - 1;
}
while (Unsafe.Add(ref data0, j) > pivot && j > lo);
if (i >= j)
{
return j;
}
Swap(ref Unsafe.Add(ref data0, i), ref Unsafe.Add(ref data0, j));
}
}
}
}

114
src/ImageSharp/Advanced/AdvancedImageExtensions.cs

@ -3,8 +3,10 @@
using System;
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Memory;
namespace SixLabors.ImageSharp.Advanced
{
@ -23,6 +25,52 @@ namespace SixLabors.ImageSharp.Advanced
where TPixel : struct, IPixel<TPixel>
=> GetConfiguration((IConfigurable)source);
/// <summary>
/// Gets the representation of the pixels as a <see cref="Span{T}"/> of contiguous memory in the source image's pixel format
/// stored in row major order.
/// </summary>
/// <typeparam name="TPixel">The type of the pixel.</typeparam>
/// <param name="source">The source.</param>
/// <returns>The <see cref="Span{TPixel}"/></returns>
public static Span<TPixel> GetPixelSpan<TPixel>(this ImageFrame<TPixel> source)
where TPixel : struct, IPixel<TPixel>
=> source.GetPixelMemory().Span;
/// <summary>
/// Gets the representation of the pixels as a <see cref="Span{T}"/> of contiguous memory in the source image's pixel format
/// stored in row major order.
/// </summary>
/// <typeparam name="TPixel">The type of the pixel.</typeparam>
/// <param name="source">The source.</param>
/// <returns>The <see cref="Span{TPixel}"/></returns>
public static Span<TPixel> GetPixelSpan<TPixel>(this Image<TPixel> source)
where TPixel : struct, IPixel<TPixel>
=> source.Frames.RootFrame.GetPixelSpan();
/// <summary>
/// Gets the representation of the pixels as a <see cref="Span{T}"/> of contiguous memory
/// at row <paramref name="rowIndex"/> beginning from the the first pixel on that row.
/// </summary>
/// <typeparam name="TPixel">The type of the pixel.</typeparam>
/// <param name="source">The source.</param>
/// <param name="rowIndex">The row.</param>
/// <returns>The <see cref="Span{TPixel}"/></returns>
public static Span<TPixel> GetPixelRowSpan<TPixel>(this ImageFrame<TPixel> source, int rowIndex)
where TPixel : struct, IPixel<TPixel>
=> source.PixelBuffer.GetRowSpan(rowIndex);
/// <summary>
/// Gets the representation of the pixels as <see cref="Span{T}"/> of of contiguous memory
/// at row <paramref name="rowIndex"/> beginning from the the first pixel on that row.
/// </summary>
/// <typeparam name="TPixel">The type of the pixel.</typeparam>
/// <param name="source">The source.</param>
/// <param name="rowIndex">The row.</param>
/// <returns>The <see cref="Span{TPixel}"/></returns>
public static Span<TPixel> GetPixelRowSpan<TPixel>(this Image<TPixel> source, int rowIndex)
where TPixel : struct, IPixel<TPixel>
=> source.Frames.RootFrame.GetPixelRowSpan(rowIndex);
/// <summary>
/// Returns a reference to the 0th element of the Pixel buffer,
/// allowing direct manipulation of pixel data through unsafe operations.
@ -31,9 +79,10 @@ namespace SixLabors.ImageSharp.Advanced
/// <typeparam name="TPixel">The Pixel format.</typeparam>
/// <param name="source">The source image frame</param>
/// <returns>A pinnable reference the first root of the pixel buffer.</returns>
[Obsolete("This method will be removed in our next release! Please use MemoryMarshal.GetReference(source.GetPixelSpan())!")]
public static ref TPixel DangerousGetPinnableReferenceToPixelBuffer<TPixel>(this ImageFrame<TPixel> source)
where TPixel : struct, IPixel<TPixel>
=> ref DangerousGetPinnableReferenceToPixelBuffer((IPixelSource<TPixel>)source);
=> ref DangerousGetPinnableReferenceToPixelBuffer((IPixelSource<TPixel>)source);
/// <summary>
/// Returns a reference to the 0th element of the Pixel buffer,
@ -43,59 +92,68 @@ namespace SixLabors.ImageSharp.Advanced
/// <typeparam name="TPixel">The Pixel format.</typeparam>
/// <param name="source">The source image</param>
/// <returns>A pinnable reference the first root of the pixel buffer.</returns>
[Obsolete("This method will be removed in our next release! Please use MemoryMarshal.GetReference(source.GetPixelSpan())!")]
public static ref TPixel DangerousGetPinnableReferenceToPixelBuffer<TPixel>(this Image<TPixel> source)
where TPixel : struct, IPixel<TPixel>
=> ref source.Frames.RootFrame.DangerousGetPinnableReferenceToPixelBuffer();
=> ref source.Frames.RootFrame.DangerousGetPinnableReferenceToPixelBuffer();
/// <summary>
/// Gets the representation of the pixels as an area of contiguous memory in the given pixel format.
/// Gets the representation of the pixels as a <see cref="Memory{T}"/> of contiguous memory in the source image's pixel format
/// stored in row major order.
/// </summary>
/// <typeparam name="TPixel">The type of the pixel.</typeparam>
/// <param name="source">The source.</param>
/// <returns>The <see cref="Span{TPixel}"/></returns>
internal static Span<TPixel> GetPixelSpan<TPixel>(this ImageFrame<TPixel> source)
/// <typeparam name="TPixel">The Pixel format.</typeparam>
/// <param name="source">The source <see cref="ImageFrame{TPixel}"/></param>
/// <returns>The <see cref="Memory{T}"/></returns>
internal static Memory<TPixel> GetPixelMemory<TPixel>(this ImageFrame<TPixel> source)
where TPixel : struct, IPixel<TPixel>
=> GetSpan(source);
{
return source.PixelBuffer.MemorySource.Memory;
}
/// <summary>
/// Gets the representation of the pixels as an area of contiguous memory at row 'y' beginning from the the first pixel on that row.
/// Gets the representation of the pixels as a <see cref="Memory{T}"/> of contiguous memory in the source image's pixel format
/// stored in row major order.
/// </summary>
/// <typeparam name="TPixel">The type of the pixel.</typeparam>
/// <param name="source">The source.</param>
/// <param name="row">The row.</param>
/// <returns>The <see cref="Span{TPixel}"/></returns>
internal static Span<TPixel> GetPixelRowSpan<TPixel>(this ImageFrame<TPixel> source, int row)
/// <typeparam name="TPixel">The Pixel format.</typeparam>
/// <param name="source">The source <see cref="Image{TPixel}"/></param>
/// <returns>The <see cref="Memory{T}"/></returns>
internal static Memory<TPixel> GetPixelMemory<TPixel>(this Image<TPixel> source)
where TPixel : struct, IPixel<TPixel>
=> GetSpan(source, row);
{
return source.Frames.RootFrame.GetPixelMemory();
}
/// <summary>
/// Gets the representation of the pixels as an area of contiguous memory in the given pixel format.
/// Gets the representation of the pixels as a <see cref="Span{T}"/> of contiguous memory
/// at row <paramref name="rowIndex"/> beginning from the the first pixel on that row.
/// </summary>
/// <typeparam name="TPixel">The type of the pixel.</typeparam>
/// <param name="source">The source.</param>
/// <param name="rowIndex">The row.</param>
/// <returns>The <see cref="Span{TPixel}"/></returns>
internal static Span<TPixel> GetPixelSpan<TPixel>(this Image<TPixel> source)
internal static Memory<TPixel> GetPixelRowMemory<TPixel>(this ImageFrame<TPixel> source, int rowIndex)
where TPixel : struct, IPixel<TPixel>
=> source.Frames.RootFrame.GetPixelSpan();
=> source.PixelBuffer.GetRowMemory(rowIndex);
/// <summary>
/// Gets the representation of the pixels as an area of contiguous memory at row 'y' beginning from the the first pixel on that row.
/// Gets the representation of the pixels as <see cref="Span{T}"/> of of contiguous memory
/// at row <paramref name="rowIndex"/> beginning from the the first pixel on that row.
/// </summary>
/// <typeparam name="TPixel">The type of the pixel.</typeparam>
/// <param name="source">The source.</param>
/// <param name="row">The row.</param>
/// <param name="rowIndex">The row.</param>
/// <returns>The <see cref="Span{TPixel}"/></returns>
internal static Span<TPixel> GetPixelRowSpan<TPixel>(this Image<TPixel> source, int row)
internal static Memory<TPixel> GetPixelRowMemory<TPixel>(this Image<TPixel> source, int rowIndex)
where TPixel : struct, IPixel<TPixel>
=> source.Frames.RootFrame.GetPixelRowSpan(row);
=> source.Frames.RootFrame.GetPixelRowMemory(rowIndex);
/// <summary>
/// Gets the <see cref="MemoryManager"/> assigned to 'source'.
/// Gets the <see cref="MemoryAllocator"/> assigned to 'source'.
/// </summary>
/// <param name="source">The source image</param>
/// <returns>Returns the configuration.</returns>
internal static MemoryManager GetMemoryManager(this IConfigurable source)
=> GetConfiguration(source).MemoryManager;
internal static MemoryAllocator GetMemoryAllocator(this IConfigurable source)
=> GetConfiguration(source).MemoryAllocator;
/// <summary>
/// Gets the span to the backing buffer.
@ -105,7 +163,7 @@ namespace SixLabors.ImageSharp.Advanced
/// <returns>The span retuned from Pixel source</returns>
private static Span<TPixel> GetSpan<TPixel>(IPixelSource<TPixel> source)
where TPixel : struct, IPixel<TPixel>
=> source.PixelBuffer.Span;
=> source.PixelBuffer.GetSpan();
/// <summary>
/// Gets the span to the backing buffer at the given row.
@ -131,7 +189,7 @@ namespace SixLabors.ImageSharp.Advanced
/// </returns>
private static Span<TPixel> GetSpan<TPixel>(Buffer2D<TPixel> source, int row)
where TPixel : struct, IPixel<TPixel>
=> source.Span.Slice(row * source.Width, source.Width);
=> source.GetSpan().Slice(row * source.Width, source.Width);
/// <summary>
/// Gets the configuration.
@ -149,6 +207,6 @@ namespace SixLabors.ImageSharp.Advanced
/// <returns>A reference to the element.</returns>
private static ref TPixel DangerousGetPinnableReferenceToPixelBuffer<TPixel>(IPixelSource<TPixel> source)
where TPixel : struct, IPixel<TPixel>
=> ref MemoryMarshal.GetReference(source.PixelBuffer.Span);
=> ref MemoryMarshal.GetReference(source.PixelBuffer.GetSpan());
}
}

2
src/ImageSharp/Advanced/IConfigurable.cs

@ -4,7 +4,7 @@
namespace SixLabors.ImageSharp.Advanced
{
/// <summary>
/// Encapsulates the properties for configuration
/// Encapsulates the properties for configuration.
/// </summary>
internal interface IConfigurable
{

1
src/ImageSharp/Advanced/IPixelSource.cs

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

47
src/ImageSharp/ColorSpaces/CieLab.cs

@ -20,11 +20,6 @@ namespace SixLabors.ImageSharp.ColorSpaces
/// </summary>
public static readonly CieXyz DefaultWhitePoint = Illuminants.D50;
/// <summary>
/// Represents a <see cref="CieLab"/> that has L, A, B values set to zero.
/// </summary>
public static readonly CieLab Empty = default(CieLab);
/// <summary>
/// The backing vector for SIMD support.
/// </summary>
@ -83,11 +78,7 @@ namespace SixLabors.ImageSharp.ColorSpaces
/// <summary>
/// Gets the reference white point of this color
/// </summary>
public CieXyz WhitePoint
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get;
}
public CieXyz WhitePoint { get; }
/// <summary>
/// Gets the lightness dimension.
@ -119,18 +110,8 @@ namespace SixLabors.ImageSharp.ColorSpaces
get => this.backingVector.Z;
}
/// <summary>
/// Gets a value indicating whether this <see cref="CieLab"/> is empty.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
public bool IsEmpty => this.Equals(Empty);
/// <inheritdoc />
public Vector3 Vector
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => this.backingVector;
}
public Vector3 Vector => this.backingVector;
/// <summary>
/// Compares two <see cref="CieLab"/> objects for equality.
@ -171,35 +152,21 @@ namespace SixLabors.ImageSharp.ColorSpaces
/// <inheritdoc/>
public override int GetHashCode()
{
unchecked
{
int hashCode = this.WhitePoint.GetHashCode();
hashCode = (hashCode * 397) ^ this.backingVector.GetHashCode();
return hashCode;
}
return HashHelpers.Combine(this.WhitePoint.GetHashCode(), this.backingVector.GetHashCode());
}
/// <inheritdoc/>
public override string ToString()
{
if (this.IsEmpty)
{
return "CieLab [Empty]";
}
return $"CieLab [ L={this.L:#0.##}, A={this.A:#0.##}, B={this.B:#0.##}]";
return this.Equals(default)
? "CieLab [Empty]"
: $"CieLab [ L={this.L:#0.##}, A={this.A:#0.##}, B={this.B:#0.##}]";
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override bool Equals(object obj)
{
if (obj is CieLab)
{
return this.Equals((CieLab)obj);
}
return false;
return obj is CieLab other && this.Equals(other);
}
/// <inheritdoc/>

46
src/ImageSharp/ColorSpaces/CieLch.cs

@ -20,11 +20,6 @@ namespace SixLabors.ImageSharp.ColorSpaces
/// </summary>
public static readonly CieXyz DefaultWhitePoint = Illuminants.D50;
/// <summary>
/// Represents a <see cref="CieLch"/> that has L, C, H values set to zero.
/// </summary>
public static readonly CieLch Empty = default(CieLch);
/// <summary>
/// The backing vector for SIMD support.
/// </summary>
@ -83,11 +78,7 @@ namespace SixLabors.ImageSharp.ColorSpaces
/// <summary>
/// Gets the reference white point of this color
/// </summary>
public CieXyz WhitePoint
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get;
}
public CieXyz WhitePoint { get; }
/// <summary>
/// Gets the lightness dimension.
@ -119,18 +110,8 @@ namespace SixLabors.ImageSharp.ColorSpaces
get => this.backingVector.Z;
}
/// <summary>
/// Gets a value indicating whether this <see cref="CieLch"/> is empty.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
public bool IsEmpty => this.Equals(Empty);
/// <inheritdoc />
public Vector3 Vector
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => this.backingVector;
}
public Vector3 Vector => this.backingVector;
/// <summary>
/// Compares two <see cref="CieLch"/> objects for equality.
@ -171,35 +152,22 @@ namespace SixLabors.ImageSharp.ColorSpaces
/// <inheritdoc/>
public override int GetHashCode()
{
unchecked
{
int hashCode = this.WhitePoint.GetHashCode();
hashCode = (hashCode * 397) ^ this.backingVector.GetHashCode();
return hashCode;
}
return HashHelpers.Combine(this.WhitePoint.GetHashCode(), this.backingVector.GetHashCode());
}
/// <inheritdoc/>
public override string ToString()
{
if (this.IsEmpty)
{
return "CieLch [Empty]";
}
return $"CieLch [ L={this.L:#0.##}, C={this.C:#0.##}, H={this.H:#0.##}]";
return this.Equals(default)
? "CieLch [Empty]"
: $"CieLch [ L={this.L:#0.##}, C={this.C:#0.##}, H={this.H:#0.##}]";
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override bool Equals(object obj)
{
if (obj is CieLch)
{
return this.Equals((CieLch)obj);
}
return false;
return obj is CieLch other && this.Equals(other);
}
/// <inheritdoc/>

50
src/ImageSharp/ColorSpaces/CieLchuv.cs

@ -20,11 +20,6 @@ namespace SixLabors.ImageSharp.ColorSpaces
/// </summary>
public static readonly CieXyz DefaultWhitePoint = Illuminants.D65;
/// <summary>
/// Represents a <see cref="CieLchuv"/> that has L, C, H values set to zero.
/// </summary>
public static readonly CieLchuv Empty = default(CieLchuv);
/// <summary>
/// The backing vector for SIMD support.
/// </summary>
@ -83,11 +78,7 @@ namespace SixLabors.ImageSharp.ColorSpaces
/// <summary>
/// Gets the reference white point of this color
/// </summary>
public CieXyz WhitePoint
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get;
}
public CieXyz WhitePoint { get; }
/// <summary>
/// Gets the lightness dimension.
@ -119,18 +110,8 @@ namespace SixLabors.ImageSharp.ColorSpaces
get => this.backingVector.Z;
}
/// <summary>
/// Gets a value indicating whether this <see cref="CieLchuv"/> is empty.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
public bool IsEmpty => this.Equals(Empty);
/// <inheritdoc />
public Vector3 Vector
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => this.backingVector;
}
public Vector3 Vector => this.backingVector;
/// <summary>
/// Compares two <see cref="CieLchuv"/> objects for equality.
@ -144,7 +125,6 @@ namespace SixLabors.ImageSharp.ColorSpaces
/// <returns>
/// True if the current left is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(CieLchuv left, CieLchuv right)
{
return left.Equals(right);
@ -162,44 +142,30 @@ namespace SixLabors.ImageSharp.ColorSpaces
/// <returns>
/// True if the current left is unequal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(CieLchuv left, CieLchuv right)
{
return !left.Equals(right);
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override int GetHashCode()
{
unchecked
{
int hashCode = this.WhitePoint.GetHashCode();
hashCode = (hashCode * 397) ^ this.backingVector.GetHashCode();
return hashCode;
}
return HashHelpers.Combine(this.WhitePoint.GetHashCode(), this.backingVector.GetHashCode());
}
/// <inheritdoc/>
public override string ToString()
{
if (this.IsEmpty)
{
return "CieLchuv [Empty]";
}
return $"CieLchuv [ L={this.L:#0.##}, C={this.C:#0.##}, H={this.H:#0.##}]";
return this.Equals(default)
? "CieLchuv [Empty]"
: $"CieLchuv [ L={this.L:#0.##}, C={this.C:#0.##}, H={this.H:#0.##}";
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override bool Equals(object obj)
{
if (obj is CieLchuv)
{
return this.Equals((CieLchuv)obj);
}
return false;
return obj is CieLchuv other && this.Equals(other);
}
/// <inheritdoc/>

47
src/ImageSharp/ColorSpaces/CieLuv.cs

@ -22,11 +22,6 @@ namespace SixLabors.ImageSharp.ColorSpaces
/// </summary>
public static readonly CieXyz DefaultWhitePoint = Illuminants.D65;
/// <summary>
/// Represents a <see cref="CieLuv"/> that has L, U, and V values set to zero.
/// </summary>
public static readonly CieLuv Empty = default(CieLuv);
/// <summary>
/// The backing vector for SIMD support.
/// </summary>
@ -85,11 +80,7 @@ namespace SixLabors.ImageSharp.ColorSpaces
/// <summary>
/// Gets the reference white point of this color
/// </summary>
public CieXyz WhitePoint
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get;
}
public CieXyz WhitePoint { get; }
/// <summary>
/// Gets the lightness dimension
@ -121,18 +112,8 @@ namespace SixLabors.ImageSharp.ColorSpaces
get => this.backingVector.Z;
}
/// <summary>
/// Gets a value indicating whether this <see cref="CieLuv"/> is empty.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
public bool IsEmpty => this.Equals(Empty);
/// <inheritdoc />
public Vector3 Vector
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => this.backingVector;
}
public Vector3 Vector => this.backingVector;
/// <summary>
/// Compares two <see cref="CieLuv"/> objects for equality.
@ -173,35 +154,21 @@ namespace SixLabors.ImageSharp.ColorSpaces
/// <inheritdoc/>
public override int GetHashCode()
{
unchecked
{
int hashCode = this.WhitePoint.GetHashCode();
hashCode = (hashCode * 397) ^ this.backingVector.GetHashCode();
return hashCode;
}
return HashHelpers.Combine(this.WhitePoint.GetHashCode(), this.backingVector.GetHashCode());
}
/// <inheritdoc/>
public override string ToString()
{
if (this.IsEmpty)
{
return "CieLuv [ Empty ]";
}
return $"CieLuv [ L={this.L:#0.##}, U={this.U:#0.##}, V={this.V:#0.##} ]";
return this.Equals(default)
? "CieLuv [ Empty ]"
: $"CieLuv [ L={this.L:#0.##}, U={this.U:#0.##}, V={this.V:#0.##} ]";
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override bool Equals(object obj)
{
if (obj is CieLuv)
{
return this.Equals((CieLuv)obj);
}
return false;
return obj is CieLuv other && this.Equals(other);
}
/// <inheritdoc/>

29
src/ImageSharp/ColorSpaces/CieXyChromaticityCoordinates.cs

@ -14,11 +14,6 @@ namespace SixLabors.ImageSharp.ColorSpaces
/// </summary>
internal readonly struct CieXyChromaticityCoordinates : IEquatable<CieXyChromaticityCoordinates>, IAlmostEquatable<CieXyChromaticityCoordinates, float>
{
/// <summary>
/// Represents a <see cref="CieXyChromaticityCoordinates"/> that has X, Y values set to zero.
/// </summary>
public static readonly CieXyChromaticityCoordinates Empty = default(CieXyChromaticityCoordinates);
/// <summary>
/// The backing vector for SIMD support.
/// </summary>
@ -69,12 +64,6 @@ namespace SixLabors.ImageSharp.ColorSpaces
get => this.backingVector.Y;
}
/// <summary>
/// Gets a value indicating whether this <see cref="CieXyChromaticityCoordinates"/> is empty.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
public bool IsEmpty => this.Equals(Empty);
/// <summary>
/// Compares two <see cref="CieXyChromaticityCoordinates"/> objects for equality.
/// </summary>
@ -112,6 +101,7 @@ namespace SixLabors.ImageSharp.ColorSpaces
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override int GetHashCode()
{
return this.backingVector.GetHashCode();
@ -120,24 +110,15 @@ namespace SixLabors.ImageSharp.ColorSpaces
/// <inheritdoc/>
public override string ToString()
{
if (this.IsEmpty)
{
return "CieXyChromaticityCoordinates [Empty]";
}
return $"CieXyChromaticityCoordinates [ X={this.X:#0.##}, Y={this.Y:#0.##}]";
return this.Equals(default)
? "CieXyChromaticityCoordinates [Empty]"
: $"CieXyChromaticityCoordinates [ X={this.X:#0.##}, Y={this.Y:#0.##}]";
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override bool Equals(object obj)
{
if (obj is CieXyChromaticityCoordinates)
{
return this.Equals((CieXyChromaticityCoordinates)obj);
}
return false;
return obj is CieXyChromaticityCoordinates other && this.Equals(other);
}
/// <inheritdoc/>

35
src/ImageSharp/ColorSpaces/CieXyy.cs

@ -14,11 +14,6 @@ namespace SixLabors.ImageSharp.ColorSpaces
/// </summary>
internal readonly struct CieXyy : IColorVector, IEquatable<CieXyy>, IAlmostEquatable<CieXyy, float>
{
/// <summary>
/// Represents a <see cref="CieXyy"/> that has X, Y, and Y values set to zero.
/// </summary>
public static readonly CieXyy Empty = default(CieXyy);
/// <summary>
/// The backing vector for SIMD support.
/// </summary>
@ -78,18 +73,8 @@ namespace SixLabors.ImageSharp.ColorSpaces
get => this.backingVector.Z;
}
/// <summary>
/// Gets a value indicating whether this <see cref="CieXyy"/> is empty.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
public bool IsEmpty => this.Equals(Empty);
/// <inheritdoc />
public Vector3 Vector
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => this.backingVector;
}
public Vector3 Vector => this.backingVector;
/// <summary>
/// Compares two <see cref="CieXyy"/> objects for equality.
@ -128,6 +113,7 @@ namespace SixLabors.ImageSharp.ColorSpaces
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override int GetHashCode()
{
return this.backingVector.GetHashCode();
@ -136,24 +122,15 @@ namespace SixLabors.ImageSharp.ColorSpaces
/// <inheritdoc/>
public override string ToString()
{
if (this.IsEmpty)
{
return "CieXyy [ Empty ]";
}
return $"CieXyy [ X={this.X:#0.##}, Y={this.Y:#0.##}, Yl={this.Yl:#0.##} ]";
return this.Equals(default)
? "CieXyy [ Empty ]"
: $"CieXyy [ X={this.X:#0.##}, Y={this.Y:#0.##}, Yl={this.Yl:#0.##} ]";
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override bool Equals(object obj)
{
if (obj is CieXyy)
{
return this.Equals((CieXyy)obj);
}
return false;
return obj is CieXyy other && this.Equals(other);
}
/// <inheritdoc/>

36
src/ImageSharp/ColorSpaces/CieXyz.cs

@ -14,11 +14,6 @@ namespace SixLabors.ImageSharp.ColorSpaces
/// </summary>
internal readonly struct CieXyz : IColorVector, IEquatable<CieXyz>, IAlmostEquatable<CieXyz, float>
{
/// <summary>
/// Represents a <see cref="CieXyz"/> that has X, Y, and Z values set to zero.
/// </summary>
public static readonly CieXyz Empty = default(CieXyz);
/// <summary>
/// The backing vector for SIMD support.
/// </summary>
@ -40,7 +35,6 @@ namespace SixLabors.ImageSharp.ColorSpaces
/// Initializes a new instance of the <see cref="CieXyz"/> struct.
/// </summary>
/// <param name="vector">The vector representing the x, y, z components.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public CieXyz(Vector3 vector)
: this()
{
@ -78,18 +72,8 @@ namespace SixLabors.ImageSharp.ColorSpaces
get => this.backingVector.Z;
}
/// <summary>
/// Gets a value indicating whether this <see cref="CieXyz"/> is empty.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
public bool IsEmpty => this.Equals(Empty);
/// <inheritdoc />
public Vector3 Vector
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => this.backingVector;
}
public Vector3 Vector => this.backingVector;
/// <summary>
/// Compares two <see cref="CieXyz"/> objects for equality.
@ -128,6 +112,7 @@ namespace SixLabors.ImageSharp.ColorSpaces
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override int GetHashCode()
{
return this.backingVector.GetHashCode();
@ -136,24 +121,15 @@ namespace SixLabors.ImageSharp.ColorSpaces
/// <inheritdoc/>
public override string ToString()
{
if (this.IsEmpty)
{
return "CieXyz [ Empty ]";
}
return $"CieXyz [ X={this.X:#0.##}, Y={this.Y:#0.##}, Z={this.Z:#0.##} ]";
return this.Equals(default)
? "CieXyz [ Empty ]"
: $"CieXyz [ X={this.X:#0.##}, Y={this.Y:#0.##}, Z={this.Z:#0.##} ]";
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override bool Equals(object obj)
{
if (obj is CieXyz)
{
return this.Equals((CieXyz)obj);
}
return false;
return obj is CieXyz other && this.Equals(other);
}
/// <inheritdoc/>

29
src/ImageSharp/ColorSpaces/Cmyk.cs

@ -13,11 +13,6 @@ namespace SixLabors.ImageSharp.ColorSpaces
/// </summary>
internal readonly struct Cmyk : IEquatable<Cmyk>, IAlmostEquatable<Cmyk, float>
{
/// <summary>
/// Represents a <see cref="Cmyk"/> that has C, M, Y, and K values set to zero.
/// </summary>
public static readonly Cmyk Empty = default(Cmyk);
/// <summary>
/// The backing vector for SIMD support.
/// </summary>
@ -87,12 +82,6 @@ namespace SixLabors.ImageSharp.ColorSpaces
get => this.backingVector.W;
}
/// <summary>
/// Gets a value indicating whether this <see cref="Cmyk"/> is empty.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
public bool IsEmpty => this.Equals(Empty);
/// <summary>
/// Compares two <see cref="Cmyk"/> objects for equality.
/// </summary>
@ -130,6 +119,7 @@ namespace SixLabors.ImageSharp.ColorSpaces
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override int GetHashCode()
{
return this.backingVector.GetHashCode();
@ -138,24 +128,15 @@ namespace SixLabors.ImageSharp.ColorSpaces
/// <inheritdoc/>
public override string ToString()
{
if (this.IsEmpty)
{
return "Cmyk [Empty]";
}
return $"Cmyk [ C={this.C:#0.##}, M={this.M:#0.##}, Y={this.Y:#0.##}, K={this.K:#0.##}]";
return this.Equals(default)
? "Cmyk [Empty]"
: $"Cmyk [ C={this.C:#0.##}, M={this.M:#0.##}, Y={this.Y:#0.##}, K={this.K:#0.##}]";
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override bool Equals(object obj)
{
if (obj is Cmyk)
{
return this.Equals((Cmyk)obj);
}
return false;
return obj is Cmyk other && this.Equals(other);
}
/// <inheritdoc/>

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

@ -2,7 +2,6 @@
// Licensed under the Apache License, Version 2.0.
using System;
using SixLabors.ImageSharp.ColorSpaces;
using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.RgbColorSapce;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion
@ -19,11 +18,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <param name="color">The color to adapt</param>
/// <param name="sourceWhitePoint">The white point to adapt for</param>
/// <returns>The adapted color</returns>
public CieXyz Adapt(CieXyz color, CieXyz sourceWhitePoint)
public CieXyz Adapt(in CieXyz color, in CieXyz sourceWhitePoint)
{
Guard.NotNull(color, nameof(color));
Guard.NotNull(sourceWhitePoint, nameof(sourceWhitePoint));
if (!this.IsChromaticAdaptationPerformed)
{
throw new InvalidOperationException("Cannot perform chromatic adaptation, provide a chromatic adaptation method and white point.");
@ -37,10 +33,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to adapt</param>
/// <returns>The adapted color</returns>
public CieLab Adapt(CieLab color)
public CieLab Adapt(in CieLab color)
{
Guard.NotNull(color, nameof(color));
if (!this.IsChromaticAdaptationPerformed)
{
throw new InvalidOperationException("Cannot perform chromatic adaptation, provide a chromatic adaptation method and white point.");
@ -60,10 +54,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to adapt</param>
/// <returns>The adapted color</returns>
public CieLch Adapt(CieLch color)
public CieLch Adapt(in CieLch color)
{
Guard.NotNull(color, nameof(color));
if (!this.IsChromaticAdaptationPerformed)
{
throw new InvalidOperationException("Cannot perform chromatic adaptation, provide a chromatic adaptation method and white point.");
@ -83,10 +75,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to adapt</param>
/// <returns>The adapted color</returns>
public CieLchuv Adapt(CieLchuv color)
public CieLchuv Adapt(in CieLchuv color)
{
Guard.NotNull(color, nameof(color));
if (!this.IsChromaticAdaptationPerformed)
{
throw new InvalidOperationException("Cannot perform chromatic adaptation, provide a chromatic adaptation method and white point.");
@ -106,10 +96,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to adapt</param>
/// <returns>The adapted color</returns>
public CieLuv Adapt(CieLuv color)
public CieLuv Adapt(in CieLuv color)
{
Guard.NotNull(color, nameof(color));
if (!this.IsChromaticAdaptationPerformed)
{
throw new InvalidOperationException("Cannot perform chromatic adaptation, provide a chromatic adaptation method and white point.");
@ -129,10 +117,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to adapt</param>
/// <returns>The adapted color</returns>
public HunterLab Adapt(HunterLab color)
public HunterLab Adapt(in HunterLab color)
{
Guard.NotNull(color, nameof(color));
if (!this.IsChromaticAdaptationPerformed)
{
throw new InvalidOperationException("Cannot perform chromatic adaptation, provide a chromatic adaptation method and white point.");
@ -152,10 +138,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to adapt</param>
/// <returns>The adapted color</returns>
public LinearRgb Adapt(LinearRgb color)
public LinearRgb Adapt(in LinearRgb color)
{
Guard.NotNull(color, nameof(color));
if (!this.IsChromaticAdaptationPerformed)
{
throw new InvalidOperationException("Cannot perform chromatic adaptation, provide a chromatic adaptation method and white point.");
@ -183,10 +167,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to adapt</param>
/// <returns>The adapted color</returns>
public Rgb Adapt(Rgb color)
public Rgb Adapt(in Rgb color)
{
Guard.NotNull(color, nameof(color));
LinearRgb linearInput = this.ToLinearRgb(color);
LinearRgb linearOutput = this.Adapt(linearInput);
return this.ToRgb(linearOutput);

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

@ -1,7 +1,6 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.ColorSpaces;
using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.CieLabColorSapce;
using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.CieLchColorSapce;
@ -22,10 +21,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLab"/></returns>
public CieLab ToCieLab(CieLch color)
public CieLab ToCieLab(in CieLch color)
{
Guard.NotNull(color, nameof(color));
// Conversion (perserving white point)
CieLab unadapted = CieLchToCieLabConverter.Convert(color);
@ -43,10 +40,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLab"/></returns>
public CieLab ToCieLab(CieLchuv color)
public CieLab ToCieLab(in CieLchuv color)
{
Guard.NotNull(color, nameof(color));
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLab(xyzColor);
}
@ -56,10 +51,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLab"/></returns>
public CieLab ToCieLab(CieLuv color)
public CieLab ToCieLab(in CieLuv color)
{
Guard.NotNull(color, nameof(color));
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLab(xyzColor);
}
@ -69,10 +62,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLab"/></returns>
public CieLab ToCieLab(CieXyy color)
public CieLab ToCieLab(in CieXyy color)
{
Guard.NotNull(color, nameof(color));
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLab(xyzColor);
}
@ -82,17 +73,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLab"/></returns>
public CieLab ToCieLab(CieXyz color)
public CieLab ToCieLab(in CieXyz color)
{
Guard.NotNull(color, nameof(color));
// Adaptation
CieXyz adapted = !this.WhitePoint.Equals(this.TargetLabWhitePoint) && this.IsChromaticAdaptationPerformed
? this.ChromaticAdaptation.Transform(color, this.WhitePoint, this.TargetLabWhitePoint)
: color;
// Conversion
CieXyzToCieLabConverter converter = new CieXyzToCieLabConverter(this.TargetLabWhitePoint);
var converter = new CieXyzToCieLabConverter(this.TargetLabWhitePoint);
return converter.Convert(adapted);
}
@ -101,10 +90,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLab"/></returns>
public CieLab ToCieLab(Cmyk color)
public CieLab ToCieLab(in Cmyk color)
{
Guard.NotNull(color, nameof(color));
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLab(xyzColor);
}
@ -114,10 +101,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLab"/></returns>
public CieLab ToCieLab(Hsl color)
public CieLab ToCieLab(in Hsl color)
{
Guard.NotNull(color, nameof(color));
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLab(xyzColor);
}
@ -127,10 +112,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLab"/></returns>
public CieLab ToCieLab(Hsv color)
public CieLab ToCieLab(in Hsv color)
{
Guard.NotNull(color, nameof(color));
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLab(xyzColor);
}
@ -140,10 +123,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLab"/></returns>
public CieLab ToCieLab(HunterLab color)
public CieLab ToCieLab(in HunterLab color)
{
Guard.NotNull(color, nameof(color));
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLab(xyzColor);
}
@ -153,10 +134,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLab"/></returns>
public CieLab ToCieLab(Lms color)
public CieLab ToCieLab(in Lms color)
{
Guard.NotNull(color, nameof(color));
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLab(xyzColor);
}
@ -166,10 +145,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLab"/></returns>
public CieLab ToCieLab(LinearRgb color)
public CieLab ToCieLab(in LinearRgb color)
{
Guard.NotNull(color, nameof(color));
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLab(xyzColor);
}
@ -179,10 +156,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLab"/></returns>
public CieLab ToCieLab(Rgb color)
public CieLab ToCieLab(in Rgb color)
{
Guard.NotNull(color, nameof(color));
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLab(xyzColor);
}
@ -192,10 +167,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLab"/></returns>
public CieLab ToCieLab(YCbCr color)
public CieLab ToCieLab(in YCbCr color)
{
Guard.NotNull(color, nameof(color));
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLab(xyzColor);
}

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

@ -20,10 +20,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLch"/></returns>
public CieLch ToCieLch(CieLab color)
public CieLch ToCieLch(in CieLab color)
{
Guard.NotNull(color, nameof(color));
// Adaptation
CieLab adapted = this.IsChromaticAdaptationPerformed ? this.Adapt(color) : color;
@ -36,10 +34,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLch"/></returns>
public CieLch ToCieLch(CieLchuv color)
public CieLch ToCieLch(in CieLchuv color)
{
Guard.NotNull(color, nameof(color));
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLch(xyzColor);
}
@ -49,10 +45,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLch"/></returns>
public CieLch ToCieLch(CieLuv color)
public CieLch ToCieLch(in CieLuv color)
{
Guard.NotNull(color, nameof(color));
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLch(xyzColor);
}
@ -62,10 +56,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLch"/></returns>
public CieLch ToCieLch(CieXyy color)
public CieLch ToCieLch(in CieXyy color)
{
Guard.NotNull(color, nameof(color));
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLch(xyzColor);
}
@ -75,10 +67,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLch"/></returns>
public CieLch ToCieLch(CieXyz color)
public CieLch ToCieLch(in CieXyz color)
{
Guard.NotNull(color, nameof(color));
CieLab labColor = this.ToCieLab(color);
return this.ToCieLch(labColor);
}
@ -88,10 +78,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLch"/></returns>
public CieLch ToCieLch(Cmyk color)
public CieLch ToCieLch(in Cmyk color)
{
Guard.NotNull(color, nameof(color));
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLch(xyzColor);
}
@ -101,10 +89,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLch"/></returns>
public CieLch ToCieLch(Hsl color)
public CieLch ToCieLch(in Hsl color)
{
Guard.NotNull(color, nameof(color));
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLch(xyzColor);
}
@ -114,10 +100,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLch"/></returns>
public CieLch ToCieLch(Hsv color)
public CieLch ToCieLch(in Hsv color)
{
Guard.NotNull(color, nameof(color));
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLch(xyzColor);
}
@ -127,10 +111,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLch"/></returns>
public CieLch ToCieLch(HunterLab color)
public CieLch ToCieLch(in HunterLab color)
{
Guard.NotNull(color, nameof(color));
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLch(xyzColor);
}
@ -140,10 +122,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLch"/></returns>
public CieLch ToCieLch(LinearRgb color)
public CieLch ToCieLch(in LinearRgb color)
{
Guard.NotNull(color, nameof(color));
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLch(xyzColor);
}
@ -153,10 +133,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLch"/></returns>
public CieLch ToCieLch(Lms color)
public CieLch ToCieLch(in Lms color)
{
Guard.NotNull(color, nameof(color));
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLch(xyzColor);
}
@ -166,10 +144,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLch"/></returns>
public CieLch ToCieLch(Rgb color)
public CieLch ToCieLch(in Rgb color)
{
Guard.NotNull(color, nameof(color));
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLch(xyzColor);
}
@ -179,10 +155,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLch"/></returns>
public CieLch ToCieLch(YCbCr color)
public CieLch ToCieLch(in YCbCr color)
{
Guard.NotNull(color, nameof(color));
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLch(xyzColor);
}

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

@ -20,10 +20,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLchuv"/></returns>
public CieLchuv ToCieLchuv(CieLab color)
public CieLchuv ToCieLchuv(in CieLab color)
{
Guard.NotNull(color, nameof(color));
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLchuv(xyzColor);
}
@ -33,10 +31,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLchuv"/></returns>
public CieLchuv ToCieLchuv(CieLch color)
public CieLchuv ToCieLchuv(in CieLch color)
{
Guard.NotNull(color, nameof(color));
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLchuv(xyzColor);
}
@ -46,10 +42,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLchuv"/></returns>
public CieLchuv ToCieLchuv(CieLuv color)
public CieLchuv ToCieLchuv(in CieLuv color)
{
Guard.NotNull(color, nameof(color));
// Adaptation
CieLuv adapted = this.IsChromaticAdaptationPerformed ? this.Adapt(color) : color;
@ -62,10 +56,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLchuv"/></returns>
public CieLchuv ToCieLchuv(CieXyy color)
public CieLchuv ToCieLchuv(in CieXyy color)
{
Guard.NotNull(color, nameof(color));
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLchuv(xyzColor);
}
@ -75,10 +67,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLchuv"/></returns>
public CieLchuv ToCieLchuv(CieXyz color)
public CieLchuv ToCieLchuv(in CieXyz color)
{
Guard.NotNull(color, nameof(color));
CieLab labColor = this.ToCieLab(color);
return this.ToCieLchuv(labColor);
}
@ -88,10 +78,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLchuv"/></returns>
public CieLchuv ToCieLchuv(Cmyk color)
public CieLchuv ToCieLchuv(in Cmyk color)
{
Guard.NotNull(color, nameof(color));
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLchuv(xyzColor);
}
@ -101,10 +89,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLchuv"/></returns>
public CieLchuv ToCieLchuv(Hsl color)
public CieLchuv ToCieLchuv(in Hsl color)
{
Guard.NotNull(color, nameof(color));
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLchuv(xyzColor);
}
@ -114,10 +100,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLchuv"/></returns>
public CieLchuv ToCieLchuv(Hsv color)
public CieLchuv ToCieLchuv(in Hsv color)
{
Guard.NotNull(color, nameof(color));
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLchuv(xyzColor);
}
@ -127,10 +111,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLchuv"/></returns>
public CieLchuv ToCieLchuv(HunterLab color)
public CieLchuv ToCieLchuv(in HunterLab color)
{
Guard.NotNull(color, nameof(color));
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLchuv(xyzColor);
}
@ -140,10 +122,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLchuv"/></returns>
public CieLchuv ToCieLchuv(LinearRgb color)
public CieLchuv ToCieLchuv(in LinearRgb color)
{
Guard.NotNull(color, nameof(color));
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLchuv(xyzColor);
}
@ -153,10 +133,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLchuv"/></returns>
public CieLchuv ToCieLchuv(Lms color)
public CieLchuv ToCieLchuv(in Lms color)
{
Guard.NotNull(color, nameof(color));
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLchuv(xyzColor);
}
@ -168,8 +146,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="CieLchuv"/></returns>
public CieLchuv ToCieLchuv(Rgb color)
{
Guard.NotNull(color, nameof(color));
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLchuv(xyzColor);
}
@ -179,10 +155,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLchuv"/></returns>
public CieLchuv ToCieLchuv(YCbCr color)
public CieLchuv ToCieLchuv(in YCbCr color)
{
Guard.NotNull(color, nameof(color));
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLchuv(xyzColor);
}

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

@ -19,10 +19,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLuv"/></returns>
public CieLuv ToCieLuv(CieLab color)
public CieLuv ToCieLuv(in CieLab color)
{
Guard.NotNull(color, nameof(color));
var xyzColor = this.ToCieXyz(color);
return this.ToCieLuv(xyzColor);
}
@ -32,10 +30,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLuv"/></returns>
public CieLuv ToCieLuv(CieLch color)
public CieLuv ToCieLuv(in CieLch color)
{
Guard.NotNull(color, nameof(color));
var xyzColor = this.ToCieXyz(color);
return this.ToCieLuv(xyzColor);
}
@ -45,10 +41,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLab"/></returns>
public CieLuv ToCieLuv(CieLchuv color)
public CieLuv ToCieLuv(in CieLchuv color)
{
Guard.NotNull(color, nameof(color));
// Conversion (perserving white point)
CieLuv unadapted = CieLchuvToCieLuvConverter.Convert(color);
@ -66,10 +60,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLuv"/></returns>
public CieLuv ToCieLuv(CieXyy color)
public CieLuv ToCieLuv(in CieXyy color)
{
Guard.NotNull(color, nameof(color));
var xyzColor = this.ToCieXyz(color);
return this.ToCieLuv(xyzColor);
}
@ -79,10 +71,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLuv"/></returns>
public CieLuv ToCieLuv(CieXyz color)
public CieLuv ToCieLuv(in CieXyz color)
{
Guard.NotNull(color, nameof(color));
// Adaptation
CieXyz adapted = !this.WhitePoint.Equals(this.TargetLabWhitePoint) && this.IsChromaticAdaptationPerformed
? this.ChromaticAdaptation.Transform(color, this.WhitePoint, this.TargetLabWhitePoint)
@ -98,10 +88,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLuv"/></returns>
public CieLuv ToCieLuv(Cmyk color)
public CieLuv ToCieLuv(in Cmyk color)
{
Guard.NotNull(color, nameof(color));
var xyzColor = this.ToCieXyz(color);
return this.ToCieLuv(xyzColor);
}
@ -111,10 +99,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLuv"/></returns>
public CieLuv ToCieLuv(Hsl color)
public CieLuv ToCieLuv(in Hsl color)
{
Guard.NotNull(color, nameof(color));
var xyzColor = this.ToCieXyz(color);
return this.ToCieLuv(xyzColor);
}
@ -124,10 +110,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLuv"/></returns>
public CieLuv ToCieLuv(Hsv color)
public CieLuv ToCieLuv(in Hsv color)
{
Guard.NotNull(color, nameof(color));
var xyzColor = this.ToCieXyz(color);
return this.ToCieLuv(xyzColor);
}
@ -137,10 +121,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLuv"/></returns>
public CieLuv ToCieLuv(HunterLab color)
public CieLuv ToCieLuv(in HunterLab color)
{
Guard.NotNull(color, nameof(color));
var xyzColor = this.ToCieXyz(color);
return this.ToCieLuv(xyzColor);
}
@ -150,10 +132,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLuv"/></returns>
public CieLuv ToCieLuv(Lms color)
public CieLuv ToCieLuv(in Lms color)
{
Guard.NotNull(color, nameof(color));
var xyzColor = this.ToCieXyz(color);
return this.ToCieLuv(xyzColor);
}
@ -163,10 +143,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLuv"/></returns>
public CieLuv ToCieLuv(LinearRgb color)
public CieLuv ToCieLuv(in LinearRgb color)
{
Guard.NotNull(color, nameof(color));
var xyzColor = this.ToCieXyz(color);
return this.ToCieLuv(xyzColor);
}
@ -176,10 +154,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLuv"/></returns>
public CieLuv ToCieLuv(Rgb color)
public CieLuv ToCieLuv(in Rgb color)
{
Guard.NotNull(color, nameof(color));
var xyzColor = this.ToCieXyz(color);
return this.ToCieLuv(xyzColor);
}
@ -189,10 +165,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLuv"/></returns>
public CieLuv ToCieLuv(YCbCr color)
public CieLuv ToCieLuv(in YCbCr color)
{
Guard.NotNull(color, nameof(color));
var xyzColor = this.ToCieXyz(color);
return this.ToCieLuv(xyzColor);
}

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

@ -17,10 +17,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieXyy"/></returns>
public CieXyy ToCieXyy(CieLab color)
public CieXyy ToCieXyy(in CieLab color)
{
Guard.NotNull(color, nameof(color));
var xyzColor = this.ToCieXyz(color);
return this.ToCieXyy(xyzColor);
@ -31,10 +29,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieXyy"/></returns>
public CieXyy ToCieXyy(CieLch color)
public CieXyy ToCieXyy(in CieLch color)
{
Guard.NotNull(color, nameof(color));
var xyzColor = this.ToCieXyz(color);
return this.ToCieXyy(xyzColor);
@ -45,10 +41,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieXyy"/></returns>
public CieXyy ToCieXyy(CieLchuv color)
public CieXyy ToCieXyy(in CieLchuv color)
{
Guard.NotNull(color, nameof(color));
var xyzColor = this.ToCieXyz(color);
return this.ToCieXyy(xyzColor);
@ -59,10 +53,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieXyy"/></returns>
public CieXyy ToCieXyy(CieLuv color)
public CieXyy ToCieXyy(in CieLuv color)
{
Guard.NotNull(color, nameof(color));
var xyzColor = this.ToCieXyz(color);
return this.ToCieXyy(xyzColor);
@ -73,10 +65,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieXyy"/></returns>
public CieXyy ToCieXyy(CieXyz color)
public CieXyy ToCieXyy(in CieXyz color)
{
Guard.NotNull(color, nameof(color));
return CieXyzAndCieXyyConverter.Convert(color);
}
@ -85,10 +75,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieXyy"/></returns>
public CieXyy ToCieXyy(Cmyk color)
public CieXyy ToCieXyy(in Cmyk color)
{
Guard.NotNull(color, nameof(color));
var xyzColor = this.ToCieXyz(color);
return this.ToCieXyy(xyzColor);
@ -101,8 +89,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="CieXyy"/></returns>
public CieXyy ToCieXyy(Hsl color)
{
Guard.NotNull(color, nameof(color));
var xyzColor = this.ToCieXyz(color);
return this.ToCieXyy(xyzColor);
@ -113,10 +99,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieXyy"/></returns>
public CieXyy ToCieXyy(Hsv color)
public CieXyy ToCieXyy(in Hsv color)
{
Guard.NotNull(color, nameof(color));
var xyzColor = this.ToCieXyz(color);
return this.ToCieXyy(xyzColor);
@ -127,10 +111,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieXyy"/></returns>
public CieXyy ToCieXyy(HunterLab color)
public CieXyy ToCieXyy(in HunterLab color)
{
Guard.NotNull(color, nameof(color));
var xyzColor = this.ToCieXyz(color);
return this.ToCieXyy(xyzColor);
@ -141,10 +123,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieXyy"/></returns>
public CieXyy ToCieXyy(LinearRgb color)
public CieXyy ToCieXyy(in LinearRgb color)
{
Guard.NotNull(color, nameof(color));
var xyzColor = this.ToCieXyz(color);
return this.ToCieXyy(xyzColor);
@ -155,10 +135,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieXyy"/></returns>
public CieXyy ToCieXyy(Lms color)
public CieXyy ToCieXyy(in Lms color)
{
Guard.NotNull(color, nameof(color));
var xyzColor = this.ToCieXyz(color);
return this.ToCieXyy(xyzColor);
@ -169,10 +147,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieXyy"/></returns>
public CieXyy ToCieXyy(Rgb color)
public CieXyy ToCieXyy(in Rgb color)
{
Guard.NotNull(color, nameof(color));
var xyzColor = this.ToCieXyz(color);
return this.ToCieXyy(xyzColor);
@ -183,10 +159,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieXyy"/></returns>
public CieXyy ToCieXyy(YCbCr color)
public CieXyy ToCieXyy(in YCbCr color)
{
Guard.NotNull(color, nameof(color));
var xyzColor = this.ToCieXyz(color);
return this.ToCieXyy(xyzColor);

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

@ -1,7 +1,6 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.ColorSpaces;
using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.CieLabColorSapce;
using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.CieLuvColorSapce;
using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.HunterLabColorSapce;
@ -27,10 +26,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieXyz"/></returns>
public CieXyz ToCieXyz(CieLab color)
public CieXyz ToCieXyz(in CieLab color)
{
Guard.NotNull(color, nameof(color));
// Conversion
CieXyz unadapted = CieLabToCieXyzConverter.Convert(color);
@ -47,10 +44,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieXyz"/></returns>
public CieXyz ToCieXyz(CieLch color)
public CieXyz ToCieXyz(in CieLch color)
{
Guard.NotNull(color, nameof(color));
// Conversion to Lab
CieLab labColor = CieLchToCieLabConverter.Convert(color);
@ -63,10 +58,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieXyz"/></returns>
public CieXyz ToCieXyz(CieLchuv color)
public CieXyz ToCieXyz(in CieLchuv color)
{
Guard.NotNull(color, nameof(color));
// Conversion to Luv
CieLuv luvColor = CieLchuvToCieLuvConverter.Convert(color);
@ -79,10 +72,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieXyz"/></returns>
public CieXyz ToCieXyz(CieLuv color)
public CieXyz ToCieXyz(in CieLuv color)
{
Guard.NotNull(color, nameof(color));
// Conversion
CieXyz unadapted = CieLuvToCieXyzConverter.Convert(color);
@ -99,10 +90,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieXyz"/></returns>
public CieXyz ToCieXyz(CieXyy color)
public CieXyz ToCieXyz(in CieXyy color)
{
Guard.NotNull(color, nameof(color));
// Conversion
return CieXyzAndCieXyyConverter.Convert(color);
}
@ -112,10 +101,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieXyz"/></returns>
public CieXyz ToCieXyz(Cmyk color)
public CieXyz ToCieXyz(in Cmyk color)
{
Guard.NotNull(color, nameof(color));
// Conversion
var rgb = this.ToRgb(color);
@ -127,10 +114,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieXyz"/></returns>
public CieXyz ToCieXyz(Hsl color)
public CieXyz ToCieXyz(in Hsl color)
{
Guard.NotNull(color, nameof(color));
// Conversion
var rgb = this.ToRgb(color);
@ -142,10 +127,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieXyz"/></returns>
public CieXyz ToCieXyz(Hsv color)
public CieXyz ToCieXyz(in Hsv color)
{
Guard.NotNull(color, nameof(color));
// Conversion
var rgb = this.ToRgb(color);
@ -157,10 +140,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieXyz"/></returns>
public CieXyz ToCieXyz(HunterLab color)
public CieXyz ToCieXyz(in HunterLab color)
{
Guard.NotNull(color, nameof(color));
// Conversion
CieXyz unadapted = HunterLabToCieXyzConverter.Convert(color);
@ -177,10 +158,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieXyz"/></returns>
public CieXyz ToCieXyz(LinearRgb color)
public CieXyz ToCieXyz(in LinearRgb color)
{
Guard.NotNull(color, nameof(color));
// Conversion
LinearRgbToCieXyzConverter converter = this.GetLinearRgbToCieXyzConverter(color.WorkingSpace);
CieXyz unadapted = converter.Convert(color);
@ -196,10 +175,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieXyz"/></returns>
public CieXyz ToCieXyz(Lms color)
public CieXyz ToCieXyz(in Lms color)
{
Guard.NotNull(color, nameof(color));
// Conversion
return this.cachedCieXyzAndLmsConverter.Convert(color);
}
@ -209,10 +186,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieXyz"/></returns>
public CieXyz ToCieXyz(Rgb color)
public CieXyz ToCieXyz(in Rgb color)
{
Guard.NotNull(color, nameof(color));
// Conversion
LinearRgb linear = RgbToLinearRgbConverter.Convert(color);
return this.ToCieXyz(linear);
@ -223,10 +198,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieXyz"/></returns>
public CieXyz ToCieXyz(YCbCr color)
public CieXyz ToCieXyz(in YCbCr color)
{
Guard.NotNull(color, nameof(color));
// Conversion
var rgb = this.ToRgb(color);
@ -238,7 +211,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="workingSpace">The source working space</param>
/// <returns>The <see cref="LinearRgbToCieXyzConverter"/></returns>
private LinearRgbToCieXyzConverter GetLinearRgbToCieXyzConverter(IRgbWorkingSpace workingSpace)
private LinearRgbToCieXyzConverter GetLinearRgbToCieXyzConverter(RgbWorkingSpace workingSpace)
{
if (this.linearRgbToCieXyzConverter != null && this.linearRgbToCieXyzConverter.SourceWorkingSpace.Equals(workingSpace))
{

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

@ -1,7 +1,6 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.ColorSpaces;
using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.CmykColorSapce;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion
@ -18,10 +17,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Cmyk"/></returns>
public Cmyk ToCmyk(CieLab color)
public Cmyk ToCmyk(in CieLab color)
{
Guard.NotNull(color, nameof(color));
var xyzColor = this.ToCieXyz(color);
return this.ToCmyk(xyzColor);
@ -32,10 +29,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Cmyk"/></returns>
public Cmyk ToCmyk(CieLch color)
public Cmyk ToCmyk(in CieLch color)
{
Guard.NotNull(color, nameof(color));
var xyzColor = this.ToCieXyz(color);
return this.ToCmyk(xyzColor);
@ -46,10 +41,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Cmyk"/></returns>
public Cmyk ToCmyk(CieLchuv color)
public Cmyk ToCmyk(in CieLchuv color)
{
Guard.NotNull(color, nameof(color));
var xyzColor = this.ToCieXyz(color);
return this.ToCmyk(xyzColor);
@ -60,10 +53,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Cmyk"/></returns>
public Cmyk ToCmyk(CieLuv color)
public Cmyk ToCmyk(in CieLuv color)
{
Guard.NotNull(color, nameof(color));
var xyzColor = this.ToCieXyz(color);
return this.ToCmyk(xyzColor);
@ -74,10 +65,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Cmyk"/></returns>
public Cmyk ToCmyk(CieXyy color)
public Cmyk ToCmyk(in CieXyy color)
{
Guard.NotNull(color, nameof(color));
var xyzColor = this.ToCieXyz(color);
return this.ToCmyk(xyzColor);
@ -88,10 +77,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Cmyk"/></returns>
public Cmyk ToCmyk(CieXyz color)
public Cmyk ToCmyk(in CieXyz color)
{
Guard.NotNull(color, nameof(color));
var rgb = this.ToRgb(color);
return CmykAndRgbConverter.Convert(rgb);
@ -102,10 +89,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Cmyk"/></returns>
public Cmyk ToCmyk(Hsl color)
public Cmyk ToCmyk(in Hsl color)
{
Guard.NotNull(color, nameof(color));
var rgb = this.ToRgb(color);
return CmykAndRgbConverter.Convert(rgb);
@ -116,10 +101,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Cmyk"/></returns>
public Cmyk ToCmyk(Hsv color)
public Cmyk ToCmyk(in Hsv color)
{
Guard.NotNull(color, nameof(color));
var rgb = this.ToRgb(color);
return CmykAndRgbConverter.Convert(rgb);
@ -130,10 +113,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Cmyk"/></returns>
public Cmyk ToCmyk(HunterLab color)
public Cmyk ToCmyk(in HunterLab color)
{
Guard.NotNull(color, nameof(color));
var xyzColor = this.ToCieXyz(color);
return this.ToCmyk(xyzColor);
@ -144,10 +125,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Cmyk"/></returns>
public Cmyk ToCmyk(LinearRgb color)
public Cmyk ToCmyk(in LinearRgb color)
{
Guard.NotNull(color, nameof(color));
var rgb = this.ToRgb(color);
return CmykAndRgbConverter.Convert(rgb);
@ -158,10 +137,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Cmyk"/></returns>
public Cmyk ToCmyk(Lms color)
public Cmyk ToCmyk(in Lms color)
{
Guard.NotNull(color, nameof(color));
var xyzColor = this.ToCieXyz(color);
return this.ToCmyk(xyzColor);
@ -172,10 +149,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Cmyk"/></returns>
public Cmyk ToCmyk(Rgb color)
public Cmyk ToCmyk(in Rgb color)
{
Guard.NotNull(color, nameof(color));
return CmykAndRgbConverter.Convert(color);
}
@ -184,10 +159,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Cmyk"/></returns>
public Cmyk ToCmyk(YCbCr color)
public Cmyk ToCmyk(in YCbCr color)
{
Guard.NotNull(color, nameof(color));
var rgb = this.ToRgb(color);
return CmykAndRgbConverter.Convert(rgb);

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

@ -1,7 +1,6 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.ColorSpaces;
using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.HslColorSapce;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion
@ -18,10 +17,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Hsl"/></returns>
public Hsl ToHsl(CieLab color)
public Hsl ToHsl(in CieLab color)
{
Guard.NotNull(color, nameof(color));
var xyzColor = this.ToCieXyz(color);
return this.ToHsl(xyzColor);
@ -32,10 +29,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Hsl"/></returns>
public Hsl ToHsl(CieLch color)
public Hsl ToHsl(in CieLch color)
{
Guard.NotNull(color, nameof(color));
var xyzColor = this.ToCieXyz(color);
return this.ToHsl(xyzColor);
@ -46,10 +41,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Hsl"/></returns>
public Hsl ToHsl(CieLchuv color)
public Hsl ToHsl(in CieLchuv color)
{
Guard.NotNull(color, nameof(color));
var xyzColor = this.ToCieXyz(color);
return this.ToHsl(xyzColor);
@ -60,10 +53,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Hsl"/></returns>
public Hsl ToHsl(CieLuv color)
public Hsl ToHsl(in CieLuv color)
{
Guard.NotNull(color, nameof(color));
var xyzColor = this.ToCieXyz(color);
return this.ToHsl(xyzColor);
@ -74,10 +65,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Hsl"/></returns>
public Hsl ToHsl(CieXyy color)
public Hsl ToHsl(in CieXyy color)
{
Guard.NotNull(color, nameof(color));
var xyzColor = this.ToCieXyz(color);
return this.ToHsl(xyzColor);
@ -88,10 +77,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Hsl"/></returns>
public Hsl ToHsl(CieXyz color)
public Hsl ToHsl(in CieXyz color)
{
Guard.NotNull(color, nameof(color));
var rgb = this.ToRgb(color);
return HslAndRgbConverter.Convert(rgb);
@ -102,10 +89,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Hsl"/></returns>
public Hsl ToHsl(Cmyk color)
public Hsl ToHsl(in Cmyk color)
{
Guard.NotNull(color, nameof(color));
var rgb = this.ToRgb(color);
return HslAndRgbConverter.Convert(rgb);
@ -116,10 +101,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Hsl"/></returns>
public Hsl ToHsl(Hsv color)
public Hsl ToHsl(in Hsv color)
{
Guard.NotNull(color, nameof(color));
var rgb = this.ToRgb(color);
return HslAndRgbConverter.Convert(rgb);
@ -130,10 +113,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Hsl"/></returns>
public Hsl ToHsl(HunterLab color)
public Hsl ToHsl(in HunterLab color)
{
Guard.NotNull(color, nameof(color));
var xyzColor = this.ToCieXyz(color);
return this.ToHsl(xyzColor);
@ -144,10 +125,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Hsl"/></returns>
public Hsl ToHsl(LinearRgb color)
public Hsl ToHsl(in LinearRgb color)
{
Guard.NotNull(color, nameof(color));
var rgb = this.ToRgb(color);
return HslAndRgbConverter.Convert(rgb);
@ -160,8 +139,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="Hsl"/></returns>
public Hsl ToHsl(Lms color)
{
Guard.NotNull(color, nameof(color));
var xyzColor = this.ToCieXyz(color);
return this.ToHsl(xyzColor);
@ -172,10 +149,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Hsl"/></returns>
public Hsl ToHsl(Rgb color)
public Hsl ToHsl(in Rgb color)
{
Guard.NotNull(color, nameof(color));
return HslAndRgbConverter.Convert(color);
}
@ -184,10 +159,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Hsl"/></returns>
public Hsl ToHsl(YCbCr color)
public Hsl ToHsl(in YCbCr color)
{
Guard.NotNull(color, nameof(color));
var rgb = this.ToRgb(color);
return HslAndRgbConverter.Convert(rgb);

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

@ -1,7 +1,6 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.ColorSpaces;
using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.HsvColorSapce;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion
@ -18,10 +17,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Hsv"/></returns>
public Hsv ToHsv(CieLab color)
public Hsv ToHsv(in CieLab color)
{
Guard.NotNull(color, nameof(color));
var xyzColor = this.ToCieXyz(color);
return this.ToHsv(xyzColor);
@ -32,10 +29,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Hsv"/></returns>
public Hsv ToHsv(CieLch color)
public Hsv ToHsv(in CieLch color)
{
Guard.NotNull(color, nameof(color));
var xyzColor = this.ToCieXyz(color);
return this.ToHsv(xyzColor);
@ -46,10 +41,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Hsv"/></returns>
public Hsv ToHsv(CieLchuv color)
public Hsv ToHsv(in CieLchuv color)
{
Guard.NotNull(color, nameof(color));
var xyzColor = this.ToCieXyz(color);
return this.ToHsv(xyzColor);
@ -60,10 +53,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Hsv"/></returns>
public Hsv ToHsv(CieLuv color)
public Hsv ToHsv(in CieLuv color)
{
Guard.NotNull(color, nameof(color));
var xyzColor = this.ToCieXyz(color);
return this.ToHsv(xyzColor);
@ -74,10 +65,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Hsv"/></returns>
public Hsv ToHsv(CieXyy color)
public Hsv ToHsv(in CieXyy color)
{
Guard.NotNull(color, nameof(color));
var xyzColor = this.ToCieXyz(color);
return this.ToHsv(xyzColor);
@ -88,10 +77,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Hsv"/></returns>
public Hsv ToHsv(CieXyz color)
public Hsv ToHsv(in CieXyz color)
{
Guard.NotNull(color, nameof(color));
var rgb = this.ToRgb(color);
return HsvAndRgbConverter.Convert(rgb);
@ -102,10 +89,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Hsv"/></returns>
public Hsv ToHsv(Cmyk color)
public Hsv ToHsv(in Cmyk color)
{
Guard.NotNull(color, nameof(color));
var rgb = this.ToRgb(color);
return HsvAndRgbConverter.Convert(rgb);
@ -116,10 +101,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Hsv"/></returns>
public Hsv ToHsv(Hsl color)
public Hsv ToHsv(in Hsl color)
{
Guard.NotNull(color, nameof(color));
var rgb = this.ToRgb(color);
return HsvAndRgbConverter.Convert(rgb);
@ -130,10 +113,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Hsv"/></returns>
public Hsv ToHsv(HunterLab color)
public Hsv ToHsv(in HunterLab color)
{
Guard.NotNull(color, nameof(color));
var xyzColor = this.ToCieXyz(color);
return this.ToHsv(xyzColor);
@ -144,10 +125,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Hsv"/></returns>
public Hsv ToHsv(LinearRgb color)
public Hsv ToHsv(in LinearRgb color)
{
Guard.NotNull(color, nameof(color));
var rgb = this.ToRgb(color);
return HsvAndRgbConverter.Convert(rgb);
@ -160,8 +139,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="Hsv"/></returns>
public Hsv ToHsv(Lms color)
{
Guard.NotNull(color, nameof(color));
var xyzColor = this.ToCieXyz(color);
return this.ToHsv(xyzColor);
@ -172,10 +149,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Hsv"/></returns>
public Hsv ToHsv(Rgb color)
public Hsv ToHsv(in Rgb color)
{
Guard.NotNull(color, nameof(color));
return HsvAndRgbConverter.Convert(color);
}
@ -184,10 +159,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Hsv"/></returns>
public Hsv ToHsv(YCbCr color)
public Hsv ToHsv(in YCbCr color)
{
Guard.NotNull(color, nameof(color));
var rgb = this.ToRgb(color);
return HsvAndRgbConverter.Convert(rgb);

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

@ -15,10 +15,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="HunterLab"/></returns>
public HunterLab ToHunterLab(CieLab color)
public HunterLab ToHunterLab(in CieLab color)
{
Guard.NotNull(color, nameof(color));
var xyzColor = this.ToCieXyz(color);
return this.ToHunterLab(xyzColor);
}
@ -28,10 +26,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="HunterLab"/></returns>
public HunterLab ToHunterLab(CieLch color)
public HunterLab ToHunterLab(in CieLch color)
{
Guard.NotNull(color, nameof(color));
var xyzColor = this.ToCieXyz(color);
return this.ToHunterLab(xyzColor);
}
@ -41,10 +37,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="HunterLab"/></returns>
public HunterLab ToHunterLab(CieLchuv color)
public HunterLab ToHunterLab(in CieLchuv color)
{
Guard.NotNull(color, nameof(color));
var xyzColor = this.ToCieXyz(color);
return this.ToHunterLab(xyzColor);
}
@ -54,10 +48,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="HunterLab"/></returns>
public HunterLab ToHunterLab(CieLuv color)
public HunterLab ToHunterLab(in CieLuv color)
{
Guard.NotNull(color, nameof(color));
var xyzColor = this.ToCieXyz(color);
return this.ToHunterLab(xyzColor);
}
@ -67,10 +59,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="HunterLab"/></returns>
public HunterLab ToHunterLab(CieXyy color)
public HunterLab ToHunterLab(in CieXyy color)
{
Guard.NotNull(color, nameof(color));
var xyzColor = this.ToCieXyz(color);
return this.ToHunterLab(xyzColor);
}
@ -80,10 +70,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="HunterLab"/></returns>
public HunterLab ToHunterLab(CieXyz color)
public HunterLab ToHunterLab(in CieXyz color)
{
Guard.NotNull(color, nameof(color));
// Adaptation
CieXyz adapted = !this.WhitePoint.Equals(this.TargetHunterLabWhitePoint) && this.IsChromaticAdaptationPerformed
? this.ChromaticAdaptation.Transform(color, this.WhitePoint, this.TargetHunterLabWhitePoint)
@ -98,10 +86,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="HunterLab"/></returns>
public HunterLab ToHunterLab(Cmyk color)
public HunterLab ToHunterLab(in Cmyk color)
{
Guard.NotNull(color, nameof(color));
var xyzColor = this.ToCieXyz(color);
return this.ToHunterLab(xyzColor);
}
@ -111,10 +97,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="HunterLab"/></returns>
public HunterLab ToHunterLab(Hsl color)
public HunterLab ToHunterLab(in Hsl color)
{
Guard.NotNull(color, nameof(color));
var xyzColor = this.ToCieXyz(color);
return this.ToHunterLab(xyzColor);
}
@ -124,10 +108,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="HunterLab"/></returns>
public HunterLab ToHunterLab(Hsv color)
public HunterLab ToHunterLab(in Hsv color)
{
Guard.NotNull(color, nameof(color));
var xyzColor = this.ToCieXyz(color);
return this.ToHunterLab(xyzColor);
}
@ -137,10 +119,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="HunterLab"/></returns>
public HunterLab ToHunterLab(LinearRgb color)
public HunterLab ToHunterLab(in LinearRgb color)
{
Guard.NotNull(color, nameof(color));
var xyzColor = this.ToCieXyz(color);
return this.ToHunterLab(xyzColor);
}
@ -150,10 +130,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="HunterLab"/></returns>
public HunterLab ToHunterLab(Lms color)
public HunterLab ToHunterLab(in Lms color)
{
Guard.NotNull(color, nameof(color));
var xyzColor = this.ToCieXyz(color);
return this.ToHunterLab(xyzColor);
}
@ -163,10 +141,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="HunterLab"/></returns>
public HunterLab ToHunterLab(Rgb color)
public HunterLab ToHunterLab(in Rgb color)
{
Guard.NotNull(color, nameof(color));
var xyzColor = this.ToCieXyz(color);
return this.ToHunterLab(xyzColor);
}
@ -176,10 +152,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="HunterLab"/></returns>
public HunterLab ToHunterLab(YCbCr color)
public HunterLab ToHunterLab(in YCbCr color)
{
Guard.NotNull(color, nameof(color));
var xyzColor = this.ToCieXyz(color);
return this.ToHunterLab(xyzColor);
}

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

@ -19,10 +19,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="LinearRgb"/></returns>
public LinearRgb ToLinearRgb(CieLab color)
public LinearRgb ToLinearRgb(in CieLab color)
{
Guard.NotNull(color, nameof(color));
var xyzColor = this.ToCieXyz(color);
return this.ToLinearRgb(xyzColor);
}
@ -32,10 +30,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="LinearRgb"/></returns>
public LinearRgb ToLinearRgb(CieLch color)
public LinearRgb ToLinearRgb(in CieLch color)
{
Guard.NotNull(color, nameof(color));
var xyzColor = this.ToCieXyz(color);
return this.ToLinearRgb(xyzColor);
}
@ -45,10 +41,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="LinearRgb"/></returns>
public LinearRgb ToLinearRgb(CieLchuv color)
public LinearRgb ToLinearRgb(in CieLchuv color)
{
Guard.NotNull(color, nameof(color));
var xyzColor = this.ToCieXyz(color);
return this.ToLinearRgb(xyzColor);
}
@ -58,10 +52,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="LinearRgb"/></returns>
public LinearRgb ToLinearRgb(CieLuv color)
public LinearRgb ToLinearRgb(in CieLuv color)
{
Guard.NotNull(color, nameof(color));
var xyzColor = this.ToCieXyz(color);
return this.ToLinearRgb(xyzColor);
}
@ -71,10 +63,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="LinearRgb"/></returns>
public LinearRgb ToLinearRgb(CieXyy color)
public LinearRgb ToLinearRgb(in CieXyy color)
{
Guard.NotNull(color, nameof(color));
var xyzColor = this.ToCieXyz(color);
return this.ToLinearRgb(xyzColor);
}
@ -84,10 +74,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="LinearRgb"/></returns>
public LinearRgb ToLinearRgb(CieXyz color)
public LinearRgb ToLinearRgb(in CieXyz color)
{
Guard.NotNull(color, nameof(color));
// Adaptation
CieXyz adapted = this.TargetRgbWorkingSpace.WhitePoint.Equals(this.WhitePoint) || !this.IsChromaticAdaptationPerformed
? color
@ -103,10 +91,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="LinearRgb"/></returns>
public LinearRgb ToLinearRgb(Cmyk color)
public LinearRgb ToLinearRgb(in Cmyk color)
{
Guard.NotNull(color, nameof(color));
var rgb = this.ToRgb(color);
return this.ToLinearRgb(rgb);
}
@ -116,10 +102,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="LinearRgb"/></returns>
public LinearRgb ToLinearRgb(Hsl color)
public LinearRgb ToLinearRgb(in Hsl color)
{
Guard.NotNull(color, nameof(color));
var rgb = this.ToRgb(color);
return this.ToLinearRgb(rgb);
}
@ -129,10 +113,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="LinearRgb"/></returns>
public LinearRgb ToLinearRgb(Hsv color)
public LinearRgb ToLinearRgb(in Hsv color)
{
Guard.NotNull(color, nameof(color));
var rgb = this.ToRgb(color);
return this.ToLinearRgb(rgb);
}
@ -142,10 +124,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="LinearRgb"/></returns>
public LinearRgb ToLinearRgb(HunterLab color)
public LinearRgb ToLinearRgb(in HunterLab color)
{
Guard.NotNull(color, nameof(color));
var xyzColor = this.ToCieXyz(color);
return this.ToLinearRgb(xyzColor);
}
@ -155,10 +135,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="LinearRgb"/></returns>
public LinearRgb ToLinearRgb(Lms color)
public LinearRgb ToLinearRgb(in Lms color)
{
Guard.NotNull(color, nameof(color));
var xyzColor = this.ToCieXyz(color);
return this.ToLinearRgb(xyzColor);
}
@ -168,10 +146,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="LinearRgb"/></returns>
public LinearRgb ToLinearRgb(Rgb color)
public LinearRgb ToLinearRgb(in Rgb color)
{
Guard.NotNull(color, nameof(color));
// Conversion
return RgbToLinearRgbConverter.Convert(color);
}
@ -181,10 +157,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="LinearRgb"/></returns>
public LinearRgb ToLinearRgb(YCbCr color)
public LinearRgb ToLinearRgb(in YCbCr color)
{
Guard.NotNull(color, nameof(color));
var rgb = this.ToRgb(color);
return this.ToLinearRgb(rgb);
}
@ -194,7 +168,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="workingSpace">The target working space</param>
/// <returns>The <see cref="CieXyzToLinearRgbConverter"/></returns>
private CieXyzToLinearRgbConverter GetCieXyxToLinearRgbConverter(IRgbWorkingSpace workingSpace)
private CieXyzToLinearRgbConverter GetCieXyxToLinearRgbConverter(RgbWorkingSpace workingSpace)
{
if (this.cieXyzToLinearRgbConverter != null && this.cieXyzToLinearRgbConverter.TargetWorkingSpace.Equals(workingSpace))
{

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

@ -15,10 +15,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Lms"/></returns>
public Lms ToLms(CieLab color)
public Lms ToLms(in CieLab color)
{
Guard.NotNull(color, nameof(color));
var xyzColor = this.ToCieXyz(color);
return this.ToLms(xyzColor);
}
@ -28,10 +26,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Lms"/></returns>
public Lms ToLms(CieLch color)
public Lms ToLms(in CieLch color)
{
Guard.NotNull(color, nameof(color));
var xyzColor = this.ToCieXyz(color);
return this.ToLms(xyzColor);
}
@ -41,10 +37,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Lms"/></returns>
public Lms ToLms(CieLchuv color)
public Lms ToLms(in CieLchuv color)
{
Guard.NotNull(color, nameof(color));
var xyzColor = this.ToCieXyz(color);
return this.ToLms(xyzColor);
}
@ -54,10 +48,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Lms"/></returns>
public Lms ToLms(CieLuv color)
public Lms ToLms(in CieLuv color)
{
Guard.NotNull(color, nameof(color));
var xyzColor = this.ToCieXyz(color);
return this.ToLms(xyzColor);
}
@ -67,10 +59,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Lms"/></returns>
public Lms ToLms(CieXyy color)
public Lms ToLms(in CieXyy color)
{
Guard.NotNull(color, nameof(color));
var xyzColor = this.ToCieXyz(color);
return this.ToLms(xyzColor);
}
@ -80,11 +70,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Lms"/></returns>
public Lms ToLms(CieXyz color)
public Lms ToLms(in CieXyz color)
{
Guard.NotNull(color, nameof(color));
// Conversion
return this.cachedCieXyzAndLmsConverter.Convert(color);
}
@ -93,10 +80,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Lms"/></returns>
public Lms ToLms(Cmyk color)
public Lms ToLms(in Cmyk color)
{
Guard.NotNull(color, nameof(color));
var xyzColor = this.ToCieXyz(color);
return this.ToLms(xyzColor);
}
@ -106,10 +91,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Lms"/></returns>
public Lms ToLms(Hsl color)
public Lms ToLms(in Hsl color)
{
Guard.NotNull(color, nameof(color));
var xyzColor = this.ToCieXyz(color);
return this.ToLms(xyzColor);
}
@ -119,10 +102,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Lms"/></returns>
public Lms ToLms(Hsv color)
public Lms ToLms(in Hsv color)
{
Guard.NotNull(color, nameof(color));
var xyzColor = this.ToCieXyz(color);
return this.ToLms(xyzColor);
}
@ -132,10 +113,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Lms"/></returns>
public Lms ToLms(HunterLab color)
public Lms ToLms(in HunterLab color)
{
Guard.NotNull(color, nameof(color));
var xyzColor = this.ToCieXyz(color);
return this.ToLms(xyzColor);
}
@ -145,10 +124,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Lms"/></returns>
public Lms ToLms(LinearRgb color)
public Lms ToLms(in LinearRgb color)
{
Guard.NotNull(color, nameof(color));
var xyzColor = this.ToCieXyz(color);
return this.ToLms(xyzColor);
}
@ -158,10 +135,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Lms"/></returns>
public Lms ToLms(Rgb color)
public Lms ToLms(in Rgb color)
{
Guard.NotNull(color, nameof(color));
var xyzColor = this.ToCieXyz(color);
return this.ToLms(xyzColor);
}
@ -171,10 +146,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Lms"/></returns>
public Lms ToLms(YCbCr color)
public Lms ToLms(in YCbCr color)
{
Guard.NotNull(color, nameof(color));
var xyzColor = this.ToCieXyz(color);
return this.ToLms(xyzColor);
}

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

@ -17,10 +17,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Rgb"/></returns>
public Rgb ToRgb(CieLab color)
public Rgb ToRgb(in CieLab color)
{
Guard.NotNull(color, nameof(color));
var xyzColor = this.ToCieXyz(color);
return this.ToRgb(xyzColor);
}
@ -30,10 +28,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Rgb"/></returns>
public Rgb ToRgb(CieLch color)
public Rgb ToRgb(in CieLch color)
{
Guard.NotNull(color, nameof(color));
var xyzColor = this.ToCieXyz(color);
return this.ToRgb(xyzColor);
}
@ -43,10 +39,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Rgb"/></returns>
public Rgb ToRgb(CieLchuv color)
public Rgb ToRgb(in CieLchuv color)
{
Guard.NotNull(color, nameof(color));
var xyzColor = this.ToCieXyz(color);
return this.ToRgb(xyzColor);
}
@ -56,10 +50,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Rgb"/></returns>
public Rgb ToRgb(CieLuv color)
public Rgb ToRgb(in CieLuv color)
{
Guard.NotNull(color, nameof(color));
var xyzColor = this.ToCieXyz(color);
return this.ToRgb(xyzColor);
}
@ -69,10 +61,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Rgb"/></returns>
public Rgb ToRgb(CieXyy color)
public Rgb ToRgb(in CieXyy color)
{
Guard.NotNull(color, nameof(color));
var xyzColor = this.ToCieXyz(color);
return this.ToRgb(xyzColor);
}
@ -82,10 +72,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Rgb"/></returns>
public Rgb ToRgb(CieXyz color)
public Rgb ToRgb(in CieXyz color)
{
Guard.NotNull(color, nameof(color));
// Conversion
var linear = this.ToLinearRgb(color);
@ -98,10 +86,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Rgb"/></returns>
public Rgb ToRgb(Cmyk color)
public Rgb ToRgb(in Cmyk color)
{
Guard.NotNull(color, nameof(color));
// Conversion
return CmykAndRgbConverter.Convert(color);
}
@ -111,10 +97,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Rgb"/></returns>
public Rgb ToRgb(Hsv color)
public Rgb ToRgb(in Hsv color)
{
Guard.NotNull(color, nameof(color));
// Conversion
return HsvAndRgbConverter.Convert(color);
}
@ -124,10 +108,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Rgb"/></returns>
public Rgb ToRgb(Hsl color)
public Rgb ToRgb(in Hsl color)
{
Guard.NotNull(color, nameof(color));
// Conversion
return HslAndRgbConverter.Convert(color);
}
@ -137,10 +119,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Rgb"/></returns>
public Rgb ToRgb(HunterLab color)
public Rgb ToRgb(in HunterLab color)
{
Guard.NotNull(color, nameof(color));
var xyzColor = this.ToCieXyz(color);
return this.ToRgb(xyzColor);
}
@ -150,10 +130,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Rgb"/></returns>
public Rgb ToRgb(LinearRgb color)
public Rgb ToRgb(in LinearRgb color)
{
Guard.NotNull(color, nameof(color));
// Conversion
return LinearRgbToRgbConverter.Convert(color);
}
@ -163,10 +141,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Rgb"/></returns>
public Rgb ToRgb(Lms color)
public Rgb ToRgb(in Lms color)
{
Guard.NotNull(color, nameof(color));
var xyzColor = this.ToCieXyz(color);
return this.ToRgb(xyzColor);
}
@ -176,10 +152,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Rgb"/></returns>
public Rgb ToRgb(YCbCr color)
public Rgb ToRgb(in YCbCr color)
{
Guard.NotNull(color, nameof(color));
// Conversion
Rgb rgb = YCbCrAndRgbConverter.Convert(color);

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

@ -1,7 +1,6 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.ColorSpaces;
using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.YCbCrColorSapce;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion
@ -18,10 +17,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="YCbCr"/></returns>
public YCbCr ToYCbCr(CieLab color)
public YCbCr ToYCbCr(in CieLab color)
{
Guard.NotNull(color, nameof(color));
var xyzColor = this.ToCieXyz(color);
return this.ToYCbCr(xyzColor);
@ -32,10 +29,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="YCbCr"/></returns>
public YCbCr ToYCbCr(CieLch color)
public YCbCr ToYCbCr(in CieLch color)
{
Guard.NotNull(color, nameof(color));
var xyzColor = this.ToCieXyz(color);
return this.ToYCbCr(xyzColor);
@ -46,10 +41,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="YCbCr"/></returns>
public YCbCr ToYCbCr(CieLchuv color)
public YCbCr ToYCbCr(in CieLchuv color)
{
Guard.NotNull(color, nameof(color));
var xyzColor = this.ToCieXyz(color);
return this.ToYCbCr(xyzColor);
@ -60,10 +53,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="YCbCr"/></returns>
public YCbCr ToYCbCr(CieLuv color)
public YCbCr ToYCbCr(in CieLuv color)
{
Guard.NotNull(color, nameof(color));
var xyzColor = this.ToCieXyz(color);
return this.ToYCbCr(xyzColor);
@ -74,10 +65,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="YCbCr"/></returns>
public YCbCr ToYCbCr(CieXyy color)
public YCbCr ToYCbCr(in CieXyy color)
{
Guard.NotNull(color, nameof(color));
var xyzColor = this.ToCieXyz(color);
return this.ToYCbCr(xyzColor);
@ -88,10 +77,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="YCbCr"/></returns>
public YCbCr ToYCbCr(CieXyz color)
public YCbCr ToYCbCr(in CieXyz color)
{
Guard.NotNull(color, nameof(color));
var rgb = this.ToRgb(color);
return YCbCrAndRgbConverter.Convert(rgb);
@ -102,10 +89,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="YCbCr"/></returns>
public YCbCr ToYCbCr(Cmyk color)
public YCbCr ToYCbCr(in Cmyk color)
{
Guard.NotNull(color, nameof(color));
var rgb = this.ToRgb(color);
return YCbCrAndRgbConverter.Convert(rgb);
@ -116,10 +101,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="YCbCr"/></returns>
public YCbCr ToYCbCr(Hsl color)
public YCbCr ToYCbCr(in Hsl color)
{
Guard.NotNull(color, nameof(color));
var rgb = this.ToRgb(color);
return YCbCrAndRgbConverter.Convert(rgb);
@ -130,10 +113,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="YCbCr"/></returns>
public YCbCr ToYCbCr(Hsv color)
public YCbCr ToYCbCr(in Hsv color)
{
Guard.NotNull(color, nameof(color));
var rgb = this.ToRgb(color);
return YCbCrAndRgbConverter.Convert(rgb);
@ -144,10 +125,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="YCbCr"/></returns>
public YCbCr ToYCbCr(HunterLab color)
public YCbCr ToYCbCr(in HunterLab color)
{
Guard.NotNull(color, nameof(color));
var xyzColor = this.ToCieXyz(color);
return this.ToYCbCr(xyzColor);
@ -158,10 +137,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="YCbCr"/></returns>
public YCbCr ToYCbCr(LinearRgb color)
public YCbCr ToYCbCr(in LinearRgb color)
{
Guard.NotNull(color, nameof(color));
var rgb = this.ToRgb(color);
return YCbCrAndRgbConverter.Convert(rgb);
@ -172,10 +149,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="YCbCr"/></returns>
public YCbCr ToYCbCr(Lms color)
public YCbCr ToYCbCr(in Lms color)
{
Guard.NotNull(color, nameof(color));
var xyzColor = this.ToCieXyz(color);
return this.ToYCbCr(xyzColor);
@ -186,10 +161,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="YCbCr"/></returns>
public YCbCr ToYCbCr(Rgb color)
public YCbCr ToYCbCr(in Rgb color)
{
Guard.NotNull(color, nameof(color));
return YCbCrAndRgbConverter.Convert(color);
}
}

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

@ -2,8 +2,8 @@
// Licensed under the Apache License, Version 2.0.
using System.Numerics;
using SixLabors.ImageSharp.ColorSpaces;
using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.LmsColorSapce;
using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.RgbColorSapce;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion
{
@ -64,7 +64,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// Gets or sets the target working space used *when creating* RGB colors. (RGB colors on the input already contain the working space information)
/// Defaults to: <see cref="Rgb.DefaultWorkingSpace"/>.
/// </summary>
public IRgbWorkingSpace TargetRgbWorkingSpace { get; set; }
public RgbWorkingSpace TargetRgbWorkingSpace { get; set; }
/// <summary>
/// Gets or sets the chromatic adaptation method used. When null, no adaptation will be performed.

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

@ -1,8 +1,6 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.ColorSpaces;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion
{
/// <summary>
@ -20,6 +18,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <param name="sourceWhitePoint">The source white point.</param>
/// <param name="targetWhitePoint">The target white point.</param>
/// <returns>The <see cref="CieXyz"/></returns>
CieXyz Transform(CieXyz sourceColor, CieXyz sourceWhitePoint, CieXyz targetWhitePoint);
CieXyz Transform(in CieXyz sourceColor, in CieXyz sourceWhitePoint, in CieXyz targetWhitePoint);
}
}

6
src/ImageSharp/ColorSpaces/Conversion/IColorConversion.cs

@ -8,13 +8,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary>
/// <typeparam name="T">The input color type.</typeparam>
/// <typeparam name="TResult">The result color type.</typeparam>
internal interface IColorConversion<in T, out TResult>
internal interface IColorConversion<T, TResult>
where T : struct
where TResult : struct
{
/// <summary>
/// Performs the conversion from the input to an instance of the output type.
/// </summary>
/// <param name="input">The input color instance.</param>
/// <returns>The converted result</returns>
TResult Convert(T input);
TResult Convert(in T input);
}
}

4
src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLab/CieLabToCieXyzConverter.cs

@ -13,10 +13,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.CieLabColor
{
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public CieXyz Convert(CieLab input)
public CieXyz Convert(in CieLab input)
{
DebugGuard.NotNull(input, nameof(input));
// Conversion algorithm described here: http://www.brucelindbloom.com/index.html?Eqn_Lab_to_XYZ.html
float l = input.L, a = input.A, b = input.B;
float fy = (l + 16) / 116F;

11
src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLab/CieXyzToCieLabConverter.cs

@ -3,7 +3,6 @@
using System;
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.ColorSpaces;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.CieLabColorSapce
{
@ -34,18 +33,12 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.CieLabColor
/// <summary>
/// Gets the target reference whitepoint. When not set, <see cref="CieLab.DefaultWhitePoint"/> is used.
/// </summary>
public CieXyz LabWhitePoint
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get;
}
public CieXyz LabWhitePoint { get; }
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public CieLab Convert(CieXyz input)
public CieLab Convert(in CieXyz input)
{
DebugGuard.NotNull(input, nameof(input));
// Conversion algorithm described here: http://www.brucelindbloom.com/index.html?Eqn_XYZ_to_Lab.html
float wx = this.LabWhitePoint.X, wy = this.LabWhitePoint.Y, wz = this.LabWhitePoint.Z;

5
src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLch/CIeLchToCieLabConverter.cs

@ -3,7 +3,6 @@
using System;
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.ColorSpaces;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.CieLchColorSapce
{
@ -14,10 +13,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.CieLchColor
{
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public CieLab Convert(CieLch input)
public CieLab Convert(in CieLch input)
{
DebugGuard.NotNull(input, nameof(input));
// Conversion algorithm described here:
// https://en.wikipedia.org/wiki/Lab_color_space#Cylindrical_representation:_CIELCh_or_CIEHLC
float l = input.L, c = input.C, hDegrees = input.H;

5
src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLch/CieLabToCieLchConverter.cs

@ -3,7 +3,6 @@
using System;
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.ColorSpaces;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.CieLchColorSapce
{
@ -14,10 +13,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.CieLchColor
{
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public CieLch Convert(CieLab input)
public CieLch Convert(in CieLab input)
{
DebugGuard.NotNull(input, nameof(input));
// Conversion algorithm described here:
// https://en.wikipedia.org/wiki/Lab_color_space#Cylindrical_representation:_CIELCh_or_CIEHLC
float l = input.L, a = input.A, b = input.B;

5
src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLchuv/CieLchuvToCieLuvConverter.cs

@ -3,7 +3,6 @@
using System;
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.ColorSpaces;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.CieLchuvColorSapce
{
@ -14,10 +13,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.CieLchuvCol
{
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public CieLuv Convert(CieLchuv input)
public CieLuv Convert(in CieLchuv input)
{
DebugGuard.NotNull(input, nameof(input));
// Conversion algorithm described here:
// https://en.wikipedia.org/wiki/CIELUV#Cylindrical_representation_.28CIELCH.29
float l = input.L, c = input.C, hDegrees = input.H;

5
src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLchuv/CieLuvToCieLchuvConverter.cs

@ -3,7 +3,6 @@
using System;
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.ColorSpaces;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.CieLchuvColorSapce
{
@ -14,10 +13,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.CieLchuvCol
{
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public CieLchuv Convert(CieLuv input)
public CieLchuv Convert(in CieLuv input)
{
DebugGuard.NotNull(input, nameof(input));
// Conversion algorithm described here:
// https://en.wikipedia.org/wiki/CIELUV#Cylindrical_representation_.28CIELCH.29
float l = input.L, a = input.U, b = input.V;

9
src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLuv/CieLuvToCieXyzConverter.cs

@ -3,7 +3,6 @@
using System;
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.ColorSpaces;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.CieLuvColorSapce
{
@ -14,10 +13,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.CieLuvColor
{
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public CieXyz Convert(CieLuv input)
public CieXyz Convert(in CieLuv input)
{
DebugGuard.NotNull(input, nameof(input));
// Conversion algorithm described here: http://www.brucelindbloom.com/index.html?Eqn_Luv_to_XYZ.html
float l = input.L, u = input.U, v = input.V;
@ -60,7 +57,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.CieLuvColor
/// <param name="input">The whitepoint</param>
/// <returns>The <see cref="float"/></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static float ComputeU0(CieXyz input)
private static float ComputeU0(in CieXyz input)
{
return (4 * input.X) / (input.X + (15 * input.Y) + (3 * input.Z));
}
@ -71,7 +68,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.CieLuvColor
/// <param name="input">The whitepoint</param>
/// <returns>The <see cref="float"/></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static float ComputeV0(CieXyz input)
private static float ComputeV0(in CieXyz input)
{
return (9 * input.Y) / (input.X + (15 * input.Y) + (3 * input.Z));
}

14
src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLuv/CieXyzToCieLuvConverter.cs

@ -34,18 +34,12 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.CieLuvColor
/// <summary>
/// Gets the target reference whitepoint. When not set, <see cref="CieLuv.DefaultWhitePoint"/> is used.
/// </summary>
public CieXyz LuvWhitePoint
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get;
}
public CieXyz LuvWhitePoint { get; }
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public CieLuv Convert(CieXyz input)
public CieLuv Convert(in CieXyz input)
{
DebugGuard.NotNull(input, nameof(input));
// Conversion algorithm described here: http://www.brucelindbloom.com/index.html?Eqn_XYZ_to_Luv.html
float yr = input.Y / this.LuvWhitePoint.Y;
float up = ComputeUp(input);
@ -82,7 +76,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.CieLuvColor
/// <param name="input">The whitepoint</param>
/// <returns>The <see cref="float"/></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static float ComputeUp(CieXyz input)
private static float ComputeUp(in CieXyz input)
{
return (4 * input.X) / (input.X + (15 * input.Y) + (3 * input.Z));
}
@ -92,7 +86,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.CieLuvColor
/// </summary>
/// <param name="input">The whitepoint</param>
/// <returns>The <see cref="float"/></returns>
private static float ComputeVp(CieXyz input)
private static float ComputeVp(in CieXyz input)
{
return (9 * input.Y) / (input.X + (15 * input.Y) + (3 * input.Z));
}

9
src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyy/CieXyzAndCieXyyConverter.cs

@ -3,7 +3,6 @@
using System;
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.ColorSpaces;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.CieXyyColorSapce
{
@ -15,10 +14,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.CieXyyColor
{
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public CieXyy Convert(CieXyz input)
public CieXyy Convert(in CieXyz input)
{
DebugGuard.NotNull(input, nameof(input));
float x = input.X / (input.X + input.Y + input.Z);
float y = input.Y / (input.X + input.Y + input.Z);
@ -32,10 +29,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.CieXyyColor
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public CieXyz Convert(CieXyy input)
public CieXyz Convert(in CieXyy input)
{
DebugGuard.NotNull(input, nameof(input));
if (MathF.Abs(input.Y) < Constants.Epsilon)
{
return new CieXyz(0, 0, input.Yl);

5
src/ImageSharp/ColorSpaces/Conversion/Implementation/Cmyk/CmykAndRgbConverter.cs

@ -3,7 +3,6 @@
using System;
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.ColorSpaces;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.CmykColorSapce
{
@ -14,7 +13,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.CmykColorSa
{
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Rgb Convert(Cmyk input)
public Rgb Convert(in Cmyk input)
{
float r = (1F - input.C) * (1F - input.K);
float g = (1F - input.M) * (1F - input.K);
@ -25,7 +24,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.CmykColorSa
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Cmyk Convert(Rgb input)
public Cmyk Convert(in Rgb input)
{
// To CMYK
float c = 1F - input.R;

9
src/ImageSharp/ColorSpaces/Conversion/Implementation/Hsl/HslAndRgbConverter.cs

@ -3,7 +3,6 @@
using System;
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.ColorSpaces;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.HslColorSapce
{
@ -15,10 +14,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.HslColorSap
{
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Rgb Convert(Hsl input)
public Rgb Convert(in Hsl input)
{
DebugGuard.NotNull(input, nameof(input));
float rangedH = input.H / 360F;
float r = 0;
float g = 0;
@ -48,10 +45,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.HslColorSap
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Hsl Convert(Rgb input)
public Hsl Convert(in Rgb input)
{
DebugGuard.NotNull(input, nameof(input));
float r = input.R;
float g = input.G;
float b = input.B;

9
src/ImageSharp/ColorSpaces/Conversion/Implementation/Hsv/HsvAndRgbConverter.cs

@ -3,7 +3,6 @@
using System;
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.ColorSpaces;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.HsvColorSapce
{
@ -15,10 +14,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.HsvColorSap
{
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Rgb Convert(Hsv input)
public Rgb Convert(in Hsv input)
{
DebugGuard.NotNull(input, nameof(input));
float s = input.S;
float v = input.V;
@ -80,10 +77,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.HsvColorSap
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Hsv Convert(Rgb input)
public Hsv Convert(in Rgb input)
{
DebugGuard.NotNull(input, nameof(input));
float r = input.R;
float g = input.G;
float b = input.B;

4
src/ImageSharp/ColorSpaces/Conversion/Implementation/HunterLab/CieXyzAndHunterLabConverterBase.cs

@ -18,8 +18,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.HunterLabCo
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float ComputeKa(CieXyz whitePoint)
{
DebugGuard.NotNull(whitePoint, nameof(whitePoint));
if (whitePoint.Equals(Illuminants.C))
{
return 175F;
@ -36,8 +34,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.HunterLabCo
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float ComputeKb(CieXyz whitePoint)
{
DebugGuard.NotNull(whitePoint, nameof(whitePoint));
if (whitePoint == Illuminants.C)
{
return 70F;

11
src/ImageSharp/ColorSpaces/Conversion/Implementation/HunterLab/CieXyzToHunterLabConverter.cs

@ -3,7 +3,6 @@
using System;
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.ColorSpaces;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.HunterLabColorSapce
{
@ -34,18 +33,12 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.HunterLabCo
/// <summary>
/// Gets the target reference white. When not set, <see cref="HunterLab.DefaultWhitePoint"/> is used.
/// </summary>
public CieXyz HunterLabWhitePoint
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get;
}
public CieXyz HunterLabWhitePoint { get; }
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public HunterLab Convert(CieXyz input)
public HunterLab Convert(in CieXyz input)
{
DebugGuard.NotNull(input, nameof(input));
// Conversion algorithm described here: http://en.wikipedia.org/wiki/Lab_color_space#Hunter_Lab
float x = input.X, y = input.Y, z = input.Z;
float xn = this.HunterLabWhitePoint.X, yn = this.HunterLabWhitePoint.Y, zn = this.HunterLabWhitePoint.Z;

5
src/ImageSharp/ColorSpaces/Conversion/Implementation/HunterLab/HunterLabToCieXyzConverter.cs

@ -3,7 +3,6 @@
using System;
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.ColorSpaces;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.HunterLabColorSapce
{
@ -14,10 +13,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.HunterLabCo
{
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public CieXyz Convert(HunterLab input)
public CieXyz Convert(in HunterLab input)
{
DebugGuard.NotNull(input, nameof(input));
// Conversion algorithm described here: http://en.wikipedia.org/wiki/Lab_color_space#Hunter_Lab
float l = input.L, a = input.A, b = input.B;
float xn = input.WhitePoint.X, yn = input.WhitePoint.Y, zn = input.WhitePoint.Z;

9
src/ImageSharp/ColorSpaces/Conversion/Implementation/Lms/CieXyzAndLmsConverter.cs

@ -3,7 +3,6 @@
using System.Numerics;
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.ColorSpaces;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.LmsColorSapce
{
@ -61,20 +60,16 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.LmsColorSap
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Lms Convert(CieXyz input)
public Lms Convert(in CieXyz input)
{
DebugGuard.NotNull(input, nameof(input));
Vector3 vector = Vector3.Transform(input.Vector, this.transformationMatrix);
return new Lms(vector);
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public CieXyz Convert(Lms input)
public CieXyz Convert(in Lms input)
{
DebugGuard.NotNull(input, nameof(input));
Vector3 vector = Vector3.Transform(input.Vector, this.inverseTransformationMatrix);
return new CieXyz(vector);
}

2
src/ImageSharp/ColorSpaces/Conversion/Implementation/Lms/LmsAdaptationMatrix.cs

@ -17,7 +17,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.LmsColorSap
/// DISCo, Department of Informatics, Systems and Communication, University of Milan-Bicocca, viale Sarca 336, 20126 Milan, Italy
/// https://web.stanford.edu/~sujason/ColorBalancing/Papers/Two%20New%20von%20Kries%20Based%20Chromatic%20Adaptation.pdf
/// </remarks>
public static class LmsAdaptationMatrix
internal static class LmsAdaptationMatrix
{
/// <summary>
/// Von Kries chromatic adaptation transform matrix (Hunt-Pointer-Estevez adjusted for D65)

10
src/ImageSharp/ColorSpaces/Conversion/Implementation/Rgb/CieXyzToLinearRgbConverter.cs

@ -8,7 +8,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.RgbColorSap
/// <summary>
/// Color converter between CieXyz and LinearRgb
/// </summary>
internal class CieXyzToLinearRgbConverter : LinearRgbAndCieXyzConverterBase, IColorConversion<CieXyz, LinearRgb>
internal sealed class CieXyzToLinearRgbConverter : LinearRgbAndCieXyzConverterBase, IColorConversion<CieXyz, LinearRgb>
{
private readonly Matrix4x4 conversionMatrix;
@ -24,7 +24,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.RgbColorSap
/// Initializes a new instance of the <see cref="CieXyzToLinearRgbConverter"/> class.
/// </summary>
/// <param name="workingSpace">The target working space.</param>
public CieXyzToLinearRgbConverter(IRgbWorkingSpace workingSpace)
public CieXyzToLinearRgbConverter(RgbWorkingSpace workingSpace)
{
this.TargetWorkingSpace = workingSpace;
this.conversionMatrix = GetRgbToCieXyzMatrix(workingSpace);
@ -33,13 +33,11 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.RgbColorSap
/// <summary>
/// Gets the target working space
/// </summary>
public IRgbWorkingSpace TargetWorkingSpace { get; }
public RgbWorkingSpace TargetWorkingSpace { get; }
/// <inheritdoc/>
public LinearRgb Convert(CieXyz input)
public LinearRgb Convert(in CieXyz input)
{
DebugGuard.NotNull(input, nameof(input));
Matrix4x4.Invert(this.conversionMatrix, out Matrix4x4 inverted);
Vector3 vector = Vector3.Transform(input.Vector, inverted);
return new LinearRgb(vector, this.TargetWorkingSpace);

2
src/ImageSharp/ColorSpaces/Conversion/Implementation/Rgb/GammaCompanding.cs

@ -13,7 +13,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.RgbColorSap
/// <see href="http://www.brucelindbloom.com/index.html?Eqn_RGB_to_XYZ.html"/>
/// <see href="http://www.brucelindbloom.com/index.html?Eqn_XYZ_to_RGB.html"/>
/// </remarks>
public class GammaCompanding : ICompanding
internal class GammaCompanding : ICompanding
{
/// <summary>
/// Initializes a new instance of the <see cref="GammaCompanding"/> class.

4
src/ImageSharp/ColorSpaces/Conversion/Implementation/Rgb/LCompanding.cs

@ -14,7 +14,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.RgbColorSap
/// <see href="http://www.brucelindbloom.com/index.html?Eqn_RGB_to_XYZ.html"/>
/// <see href="http://www.brucelindbloom.com/index.html?Eqn_XYZ_to_RGB.html"/>
/// </remarks>
public class LCompanding : ICompanding
internal class LCompanding : ICompanding
{
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@ -32,4 +32,4 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.RgbColorSap
: MathF.Pow(1.16F * channel, 0.3333333F) - 0.16F;
}
}
}
}

7
src/ImageSharp/ColorSpaces/Conversion/Implementation/Rgb/LinearRgbAndCieXyzConverterBase.cs

@ -15,7 +15,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.RgbColorSap
/// </summary>
/// <param name="workingSpace">The Rgb working space.</param>
/// <returns>The <see cref="Matrix4x4"/> based on the chromaticity and working space.</returns>
public static Matrix4x4 GetRgbToCieXyzMatrix(IRgbWorkingSpace workingSpace)
public static Matrix4x4 GetRgbToCieXyzMatrix(RgbWorkingSpace workingSpace)
{
DebugGuard.NotNull(workingSpace, nameof(workingSpace));
@ -40,7 +40,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.RgbColorSap
const float Yb = 1;
float mZb = (1 - xb - yb) / yb;
Matrix4x4 xyzMatrix = new Matrix4x4
var xyzMatrix = new Matrix4x4
{
M11 = mXr, M21 = mXg, M31 = mXb,
M12 = Yr, M22 = Yg, M32 = Yb,
@ -48,8 +48,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.RgbColorSap
M44 = 1F
};
Matrix4x4 inverseXyzMatrix;
Matrix4x4.Invert(xyzMatrix, out inverseXyzMatrix);
Matrix4x4.Invert(xyzMatrix, out Matrix4x4 inverseXyzMatrix);
Vector3 vector = Vector3.Transform(workingSpace.WhitePoint.Vector, inverseXyzMatrix);

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

Loading…
Cancel
Save