Browse Source

Merge branch 'master' into improvement/oil-processor-memory-usage

af/octree-no-pixelmap
Sergio Pedri 6 years ago
committed by GitHub
parent
commit
c070e300ee
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 16
      .gitattributes
  2. 148
      .github/workflows/build-and-test.yml
  3. 4
      .gitignore
  4. 43
      .travis.yml
  5. 28
      .vscode/launch.json
  6. 31
      .vscode/tasks.json
  7. 22
      CodeCoverage.runsettings
  8. 54
      Directory.Build.props
  9. 31
      Directory.Build.targets
  10. 7
      GitVersion.yml
  11. 96
      ImageSharp.sln
  12. 393
      ImageSharp.sln.DotSettings
  13. 23
      README.md
  14. 69
      appveyor.yml
  15. 17
      build.cmd
  16. 122
      build.ps1
  17. 3
      build/icons/imagesharp-logo-128.png
  18. 3
      build/icons/imagesharp-logo-256.png
  19. 3
      build/icons/imagesharp-logo-32.png
  20. 3
      build/icons/imagesharp-logo-512.png
  21. 3
      build/icons/imagesharp-logo-64.png
  22. 3
      build/icons/imagesharp-logo.png
  23. 1
      build/icons/imagesharp-logo.svg
  24. 13
      ci-build.ps1
  25. 11
      ci-pack.ps1
  26. 37
      ci-test.ps1
  27. 9
      codecov.yml
  28. 112
      run-tests.ps1
  29. 2
      shared-infrastructure
  30. 13
      src/Directory.Build.props
  31. 2
      src/Directory.Build.targets
  32. 53
      src/ImageSharp.Drawing/Common/Extensions/GraphicsOptionsExtensions.cs
  33. 32
      src/ImageSharp.Drawing/ImageSharp.Drawing.csproj
  34. 2
      src/ImageSharp.Drawing/ImageSharp.Drawing.csproj.DotSettings
  35. 36
      src/ImageSharp.Drawing/Primitives/Region.cs
  36. 24
      src/ImageSharp.Drawing/Primitives/ShapePath.cs
  37. 64
      src/ImageSharp.Drawing/Primitives/ShapeRegion.cs
  38. 113
      src/ImageSharp.Drawing/Processing/BrushApplicator.cs
  39. 222
      src/ImageSharp.Drawing/Processing/Brushes.cs
  40. 35
      src/ImageSharp.Drawing/Processing/ColorStop.cs
  41. 22
      src/ImageSharp.Drawing/Processing/DrawingHelpers.cs
  42. 165
      src/ImageSharp.Drawing/Processing/EllipticGradientBrush.cs
  43. 106
      src/ImageSharp.Drawing/Processing/Extensions/DrawBezierExtensions.cs
  44. 106
      src/ImageSharp.Drawing/Processing/Extensions/DrawLineExtensions.cs
  45. 110
      src/ImageSharp.Drawing/Processing/Extensions/DrawPathCollectionExtensions.cs
  46. 103
      src/ImageSharp.Drawing/Processing/Extensions/DrawPathExtensions.cs
  47. 106
      src/ImageSharp.Drawing/Processing/Extensions/DrawPolygonExtensions.cs
  48. 103
      src/ImageSharp.Drawing/Processing/Extensions/DrawRectangleExtensions.cs
  49. 179
      src/ImageSharp.Drawing/Processing/Extensions/DrawTextExtensions.cs
  50. 76
      src/ImageSharp.Drawing/Processing/Extensions/FillPathBuilderExtensions.cs
  51. 76
      src/ImageSharp.Drawing/Processing/Extensions/FillPathCollectionExtensions.cs
  52. 64
      src/ImageSharp.Drawing/Processing/Extensions/FillPathExtensions.cs
  53. 70
      src/ImageSharp.Drawing/Processing/Extensions/FillPolygonExtensions.cs
  54. 66
      src/ImageSharp.Drawing/Processing/Extensions/FillRectangleExtensions.cs
  55. 95
      src/ImageSharp.Drawing/Processing/Extensions/FillRegionExtensions.cs
  56. 164
      src/ImageSharp.Drawing/Processing/GradientBrush.cs
  57. 37
      src/ImageSharp.Drawing/Processing/GradientRepetitionMode.cs
  58. 40
      src/ImageSharp.Drawing/Processing/IBrush.cs
  59. 28
      src/ImageSharp.Drawing/Processing/IPen.cs
  60. 173
      src/ImageSharp.Drawing/Processing/ImageBrush.cs
  61. 160
      src/ImageSharp.Drawing/Processing/LinearGradientBrush.cs
  62. 285
      src/ImageSharp.Drawing/Processing/PathGradientBrush.cs
  63. 178
      src/ImageSharp.Drawing/Processing/PatternBrush.cs
  64. 76
      src/ImageSharp.Drawing/Processing/Pen.cs
  65. 97
      src/ImageSharp.Drawing/Processing/Pens.cs
  66. 41
      src/ImageSharp.Drawing/Processing/Processors/Drawing/FillProcessor.cs
  67. 122
      src/ImageSharp.Drawing/Processing/Processors/Drawing/FillProcessor{TPixel}.cs
  68. 49
      src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor.cs
  69. 197
      src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor{TPixel}.cs
  70. 79
      src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor.cs
  71. 453
      src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor{TPixel}.cs
  72. 104
      src/ImageSharp.Drawing/Processing/RadialGradientBrush.cs
  73. 166
      src/ImageSharp.Drawing/Processing/RecolorBrush.cs
  74. 139
      src/ImageSharp.Drawing/Processing/SolidBrush.cs
  75. 217
      src/ImageSharp.Drawing/Processing/TextGraphicsOptions.cs
  76. 29
      src/ImageSharp.Drawing/Utils/NumberUtils.cs
  77. 84
      src/ImageSharp.Drawing/Utils/QuickSort.cs
  78. 1
      src/ImageSharp/Advanced/AdvancedImageExtensions.cs
  79. 2
      src/ImageSharp/Advanced/AotCompilerTools.cs
  80. 2
      src/ImageSharp/Advanced/ParallelUtils/ParallelExecutionSettings.cs
  81. 2
      src/ImageSharp/Advanced/ParallelUtils/ParallelHelper.cs
  82. 6
      src/ImageSharp/Common/Extensions/EncoderExtensions.cs
  83. 48
      src/ImageSharp/Common/Extensions/StreamExtensions.cs
  84. 1
      src/ImageSharp/Common/Helpers/Buffer2DUtils.cs
  85. 1
      src/ImageSharp/Common/Helpers/DenseMatrixUtils.cs
  86. 1
      src/ImageSharp/Common/Helpers/ImageMaths.cs
  87. 14
      src/ImageSharp/Common/Helpers/TestHelpers.cs
  88. 1
      src/ImageSharp/Common/Helpers/Vector4Utils.cs
  89. 2
      src/ImageSharp/Configuration.cs
  90. 21
      src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs
  91. 5
      src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs
  92. 2
      src/ImageSharp/Formats/Gif/GifDecoderCore.cs
  93. 1
      src/ImageSharp/Formats/Gif/GifEncoderCore.cs
  94. 9
      src/ImageSharp/Formats/Gif/LzwDecoder.cs
  95. 1
      src/ImageSharp/Formats/Gif/LzwEncoder.cs
  96. 1
      src/ImageSharp/Formats/Jpeg/Components/Decoder/IJpegComponent.cs
  97. 2
      src/ImageSharp/Formats/Jpeg/Components/Decoder/IRawJpegData.cs
  98. 1
      src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegBlockPostProcessor.cs
  99. 13
      src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponent.cs
  100. 2
      src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponentPostProcessor.cs

16
.gitattributes

@ -62,15 +62,28 @@
# normalize to Windows-style line endings and
*.sln text eol=crlf merge=union
# treat as binary
*.basis binary
*.bmp binary
*.dds binary
*.dll binary
*.eot binary
*.exe binary
*.gif binary
*.jpg binary
*.ktx binary
*.pbm binary
*.pdf binary
*.png binary
*.tga binary
*.ppt binary
*.pptx binary
*.pvr binary
*.ttf binary
*.snk binary
*.tga binary
*.woff binary
*.woff2 binary
*.xls binary
*.xlsx binary
# diff as plain text
*.doc diff=astextplain
*.docx diff=astextplain
@ -78,6 +91,7 @@
*.pdf diff=astextplain
*.pptx diff=astextplain
*.rtf diff=astextplain
*.svg diff=astextplain
*.jpg filter=lfs diff=lfs merge=lfs -text
*.jpeg filter=lfs diff=lfs merge=lfs -text
*.bmp filter=lfs diff=lfs merge=lfs -text

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

@ -0,0 +1,148 @@
name: Build
on:
push:
branches:
- master
tags:
- "v*"
pull_request:
branches:
- master
jobs:
Build:
strategy:
matrix:
options:
- os: ubuntu-latest
framework: netcoreapp3.1
runtime: -x64
codecov: false
- os: windows-latest
framework: netcoreapp3.1
runtime: -x64
codecov: true
- os: windows-latest
framework: netcoreapp2.1
runtime: -x64
codecov: false
- os: windows-latest
framework: net472
runtime: -x64
codecov: false
- os: windows-latest
framework: net472
runtime: -x86
codecov: false
runs-on: ${{matrix.options.os}}
steps:
- uses: actions/checkout@v2
- name: Install NuGet
uses: NuGet/setup-nuget@v1
- name: Setup Git
shell: bash
run: |
git config --global core.autocrlf false
git config --global core.longpaths true
git fetch --prune --unshallow
git submodule -q update --init --recursive
- name: Fetch Tags for GitVersion
run: |
git fetch --tags
- name: Fetch master for GitVersion
if: github.ref != 'refs/heads/master'
run: git branch --create-reflog master origin/master
- name: Install GitVersion
uses: gittools/actions/setup-gitversion@v0.3
with:
versionSpec: "5.1.x"
- name: Use GitVersion
id: gitversion # step id used as reference for output values
uses: gittools/actions/execute-gitversion@v0.3
- name: Setup DotNet SDK
uses: actions/setup-dotnet@v1
with:
dotnet-version: "3.1.101"
- name: Build
shell: pwsh
run: ./ci-build.ps1 "${{steps.gitversion.outputs.nuGetVersion}}" "${{matrix.options.framework}}"
- name: Test
shell: pwsh
run: ./ci-test.ps1 "${{matrix.options.os}}" "${{matrix.options.framework}}" "${{matrix.options.runtime}}" "${{matrix.options.codecov}}"
env:
CI: True
XUNIT_PATH: .\tests\ImageSharp.Tests # Required for xunit
# Avoid "Please provide the repository token to upload reports via `-t :repository-token`"
# https://community.codecov.io/t/whitelist-github-action-servers-to-upload-without-a-token/491/10
# https://github.community/t5/GitHub-Actions/Make-secrets-available-to-builds-of-forks/m-p/42814/highlight/true#M5129
- name: Update Codecov
uses: iansu/codecov-action-node@v1.0.0
if: matrix.options.codecov == true && startsWith(github.repository, 'SixLabors')
with:
token: 0ef021c7-2679-4012-b42f-4bed33d99450
flags: unittests
Publish:
needs: [Build]
runs-on: windows-latest
if: (github.event_name == 'push')
steps:
- uses: actions/checkout@v2
- name: Install NuGet
uses: NuGet/setup-nuget@v1
- name: Setup Git
shell: bash
run: |
git config --global core.autocrlf false
git config --global core.longpaths true
git fetch --prune --unshallow
git submodule -q update --init --recursive
- name: Fetch Tags for GitVersion
run: |
git fetch --tags
- name: Fetch master for GitVersion
if: github.ref != 'refs/heads/master'
run: git branch --create-reflog master origin/master
- name: Install GitVersion
uses: gittools/actions/setup-gitversion@v0.3
with:
versionSpec: "5.1.x"
- name: Use GitVersion
id: gitversion # step id used as reference for output values
uses: gittools/actions/execute-gitversion@v0.3
- name: Setup DotNet SDK
uses: actions/setup-dotnet@v1
with:
dotnet-version: "3.1.101"
- name: Pack
shell: pwsh
run: ./ci-pack.ps1 "${{steps.gitversion.outputs.nuGetVersion}}"
- name: Publish to MyGet
shell: pwsh
run: nuget.exe push .\artifacts\*.nupkg ${{secrets.MYGET_TOKEN}} -Source https://www.myget.org/F/sixlabors/api/v2/package
# TODO: If github.ref starts with 'refs/tags' then it was tag push and we can optionally push out package to nuget.org

4
.gitignore

@ -137,7 +137,7 @@ publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# TODO: Comment the next line if you want to checkin your web deploy settings
# TODO: Comment the next line if you want to checkin your web deploy settings
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
@ -216,7 +216,7 @@ artifacts/
*.csproj.bak
#CodeCoverage
/ImageSharp.Coverage.xml
*.lcov
# Tests
**/Images/ActualOutput

43
.travis.yml

@ -1,43 +0,0 @@
language: csharp
solution: ImageSharp.sln
matrix:
include:
- os: linux # Ubuntu 16.04
dist: xenial
sudo: required
dotnet: 2.1.603
mono: latest
# - os: osx # OSX 10.11
# osx_image: xcode7.3.1
# dotnet: 1.0.0-preview2-003121
# mono: latest
branches:
only:
- master
- coverity_scan
script:
- git submodule -q update --init
- dotnet restore
- dotnet test tests/ImageSharp.Tests/ImageSharp.Tests.csproj -c Release -f "netcoreapp2.1"
env:
global:
# The next declaration is the encrypted COVERITY_SCAN_TOKEN, created
# via the "travis encrypt" command using the project repo's public key
- secure: "rjMvEMN9rpvIXqXqCAAKzbHyABzr7E4wPU/dYJ/mHBqlCccFpQrEXVVM1MfRFXYuWZSaIioknhLATZjT5xvIYpTNM6D57z4OTmqeRHhYm80="
before_install:
- echo -n | openssl s_client -connect scan.coverity.com:443 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' | sudo tee -a /etc/ssl/certs/ca-
addons:
coverity_scan:
project:
name: "SixLabors/ImageSharp"
description: "Build submitted via Travis CI"
notification_email: james_south@hotmail.com
build_command_prepend: "dotnet restore"
build_command: "dotnet build -c Release"
branch_pattern: coverity_scan

28
.vscode/launch.json

@ -1,28 +0,0 @@
{
// Use IntelliSense to find out which attributes exist for C# debugging
// Use hover for the description of the existing attributes
// For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md
"version": "0.2.0",
"configurations": [
{
"name": ".NET Core Launch (console)",
"type": "coreclr",
"request": "launch",
"preLaunchTask": "build",
// If you have changed target frameworks, make sure to update the program path.
"program": "${workspaceRoot}/tests/ImageSharp.Benchmarks/bin/Debug/netcoreapp2.0/ImageSharp.Benchmarks.dll",
"args": [],
"cwd": "${workspaceRoot}/samples/AvatarWithRoundedCorner",
// For more information about the 'console' field, see https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md#console-terminal-window
"console": "internalConsole",
"stopAtEntry": false,
"internalConsoleOptions": "openOnSessionStart"
},
{
"name": ".NET Core Attach",
"type": "coreclr",
"request": "attach",
"processId": "${command:pickProcess}"
}
]
}

31
.vscode/tasks.json

@ -1,31 +0,0 @@
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "0.1.0",
"command": "dotnet",
"isShellCommand": true,
"args": [],
"tasks": [
{
"taskName": "build",
"args": [ "ImageSharp.sln" ],
"isBuildCommand": true,
"showOutput": "always",
"problemMatcher": "$msCompile"
},
{
"taskName": "build benchmark",
"suppressTaskName": true,
"args": [ "build", "tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj", "-f", "netcoreapp2.0", "-c", "Release" ],
"showOutput": "always",
"problemMatcher": "$msCompile"
},
{
"taskName": "test",
"args": ["tests/ImageSharp.Tests/ImageSharp.Tests.csproj", "-c", "release", "-f", "netcoreapp2.0"],
"isTestCommand": true,
"showOutput": "always",
"problemMatcher": "$msCompile"
}
]
}

22
CodeCoverage.runsettings

@ -1,22 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<RunSettings>
<DataCollectionRunSettings>
<DataCollectors>
<DataCollector friendlyName="Code Coverage" uri="datacollector://Microsoft/CodeCoverage/2.0" assemblyQualifiedName="Microsoft.VisualStudio.Coverage.DynamicCoverageDataCollector, Microsoft.VisualStudio.TraceCollector, Version=11.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<Configuration>
<CodeCoverage>
<ModulePaths>
<Include>
<ModulePath>.*ImageSharp.dll</ModulePath>
</Include>
<Exclude>
<ModulePath>.*tests*</ModulePath>
<ModulePath>.*Tests*</ModulePath>
</Exclude>
</ModulePaths>
</CodeCoverage>
</Configuration>
</DataCollector>
</DataCollectors>
</DataCollectionRunSettings>
</RunSettings>

54
Directory.Build.props

@ -14,7 +14,7 @@
<PropertyGroup>
<BaseArtifactsPath>$(MSBuildThisFileDirectory)artifacts/</BaseArtifactsPath>
<BaseArtifactsPathSuffix>$(ImageSharpProjectCategory)/$(MSBuildProjectName)</BaseArtifactsPathSuffix>
<RepositoryUrl>https://github.com/SixLabors/ImageSharp/</RepositoryUrl>
<RepositoryUrl Condition="'$(RepositoryUrl)' == ''">https://github.com/SixLabors/ImageSharp/</RepositoryUrl>
</PropertyGroup>
<!-- Default settings that explicitly differ from the Sdk.props defaults -->
@ -29,13 +29,38 @@
<SuppressNETCoreSdkPreviewMessage>true</SuppressNETCoreSdkPreviewMessage>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)' == 'Release'">
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<!--
https://apisof.net/
+===================+=======+==========+=====================+=============+=================+====================+==============+
| SUPPORTS | MATHF | HASHCODE | EXTENDED_INTRINSICS | SPAN_STREAM | ENCODING_STRING | RUNTIME_INTRINSICS | CODECOVERAGE |
+===================+=======+==========+=====================+=============+=================+====================+==============+
| netcoreapp3.1 | Y | Y | Y | Y | Y | Y | Y |
| netcoreapp2.1 | Y | Y | Y | Y | Y | N | Y |
| netcoreapp2.0 | Y | N | N | N | N | N | Y |
| netstandard2.1 | Y | Y | N | Y | Y | N | Y |
| netstandard2.0 | N | N | N | N | N | N | Y |
| netstandard1.3 | N | N | N | N | N | N | N |
| net472 | N | N | Y | N | N | N | Y |
+===================+=======+==========+=====================+=============+=================+====================+==============+
-->
<PropertyGroup Condition="'$(TargetFramework)' == 'netcoreapp3.1'">
<DefineConstants>$(DefineConstants);SUPPORTS_MATHF;SUPPORTS_HASHCODE;SUPPORTS_EXTENDED_INTRINSICS;SUPPORTS_SPAN_STREAM;SUPPORTS_ENCODING_STRING;SUPPORTS_RUNTIME_INTRINSICS;SUPPORTS_CODECOVERAGE</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition="'$(TargetFramework)' == 'netcoreapp2.1'">
<DefineConstants>$(DefineConstants);SUPPORTS_MATHF;SUPPORTS_HASHCODE;SUPPORTS_EXTENDED_INTRINSICS;SUPPORTS_SPAN_STREAM;SUPPORTS_ENCODING_STRING;SUPPORTS_CODECOVERAGE</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition="'$(TargetFramework)' == 'netcoreapp2.0'">
<DefineConstants>$(DefineConstants);SUPPORTS_MATHF;SUPPORTS_CODECOVERAGE</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition="'$(TargetFramework)' == 'netstandard2.1'">
<DefineConstants>$(DefineConstants);SUPPORTS_MATHF;SUPPORTS_HASHCODE;SUPPORTS_SPAN_STREAM;SUPPORTS_ENCODING_STRING;SUPPORTS_CODECOVERAGE</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
<DefineConstants>$(DefineConstants);SUPPORTS_CODECOVERAGE</DefineConstants>
</PropertyGroup>
<!--TODO: Check what this is testing for and why does it fail?-->
<PropertyGroup Condition="'$(Configuration)' == 'Debug'">
<CheckForOverflowUnderflow>false</CheckForOverflowUnderflow>
<PropertyGroup Condition="'$(TargetFramework)' == 'net472'">
<DefineConstants>$(DefineConstants);SUPPORTS_EXTENDED_INTRINSICS;SUPPORTS_CODECOVERAGE</DefineConstants>
</PropertyGroup>
<!-- Default settings that explicitly differ from the Sdk.targets defaults-->
@ -56,26 +81,33 @@
<Copyright>Copyright © Six Labors and Contributors</Copyright>
<Features>strict;IOperation</Features>
<HighEntropyVA>true</HighEntropyVA>
<LangVersion>7.3</LangVersion>
<LangVersion>8.0</LangVersion>
<NeutralLanguage>en</NeutralLanguage>
<OverwriteReadOnlyFiles>true</OverwriteReadOnlyFiles>
<PackageIconUrl>https://raw.githubusercontent.com/SixLabors/Branding/master/icons/imagesharp/sixlabors.imagesharp.128.png</PackageIconUrl>
<PackageIcon>icon.png</PackageIcon>
<PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>
<PackageProjectUrl>$(RepositoryUrl)</PackageProjectUrl>
<ProduceReferenceAssembly>true</ProduceReferenceAssembly>
<RepositoryType>git</RepositoryType>
<RestoreSources>
https://www.myget.org/F/sixlabors/api/v3/index.json;
https://dotnetfeed.blob.core.windows.net/dotnet-core/index.json;
https://api.nuget.org/v3/index.json;
<!-- Contains RemoteExecutor. Taken from: https://github.com/dotnet/runtime/blob/master/NuGet.config -->
https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-eng/nuget/v3/index.json;
</RestoreSources>
<SixLaborsPublicKey>002400000c8000009400000006020000002400005253413100040000010001000147e6fe6766715eec6cfed61f1e7dcdbf69748a3e355c67e9d8dfd953acab1d5e012ba34b23308166fdc61ee1d0390d5f36d814a6091dd4b5ed9eda5a26afced924c683b4bfb4b3d64b0586a57eff9f02b1f84e3cb0ddd518bd1697f2c84dcbb97eb8bb5c7801be12112ed0ec86db934b0e9a5171e6bb1384b6d2f7d54dfa97</SixLaborsPublicKey>
<UseSharedCompilation>true</UseSharedCompilation>
</PropertyGroup>
<!-- Package references which are consumed by all projects -->
<!-- Package references and additional files which are consumed by all projects -->
<ItemGroup>
<PackageReference Include="Microsoft.Net.Compilers.Toolset" IsImplicitlyDefined="true" />
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" IsImplicitlyDefined="true" />
<!--TODO: Enable this once tests Stylecop issues are fixed-->
<!--<PackageReference Include="StyleCop.Analyzers" IsImplicitlyDefined="true" />-->
<AdditionalFiles Include="$(MSBuildThisFileDirectory)shared-infrastructure\stylecop.json" />
<!--NuGet package icon source-->
<None Include="$(MSBuildThisFileDirectory)shared-infrastructure\branding\icons\imagesharp\sixlabors.imagesharp.128.png" Pack="true" PackagePath="\icon.png" />
</ItemGroup>
</Project>

31
Directory.Build.targets

@ -15,34 +15,23 @@
<DefineConstants>$(DefineConstants);$(OS)</DefineConstants>
</PropertyGroup>
<!-- Tool versions for tool references across all projects -->
<ItemGroup>
<DotNetCliToolReference Update="dotnet-xunit" Version="2.3.1" />
</ItemGroup>
<!-- Package versions for package references across all projects -->
<ItemGroup>
<PackageReference Update="BenchmarkDotNet" Version="0.12.0" />
<PackageReference Update="Colourful" Version="2.0.3" />
<PackageReference Update="Magick.NET-Q16-AnyCPU" Version="7.14.4" />
<!--Global Dependencies-->
<PackageReference Update="Microsoft.Net.Compilers.Toolset" Version="3.3.1" />
<PackageReference Update="Microsoft.NET.Test.Sdk" Version="15.9.0" />
<PackageReference Update="Moq" Version="4.10.0" />
<PackageReference Update="Pfim" Version="0.9.1" />
<PackageReference Update="SixLabors.Core" Version="1.0.0-beta0008" />
<PackageReference Update="SixLabors.Fonts" Version="1.0.0-beta0009" />
<PackageReference Update="SixLabors.Shapes" Version="1.0.0-beta0009" />
<PackageReference Update="SixLabors.Shapes.Text" Version="1.0.0-beta0009" />
<PackageReference Update="StyleCop.Analyzers" Version="1.1.118" />
<PackageReference Update="System.Drawing.Common" Version="4.7.0" />
<PackageReference Update="Microsoft.NETFramework.ReferenceAssemblies" PrivateAssets="All" Version="1.0.0" />
<PackageReference Update="StyleCop.Analyzers" PrivateAssets="All" Version="1.1.118" />
<!--Src Dependencies-->
<PackageReference Update="System.Buffers" Version="4.5.0" />
<PackageReference Update="System.IO.Compression" Version="4.3.0" />
<PackageReference Update="System.IO.UnmanagedMemoryStream" Version="4.3.0" />
<PackageReference Update="System.Runtime.CompilerServices.Unsafe" Version="4.5.1" />
<PackageReference Update="System.Numerics.Vectors" Version="4.5.0" />
<PackageReference Update="System.Memory" Version="4.5.3" />
<PackageReference Update="System.Runtime.CompilerServices.Unsafe" Version="4.7" />
<PackageReference Update="System.Threading.Tasks.Parallel" Version="4.3.0" />
<PackageReference Update="System.ValueTuple" Version="4.5.0" />
<PackageReference Update="xunit" Version="2.3.1" />
<PackageReference Update="xunit.runner.console" Version="2.3.1" />
<PackageReference Update="xunit.runner.visualstudio" Version="2.3.1" />
</ItemGroup>
</Project>

7
GitVersion.yml

@ -0,0 +1,7 @@
continuous-delivery-fallback-tag: ci
branches:
master:
tag: unstable
mode: ContinuousDeployment
pull-request:
tag: pr

96
ImageSharp.sln

@ -3,24 +3,20 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.28902.138
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SolutionItems", "SolutionItems", "{C317F1B1-D75E-4C6D-83EB-80367343E0D7}"
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{C317F1B1-D75E-4C6D-83EB-80367343E0D7}"
ProjectSection(SolutionItems) = preProject
.editorconfig = .editorconfig
.gitattributes = .gitattributes
.gitignore = .gitignore
.gitmodules = .gitmodules
.travis.yml = .travis.yml
appveyor.yml = appveyor.yml
build.cmd = build.cmd
build.ps1 = build.ps1
codecov.yml = codecov.yml
CodeCoverage.runsettings = CodeCoverage.runsettings
ci-build.ps1 = ci-build.ps1
ci-pack.ps1 = ci-pack.ps1
ci-test.ps1 = ci-test.ps1
Directory.Build.props = Directory.Build.props
Directory.Build.targets = Directory.Build.targets
ImageSharp.sln.DotSettings = ImageSharp.sln.DotSettings
GitVersion.yml = GitVersion.yml
LICENSE = LICENSE
README.md = README.md
run-tests.ps1 = run-tests.ps1
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".github", ".github", "{1799C43E-5C54-4A8F-8D64-B1475241DB0D}"
@ -36,25 +32,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ISSUE_TEMPLATE", "ISSUE_TEM
.github\ISSUE_TEMPLATE\feature-request.md = .github\ISSUE_TEMPLATE\feature-request.md
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".vscode", ".vscode", "{0274D4CF-9932-47CC-8E89-54DC05B8F06E}"
ProjectSection(SolutionItems) = preProject
.vscode\launch.json = .vscode\launch.json
.vscode\tasks.json = .vscode\tasks.json
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{E919DF0B-2607-4462-8FC0-5C98FE50F8C9}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "icons", "icons", "{2B02E303-7CC6-4E15-97EE-DBE86B287553}"
ProjectSection(SolutionItems) = preProject
build\icons\imagesharp-logo-128.png = build\icons\imagesharp-logo-128.png
build\icons\imagesharp-logo-256.png = build\icons\imagesharp-logo-256.png
build\icons\imagesharp-logo-32.png = build\icons\imagesharp-logo-32.png
build\icons\imagesharp-logo-512.png = build\icons\imagesharp-logo-512.png
build\icons\imagesharp-logo-64.png = build\icons\imagesharp-logo-64.png
build\icons\imagesharp-logo.png = build\icons\imagesharp-logo.png
build\icons\imagesharp-logo.svg = build\icons\imagesharp-logo.svg
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{815C0625-CD3D-440F-9F80-2D83856AB7AE}"
ProjectSection(SolutionItems) = preProject
src\Directory.Build.props = src\Directory.Build.props
@ -64,20 +41,12 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{815C0625-CD3
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ImageSharp", "src\ImageSharp\ImageSharp.csproj", "{2AA31A1F-142C-43F4-8687-09ABCA4B3A26}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ImageSharp.Drawing", "src\ImageSharp.Drawing\ImageSharp.Drawing.csproj", "{2E33181E-6E28-4662-A801-E2E7DC206029}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{56801022-D71A-4FBE-BC5B-CBA08E2284EC}"
ProjectSection(SolutionItems) = preProject
tests\Directory.Build.props = tests\Directory.Build.props
tests\Directory.Build.targets = tests\Directory.Build.targets
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "CodeCoverage", "CodeCoverage", "{D4C5EC58-F8E6-4636-B9EE-C99D2578E5C6}"
ProjectSection(SolutionItems) = preProject
tests\CodeCoverage\CodeCoverage.cmd = tests\CodeCoverage\CodeCoverage.cmd
tests\CodeCoverage\packages.config = tests\CodeCoverage\packages.config
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Images", "Images", "{FA55F5DE-11A6-487D-ABA4-BC93A02717DD}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Input", "Input", "{9DA226A1-8656-49A8-A58A-A8B5C081AD66}"
@ -354,9 +323,19 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ImageSharp.Tests", "tests\I
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ImageSharp.Benchmarks", "tests\ImageSharp.Benchmarks\ImageSharp.Benchmarks.csproj", "{2BF743D8-2A06-412D-96D7-F448F00C5EA5}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ImageSharp.Sandbox46", "tests\ImageSharp.Sandbox46\ImageSharp.Sandbox46.csproj", "{561B880A-D9EE-44EF-90F5-817C54A9D9AB}"
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "workflows", "workflows", "{C0D7754B-5277-438E-ABEB-2BA34401B5A7}"
ProjectSection(SolutionItems) = preProject
.github\workflows\build-and-test.yml = .github\workflows\build-and-test.yml
EndProjectSection
EndProject
Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "SharedInfrastructure", "shared-infrastructure\src\SharedInfrastructure\SharedInfrastructure.shproj", "{68A8CC40-6AED-4E96-B524-31B1158FDEEA}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ImageSharp.Tests.ProfilingSandbox", "tests\ImageSharp.Tests.ProfilingSandbox\ImageSharp.Tests.ProfilingSandbox.csproj", "{FC527290-2F22-432C-B77B-6E815726B02C}"
EndProject
Global
GlobalSection(SharedMSBuildProjectFiles) = preSolution
shared-infrastructure\src\SharedInfrastructure\SharedInfrastructure.projitems*{68a8cc40-6aed-4e96-b524-31b1158fdeea}*SharedItemsImports = 13
EndGlobalSection
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|x64 = Debug|x64
@ -378,18 +357,6 @@ Global
{2AA31A1F-142C-43F4-8687-09ABCA4B3A26}.Release|x64.Build.0 = Release|Any CPU
{2AA31A1F-142C-43F4-8687-09ABCA4B3A26}.Release|x86.ActiveCfg = Release|Any CPU
{2AA31A1F-142C-43F4-8687-09ABCA4B3A26}.Release|x86.Build.0 = Release|Any CPU
{2E33181E-6E28-4662-A801-E2E7DC206029}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2E33181E-6E28-4662-A801-E2E7DC206029}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2E33181E-6E28-4662-A801-E2E7DC206029}.Debug|x64.ActiveCfg = Debug|Any CPU
{2E33181E-6E28-4662-A801-E2E7DC206029}.Debug|x64.Build.0 = Debug|Any CPU
{2E33181E-6E28-4662-A801-E2E7DC206029}.Debug|x86.ActiveCfg = Debug|Any CPU
{2E33181E-6E28-4662-A801-E2E7DC206029}.Debug|x86.Build.0 = Debug|Any CPU
{2E33181E-6E28-4662-A801-E2E7DC206029}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2E33181E-6E28-4662-A801-E2E7DC206029}.Release|Any CPU.Build.0 = Release|Any CPU
{2E33181E-6E28-4662-A801-E2E7DC206029}.Release|x64.ActiveCfg = Release|Any CPU
{2E33181E-6E28-4662-A801-E2E7DC206029}.Release|x64.Build.0 = Release|Any CPU
{2E33181E-6E28-4662-A801-E2E7DC206029}.Release|x86.ActiveCfg = Release|Any CPU
{2E33181E-6E28-4662-A801-E2E7DC206029}.Release|x86.Build.0 = Release|Any CPU
{EA3000E9-2A91-4EC4-8A68-E566DEBDC4F6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EA3000E9-2A91-4EC4-8A68-E566DEBDC4F6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EA3000E9-2A91-4EC4-8A68-E566DEBDC4F6}.Debug|x64.ActiveCfg = Debug|Any CPU
@ -414,28 +381,25 @@ Global
{2BF743D8-2A06-412D-96D7-F448F00C5EA5}.Release|x64.Build.0 = Release|Any CPU
{2BF743D8-2A06-412D-96D7-F448F00C5EA5}.Release|x86.ActiveCfg = Release|Any CPU
{2BF743D8-2A06-412D-96D7-F448F00C5EA5}.Release|x86.Build.0 = Release|Any CPU
{561B880A-D9EE-44EF-90F5-817C54A9D9AB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{561B880A-D9EE-44EF-90F5-817C54A9D9AB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{561B880A-D9EE-44EF-90F5-817C54A9D9AB}.Debug|x64.ActiveCfg = Debug|Any CPU
{561B880A-D9EE-44EF-90F5-817C54A9D9AB}.Debug|x64.Build.0 = Debug|Any CPU
{561B880A-D9EE-44EF-90F5-817C54A9D9AB}.Debug|x86.ActiveCfg = Debug|Any CPU
{561B880A-D9EE-44EF-90F5-817C54A9D9AB}.Debug|x86.Build.0 = Debug|Any CPU
{561B880A-D9EE-44EF-90F5-817C54A9D9AB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{561B880A-D9EE-44EF-90F5-817C54A9D9AB}.Release|Any CPU.Build.0 = Release|Any CPU
{561B880A-D9EE-44EF-90F5-817C54A9D9AB}.Release|x64.ActiveCfg = Release|Any CPU
{561B880A-D9EE-44EF-90F5-817C54A9D9AB}.Release|x64.Build.0 = Release|Any CPU
{561B880A-D9EE-44EF-90F5-817C54A9D9AB}.Release|x86.ActiveCfg = Release|Any CPU
{561B880A-D9EE-44EF-90F5-817C54A9D9AB}.Release|x86.Build.0 = Release|Any CPU
{FC527290-2F22-432C-B77B-6E815726B02C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FC527290-2F22-432C-B77B-6E815726B02C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FC527290-2F22-432C-B77B-6E815726B02C}.Debug|x64.ActiveCfg = Debug|Any CPU
{FC527290-2F22-432C-B77B-6E815726B02C}.Debug|x64.Build.0 = Debug|Any CPU
{FC527290-2F22-432C-B77B-6E815726B02C}.Debug|x86.ActiveCfg = Debug|Any CPU
{FC527290-2F22-432C-B77B-6E815726B02C}.Debug|x86.Build.0 = Debug|Any CPU
{FC527290-2F22-432C-B77B-6E815726B02C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FC527290-2F22-432C-B77B-6E815726B02C}.Release|Any CPU.Build.0 = Release|Any CPU
{FC527290-2F22-432C-B77B-6E815726B02C}.Release|x64.ActiveCfg = Release|Any CPU
{FC527290-2F22-432C-B77B-6E815726B02C}.Release|x64.Build.0 = Release|Any CPU
{FC527290-2F22-432C-B77B-6E815726B02C}.Release|x86.ActiveCfg = Release|Any CPU
{FC527290-2F22-432C-B77B-6E815726B02C}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{FBE8C1AD-5AEC-4514-9B64-091D8E145865} = {1799C43E-5C54-4A8F-8D64-B1475241DB0D}
{2B02E303-7CC6-4E15-97EE-DBE86B287553} = {E919DF0B-2607-4462-8FC0-5C98FE50F8C9}
{2AA31A1F-142C-43F4-8687-09ABCA4B3A26} = {815C0625-CD3D-440F-9F80-2D83856AB7AE}
{2E33181E-6E28-4662-A801-E2E7DC206029} = {815C0625-CD3D-440F-9F80-2D83856AB7AE}
{D4C5EC58-F8E6-4636-B9EE-C99D2578E5C6} = {56801022-D71A-4FBE-BC5B-CBA08E2284EC}
{FA55F5DE-11A6-487D-ABA4-BC93A02717DD} = {56801022-D71A-4FBE-BC5B-CBA08E2284EC}
{9DA226A1-8656-49A8-A58A-A8B5C081AD66} = {FA55F5DE-11A6-487D-ABA4-BC93A02717DD}
{1A82C5F6-90E0-4E97-BE16-A825C046B493} = {9DA226A1-8656-49A8-A58A-A8B5C081AD66}
@ -452,7 +416,9 @@ Global
{E1C42A6F-913B-4A7B-B1A8-2BB62843B254} = {9DA226A1-8656-49A8-A58A-A8B5C081AD66}
{EA3000E9-2A91-4EC4-8A68-E566DEBDC4F6} = {56801022-D71A-4FBE-BC5B-CBA08E2284EC}
{2BF743D8-2A06-412D-96D7-F448F00C5EA5} = {56801022-D71A-4FBE-BC5B-CBA08E2284EC}
{561B880A-D9EE-44EF-90F5-817C54A9D9AB} = {56801022-D71A-4FBE-BC5B-CBA08E2284EC}
{C0D7754B-5277-438E-ABEB-2BA34401B5A7} = {1799C43E-5C54-4A8F-8D64-B1475241DB0D}
{68A8CC40-6AED-4E96-B524-31B1158FDEEA} = {815C0625-CD3D-440F-9F80-2D83856AB7AE}
{FC527290-2F22-432C-B77B-6E815726B02C} = {56801022-D71A-4FBE-BC5B-CBA08E2284EC}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {5F8B9D1F-CD8B-4CC5-8216-D531E25BD795}

393
ImageSharp.sln.DotSettings

@ -1,393 +0,0 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:String x:Key="/Default/CodeStyle/CodeCleanup/Profiles/=StyleCop/@EntryIndexedValue">&lt;?xml version="1.0" encoding="utf-16"?&gt;
&lt;Profile name="StyleCop"&gt;
&lt;CSUpdateFileHeader&gt;False&lt;/CSUpdateFileHeader&gt;
&lt;CSArrangeQualifiers&gt;True&lt;/CSArrangeQualifiers&gt;
&lt;CSOptimizeUsings&gt;
&lt;OptimizeUsings&gt;True&lt;/OptimizeUsings&gt;
&lt;EmbraceInRegion&gt;False&lt;/EmbraceInRegion&gt;
&lt;RegionName&gt;&lt;/RegionName&gt;
&lt;/CSOptimizeUsings&gt;
&lt;CSReformatCode&gt;True&lt;/CSReformatCode&gt;
&lt;CSReorderTypeMembers&gt;True&lt;/CSReorderTypeMembers&gt;
&lt;/Profile&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/CodeCleanup/SilentCleanupProfile/@EntryValue">StyleCop</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/MODIFIERS_ORDER/@EntryValue">public protected internal private static new abstract virtual override sealed readonly extern unsafe volatile async</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/ThisQualifier/INSTANCE_MEMBERS_QUALIFY_MEMBERS/@EntryValue">Field, Property, Event, Method</s:String>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/ALIGN_LINQ_QUERY/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/ALIGN_MULTILINE_ARRAY_AND_OBJECT_INITIALIZER/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/ALIGN_MULTILINE_EXPRESSION/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/ALIGN_MULTILINE_EXTENDS_LIST/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/ALIGN_MULTILINE_FOR_STMT/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/ALIGN_MULTILINE_PARAMETER/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/ALIGN_MULTIPLE_DECLARATION/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/ALIGN_MULTLINE_TYPE_PARAMETER_CONSTRAINS/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/ALIGN_MULTLINE_TYPE_PARAMETER_LIST/@EntryValue">True</s:Boolean>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/ANONYMOUS_METHOD_DECLARATION_BRACES/@EntryValue">NEXT_LINE_SHIFTED_2</s:String>
<s:Int64 x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/BLANK_LINES_AROUND_SINGLE_LINE_AUTO_PROPERTY/@EntryValue">1</s:Int64>
<s:Int64 x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/BLANK_LINES_AROUND_SINGLE_LINE_FIELD/@EntryValue">1</s:Int64>
<s:Int64 x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/BLANK_LINES_AROUND_SINGLE_LINE_INVOCABLE/@EntryValue">1</s:Int64>
<s:Int64 x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/BLANK_LINES_AROUND_SINGLE_LINE_PROPERTY/@EntryValue">1</s:Int64>
<s:Int64 x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/BLANK_LINES_BETWEEN_USING_GROUPS/@EntryValue">1</s:Int64>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/CASE_BLOCK_BRACES/@EntryValue">NEXT_LINE_SHIFTED_2</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/FORCE_FIXED_BRACES_STYLE/@EntryValue">ALWAYS_ADD</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/FORCE_FOR_BRACES_STYLE/@EntryValue">ALWAYS_ADD</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/FORCE_FOREACH_BRACES_STYLE/@EntryValue">ALWAYS_ADD</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/FORCE_IFELSE_BRACES_STYLE/@EntryValue">ALWAYS_ADD</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/FORCE_WHILE_BRACES_STYLE/@EntryValue">ALWAYS_ADD</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/INITIALIZER_BRACES/@EntryValue">NEXT_LINE_SHIFTED_2</s:String>
<s:Int64 x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/KEEP_BLANK_LINES_IN_CODE/@EntryValue">1</s:Int64>
<s:Int64 x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/KEEP_BLANK_LINES_IN_DECLARATIONS/@EntryValue">1</s:Int64>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/KEEP_EXISTING_EXPR_MEMBER_ARRANGEMENT/@EntryValue">False</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/KEEP_EXISTING_INITIALIZER_ARRANGEMENT/@EntryValue">False</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/KEEP_USER_LINEBREAKS/@EntryValue">False</s:Boolean>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_ACCESSORHOLDER_ATTRIBUTE_ON_SAME_LINE_EX/@EntryValue">NEVER</s:String>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_CONSTRUCTOR_INITIALIZER_ON_SAME_LINE/@EntryValue">False</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_FIELD_ATTRIBUTE_ON_SAME_LINE/@EntryValue">False</s:Boolean>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_FIELD_ATTRIBUTE_ON_SAME_LINE_EX/@EntryValue">NEVER</s:String>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_SIMPLE_ACCESSOR_ON_SINGLE_LINE/@EntryValue">False</s:Boolean>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_SIMPLE_EMBEDDED_STATEMENT_ON_SAME_LINE/@EntryValue">ALWAYS</s:String>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_TYPE_CONSTRAINTS_ON_SAME_LINE/@EntryValue">False</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_WHILE_ON_NEW_LINE/@EntryValue">True</s:Boolean>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/SIMPLE_EMBEDDED_STATEMENT_STYLE/@EntryValue">ON_SINGLE_LINE</s:String>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/SPACE_AFTER_TYPECAST_PARENTHESES/@EntryValue">False</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/SPACE_AROUND_MULTIPLICATIVE_OP/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/SPACE_WITHIN_SINGLE_LINE_ARRAY_INITIALIZER_BRACES/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/STICK_COMMENT/@EntryValue">False</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/WRAP_AFTER_DECLARATION_LPAR/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/WRAP_AFTER_INVOCATION_LPAR/@EntryValue">True</s:Boolean>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/WRAP_ARGUMENTS_STYLE/@EntryValue">CHOP_IF_LONG</s:String>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/WRAP_BEFORE_BINARY_OPSIGN/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/WRAP_BEFORE_FIRST_TYPE_PARAMETER_CONSTRAINT/@EntryValue">True</s:Boolean>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/WRAP_EXTENDS_LIST_STYLE/@EntryValue">CHOP_IF_LONG</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/WRAP_PARAMETERS_STYLE/@EntryValue">CHOP_IF_LONG</s:String>
<s:String x:Key="/Default/CodeStyle/CSharpFileLayoutPatterns/Pattern/@EntryValue">&lt;?xml version="1.0" encoding="utf-16"?&gt;&#xD;
&lt;Patterns xmlns="urn:schemas-jetbrains-com:member-reordering-patterns"&gt;&#xD;
&lt;TypePattern DisplayName="COM interfaces or structs"&gt;&#xD;
&lt;TypePattern.Match&gt;&#xD;
&lt;Or&gt;&#xD;
&lt;And&gt;&#xD;
&lt;Kind Is="Interface" /&gt;&#xD;
&lt;Or&gt;&#xD;
&lt;HasAttribute Name="System.Runtime.InteropServices.InterfaceTypeAttribute" /&gt;&#xD;
&lt;HasAttribute Name="System.Runtime.InteropServices.ComImport" /&gt;&#xD;
&lt;/Or&gt;&#xD;
&lt;/And&gt;&#xD;
&lt;Kind Is="Struct" /&gt;&#xD;
&lt;/Or&gt;&#xD;
&lt;/TypePattern.Match&gt;&#xD;
&lt;/TypePattern&gt;&#xD;
&lt;TypePattern DisplayName="P/Invoke classes called 'NativeMethods' (StyleCop)"&gt;&#xD;
&lt;TypePattern.Match&gt;&#xD;
&lt;And&gt;&#xD;
&lt;Kind Is="Class" /&gt;&#xD;
&lt;Name Is=".*NativeMethods" /&gt;&#xD;
&lt;/And&gt;&#xD;
&lt;/TypePattern.Match&gt;&#xD;
&lt;/TypePattern&gt;&#xD;
&lt;TypePattern DisplayName="DataMember serialisation classes (StyleCop)"&gt;&#xD;
&lt;TypePattern.Match&gt;&#xD;
&lt;And&gt;&#xD;
&lt;Or&gt;&#xD;
&lt;Kind Is="Field" /&gt;&#xD;
&lt;Kind Is="Property" /&gt;&#xD;
&lt;/Or&gt;&#xD;
&lt;HasAttribute Name="System.Runtime.Serialization.DataMemberAttribute" /&gt;&#xD;
&lt;/And&gt;&#xD;
&lt;/TypePattern.Match&gt;&#xD;
&lt;/TypePattern&gt;&#xD;
&lt;TypePattern DisplayName="Default Pattern (StyleCop)" RemoveRegions="All"&gt;&#xD;
&lt;Entry DisplayName="Constants"&gt;&#xD;
&lt;Entry.Match&gt;&#xD;
&lt;Kind Is="Constant" /&gt;&#xD;
&lt;/Entry.Match&gt;&#xD;
&lt;Entry.SortBy&gt;&#xD;
&lt;Access Order="Public Internal ProtectedInternal Protected Private" /&gt;&#xD;
&lt;Name /&gt;&#xD;
&lt;/Entry.SortBy&gt;&#xD;
&lt;/Entry&gt;&#xD;
&lt;Entry DisplayName="Static fields"&gt;&#xD;
&lt;Entry.Match&gt;&#xD;
&lt;And&gt;&#xD;
&lt;Kind Is="Field" /&gt;&#xD;
&lt;Static /&gt;&#xD;
&lt;/And&gt;&#xD;
&lt;/Entry.Match&gt;&#xD;
&lt;Entry.SortBy&gt;&#xD;
&lt;Access Order="Public Internal ProtectedInternal Protected Private" /&gt;&#xD;
&lt;Readonly /&gt;&#xD;
&lt;Name /&gt;&#xD;
&lt;/Entry.SortBy&gt;&#xD;
&lt;/Entry&gt;&#xD;
&lt;Entry DisplayName="Fields"&gt;&#xD;
&lt;Entry.Match&gt;&#xD;
&lt;Kind Is="Field" /&gt;&#xD;
&lt;/Entry.Match&gt;&#xD;
&lt;Entry.SortBy&gt;&#xD;
&lt;Access Order="Public Internal ProtectedInternal Protected Private" /&gt;&#xD;
&lt;Readonly /&gt;&#xD;
&lt;Name /&gt;&#xD;
&lt;/Entry.SortBy&gt;&#xD;
&lt;/Entry&gt;&#xD;
&lt;Entry Priority="200" DisplayName="Constructors and Destructors"&gt;&#xD;
&lt;Entry.Match&gt;&#xD;
&lt;Or&gt;&#xD;
&lt;Kind Is="Constructor" /&gt;&#xD;
&lt;Kind Is="Destructor" /&gt;&#xD;
&lt;/Or&gt;&#xD;
&lt;/Entry.Match&gt;&#xD;
&lt;Entry.SortBy&gt;&#xD;
&lt;Static /&gt;&#xD;
&lt;Kind Order="Constructor Destructor" /&gt;&#xD;
&lt;Access Order="Public Internal ProtectedInternal Protected Private" /&gt;&#xD;
&lt;/Entry.SortBy&gt;&#xD;
&lt;/Entry&gt;&#xD;
&lt;Entry DisplayName="Delegates"&gt;&#xD;
&lt;Entry.Match&gt;&#xD;
&lt;Kind Is="Delegate" /&gt;&#xD;
&lt;/Entry.Match&gt;&#xD;
&lt;Entry.SortBy&gt;&#xD;
&lt;Access Order="Public Internal ProtectedInternal Protected Private" /&gt;&#xD;
&lt;Static /&gt;&#xD;
&lt;Name /&gt;&#xD;
&lt;/Entry.SortBy&gt;&#xD;
&lt;/Entry&gt;&#xD;
&lt;Entry DisplayName="Public events"&gt;&#xD;
&lt;Entry.Match&gt;&#xD;
&lt;And&gt;&#xD;
&lt;Kind Is="Event" /&gt;&#xD;
&lt;Access Is="Public" /&gt;&#xD;
&lt;/And&gt;&#xD;
&lt;/Entry.Match&gt;&#xD;
&lt;Entry.SortBy&gt;&#xD;
&lt;Access Order="Public" /&gt;&#xD;
&lt;Static /&gt;&#xD;
&lt;Name /&gt;&#xD;
&lt;/Entry.SortBy&gt;&#xD;
&lt;/Entry&gt;&#xD;
&lt;Entry DisplayName="Interface events"&gt;&#xD;
&lt;Entry.Match&gt;&#xD;
&lt;And&gt;&#xD;
&lt;Kind Is="Event" /&gt;&#xD;
&lt;ImplementsInterface /&gt;&#xD;
&lt;/And&gt;&#xD;
&lt;/Entry.Match&gt;&#xD;
&lt;Entry.SortBy&gt;&#xD;
&lt;ImplementsInterface Immediate="True" /&gt;&#xD;
&lt;Name /&gt;&#xD;
&lt;/Entry.SortBy&gt;&#xD;
&lt;/Entry&gt;&#xD;
&lt;Entry DisplayName="Other events"&gt;&#xD;
&lt;Entry.Match&gt;&#xD;
&lt;Kind Is="Event" /&gt;&#xD;
&lt;/Entry.Match&gt;&#xD;
&lt;Entry.SortBy&gt;&#xD;
&lt;Access Order="Public Internal ProtectedInternal Protected Private" /&gt;&#xD;
&lt;Static /&gt;&#xD;
&lt;Name /&gt;&#xD;
&lt;/Entry.SortBy&gt;&#xD;
&lt;/Entry&gt;&#xD;
&lt;Entry DisplayName="Enums"&gt;&#xD;
&lt;Entry.Match&gt;&#xD;
&lt;Kind Is="Enum" /&gt;&#xD;
&lt;/Entry.Match&gt;&#xD;
&lt;Entry.SortBy&gt;&#xD;
&lt;Access Order="Public Internal ProtectedInternal Protected Private" /&gt;&#xD;
&lt;Name /&gt;&#xD;
&lt;/Entry.SortBy&gt;&#xD;
&lt;/Entry&gt;&#xD;
&lt;Entry DisplayName="Interfaces"&gt;&#xD;
&lt;Entry.Match&gt;&#xD;
&lt;Kind Is="Interface" /&gt;&#xD;
&lt;/Entry.Match&gt;&#xD;
&lt;Entry.SortBy&gt;&#xD;
&lt;Access Order="Public Internal ProtectedInternal Protected Private" /&gt;&#xD;
&lt;Name /&gt;&#xD;
&lt;/Entry.SortBy&gt;&#xD;
&lt;/Entry&gt;&#xD;
&lt;Entry DisplayName="Public properties"&gt;&#xD;
&lt;Entry.Match&gt;&#xD;
&lt;And&gt;&#xD;
&lt;Kind Is="Property" /&gt;&#xD;
&lt;Access Is="Public" /&gt;&#xD;
&lt;/And&gt;&#xD;
&lt;/Entry.Match&gt;&#xD;
&lt;Entry.SortBy&gt;&#xD;
&lt;Static /&gt;&#xD;
&lt;Name /&gt;&#xD;
&lt;/Entry.SortBy&gt;&#xD;
&lt;/Entry&gt;&#xD;
&lt;Entry DisplayName="Interface properties"&gt;&#xD;
&lt;Entry.Match&gt;&#xD;
&lt;And&gt;&#xD;
&lt;Kind Is="Property" /&gt;&#xD;
&lt;ImplementsInterface /&gt;&#xD;
&lt;/And&gt;&#xD;
&lt;/Entry.Match&gt;&#xD;
&lt;Entry.SortBy&gt;&#xD;
&lt;ImplementsInterface Immediate="True" /&gt;&#xD;
&lt;Name /&gt;&#xD;
&lt;/Entry.SortBy&gt;&#xD;
&lt;/Entry&gt;&#xD;
&lt;Entry DisplayName="Other properties"&gt;&#xD;
&lt;Entry.Match&gt;&#xD;
&lt;Kind Is="Property" /&gt;&#xD;
&lt;/Entry.Match&gt;&#xD;
&lt;Entry.SortBy&gt;&#xD;
&lt;Access Order="Public Internal ProtectedInternal Protected Private" /&gt;&#xD;
&lt;Static /&gt;&#xD;
&lt;Name /&gt;&#xD;
&lt;/Entry.SortBy&gt;&#xD;
&lt;/Entry&gt;&#xD;
&lt;Entry Priority="1000" DisplayName="Public indexers"&gt;&#xD;
&lt;Entry.Match&gt;&#xD;
&lt;And&gt;&#xD;
&lt;Kind Is="Indexer" /&gt;&#xD;
&lt;Access Is="Public" /&gt;&#xD;
&lt;/And&gt;&#xD;
&lt;/Entry.Match&gt;&#xD;
&lt;Entry.SortBy&gt;&#xD;
&lt;Static /&gt;&#xD;
&lt;Name /&gt;&#xD;
&lt;/Entry.SortBy&gt;&#xD;
&lt;/Entry&gt;&#xD;
&lt;Entry Priority="1000" DisplayName="Interface indexers"&gt;&#xD;
&lt;Entry.Match&gt;&#xD;
&lt;And&gt;&#xD;
&lt;Kind Is="Indexer" /&gt;&#xD;
&lt;ImplementsInterface /&gt;&#xD;
&lt;/And&gt;&#xD;
&lt;/Entry.Match&gt;&#xD;
&lt;Entry.SortBy&gt;&#xD;
&lt;ImplementsInterface Immediate="True" /&gt;&#xD;
&lt;Name /&gt;&#xD;
&lt;/Entry.SortBy&gt;&#xD;
&lt;/Entry&gt;&#xD;
&lt;Entry Priority="1000" DisplayName="Other indexers"&gt;&#xD;
&lt;Entry.Match&gt;&#xD;
&lt;Kind Is="Indexer" /&gt;&#xD;
&lt;/Entry.Match&gt;&#xD;
&lt;Entry.SortBy&gt;&#xD;
&lt;Access Order="Public Internal ProtectedInternal Protected Private" /&gt;&#xD;
&lt;Static /&gt;&#xD;
&lt;Name /&gt;&#xD;
&lt;/Entry.SortBy&gt;&#xD;
&lt;/Entry&gt;&#xD;
&lt;Entry DisplayName="Public methods and operators"&gt;&#xD;
&lt;Entry.Match&gt;&#xD;
&lt;And&gt;&#xD;
&lt;Or&gt;&#xD;
&lt;Kind Is="Method" /&gt;&#xD;
&lt;Kind Is="Operator" /&gt;&#xD;
&lt;/Or&gt;&#xD;
&lt;Access Is="Public" /&gt;&#xD;
&lt;/And&gt;&#xD;
&lt;/Entry.Match&gt;&#xD;
&lt;Entry.SortBy&gt;&#xD;
&lt;Static /&gt;&#xD;
&lt;Name /&gt;&#xD;
&lt;/Entry.SortBy&gt;&#xD;
&lt;/Entry&gt;&#xD;
&lt;Entry DisplayName="Interface methods"&gt;&#xD;
&lt;Entry.Match&gt;&#xD;
&lt;And&gt;&#xD;
&lt;Kind Is="Method" /&gt;&#xD;
&lt;ImplementsInterface /&gt;&#xD;
&lt;/And&gt;&#xD;
&lt;/Entry.Match&gt;&#xD;
&lt;Entry.SortBy&gt;&#xD;
&lt;ImplementsInterface Immediate="True" /&gt;&#xD;
&lt;Name /&gt;&#xD;
&lt;/Entry.SortBy&gt;&#xD;
&lt;/Entry&gt;&#xD;
&lt;Entry DisplayName="Other methods"&gt;&#xD;
&lt;Entry.Match&gt;&#xD;
&lt;Kind Is="Method" /&gt;&#xD;
&lt;/Entry.Match&gt;&#xD;
&lt;Entry.SortBy&gt;&#xD;
&lt;Access Order="Public Internal ProtectedInternal Protected Private" /&gt;&#xD;
&lt;Static /&gt;&#xD;
&lt;Name /&gt;&#xD;
&lt;/Entry.SortBy&gt;&#xD;
&lt;/Entry&gt;&#xD;
&lt;Entry DisplayName="Operators"&gt;&#xD;
&lt;Entry.Match&gt;&#xD;
&lt;Kind Is="Operator" /&gt;&#xD;
&lt;/Entry.Match&gt;&#xD;
&lt;Entry.SortBy&gt;&#xD;
&lt;Access Order="Public Internal ProtectedInternal Protected Private" /&gt;&#xD;
&lt;Static /&gt;&#xD;
&lt;Name /&gt;&#xD;
&lt;/Entry.SortBy&gt;&#xD;
&lt;/Entry&gt;&#xD;
&lt;Entry Priority="600" DisplayName="Nested structs"&gt;&#xD;
&lt;Entry.Match&gt;&#xD;
&lt;Kind Is="Struct" /&gt;&#xD;
&lt;/Entry.Match&gt;&#xD;
&lt;Entry.SortBy&gt;&#xD;
&lt;Static /&gt;&#xD;
&lt;Access Order="Public Internal ProtectedInternal Protected Private" /&gt;&#xD;
&lt;Name /&gt;&#xD;
&lt;/Entry.SortBy&gt;&#xD;
&lt;/Entry&gt;&#xD;
&lt;Entry Priority="700" DisplayName="Nested classes"&gt;&#xD;
&lt;Entry.Match&gt;&#xD;
&lt;Kind Is="Class" /&gt;&#xD;
&lt;/Entry.Match&gt;&#xD;
&lt;Entry.SortBy&gt;&#xD;
&lt;Static /&gt;&#xD;
&lt;Access Order="Public Internal ProtectedInternal Protected Private" /&gt;&#xD;
&lt;Name /&gt;&#xD;
&lt;/Entry.SortBy&gt;&#xD;
&lt;/Entry&gt;&#xD;
&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">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>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=EOF/@EntryIndexedValue">EOF</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=FDCT/@EntryIndexedValue">FDCT</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=IDCT/@EntryIndexedValue">IDCT</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=JPEG/@EntryIndexedValue">JPEG</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=MCU/@EntryIndexedValue">MCU</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=PNG/@EntryIndexedValue">PNG</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=RGB/@EntryIndexedValue">RGB</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=RLE/@EntryIndexedValue">RLE</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=XY/@EntryIndexedValue">XY</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=XYZ/@EntryIndexedValue">XYZ</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/EventHandlerPatternLong/@EntryValue">$object$_On$event$</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=Constants/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=EnumMember/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=Interfaces/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="I" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=LocalConstants/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=Locals/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=MethodPropertyEvent/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=Other/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=Parameters/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateConstants/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateInstanceFields/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateStaticFields/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateStaticReadonly/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PublicFields/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=StaticReadonly/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=TypeParameters/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="T" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=TypesAndNamespaces/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpAttributeForSingleLineMethodUpgrade/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpKeepExistingMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpPlaceEmbeddedOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpRenamePlacementToArrangementMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpUseContinuousIndentInsideBracesMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EAddAccessorOwnerDeclarationBracesMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EAlwaysTreatStructAsNotReorderableMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002ECSharpPlaceAttributeOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateBlankLinesAroundFieldToBlankLinesAroundProperty/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateThisQualifierSettings/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Bgra/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Quantizer/@EntryIndexedValue">True</s:Boolean>
</wpf:ResourceDictionary>

23
README.md

@ -8,6 +8,7 @@ SixLabors.ImageSharp
<div align="center">
[![Build Status](https://img.shields.io/github/workflow/status/SixLabors/ImageSharp/Build/master)](https://github.com/SixLabors/ImageSharp/actions)
[![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)
@ -35,7 +36,6 @@ Install stable releases via Nuget; development releases are available via MyGet.
| Package Name | Release (NuGet) | Nightly (MyGet) |
|--------------------------------|-----------------|-----------------|
| `SixLabors.ImageSharp` | [![NuGet](https://img.shields.io/nuget/v/SixLabors.ImageSharp.svg)](https://www.nuget.org/packages/SixLabors.ImageSharp/) | [![MyGet](https://img.shields.io/myget/sixlabors/v/SixLabors.ImageSharp.svg)](https://www.myget.org/feed/sixlabors/package/nuget/SixLabors.ImageSharp) |
| `SixLabors.ImageSharp.Drawing` | [![NuGet](https://img.shields.io/nuget/v/SixLabors.ImageSharp.Drawing.svg)](https://www.nuget.org/packages/SixLabors.ImageSharp.Drawing/) | [![MyGet](https://img.shields.io/myget/sixlabors/v/SixLabors.ImageSharp.Drawing.svg)](https://www.myget.org/feed/sixlabors/package/nuget/SixLabors.ImageSharp.Drawing) |
### Packages
@ -46,18 +46,13 @@ The **ImageSharp** library is made up of multiple packages:
- Transform methods like Resize, Crop, Skew, Rotate - anything that alters the dimensions of the image
- Non-transform methods like Gaussian Blur, Pixelate, Edge Detection - anything that maintains the original image dimensions
- **SixLabors.ImageSharp.Drawing**
- Brushes and various drawing algorithms, including drawing images
- Various vector drawing methods for drawing paths, polygons etc.
- Text drawing
<!--
### Build Status
| |Build Status|Code Coverage|
|-------------|:----------:|:-----------:|
|**Linux/Mac**|[![Build Status](https://travis-ci.org/SixLabors/ImageSharp.svg)](https://travis-ci.org/SixLabors/ImageSharp)|[![Code coverage](https://codecov.io/gh/SixLabors/ImageSharp/branch/master/graph/badge.svg)](https://codecov.io/gh/SixLabors/ImageSharp)|
|**Windows** |[![Build Status](https://ci.appveyor.com/api/projects/status/m9pn907xdah3ca39/branch/master?svg=true)](https://ci.appveyor.com/project/six-labors/imagesharp/branch/master)|[![Code coverage](https://codecov.io/gh/SixLabors/ImageSharp/branch/master/graph/badge.svg)](https://codecov.io/gh/SixLabors/ImageSharp)|
|Build Status|Code Coverage|
|:----------:|:-----------:|
|[![Build Status](https://img.shields.io/github/workflow/status/SixLabors/ImageSharp/Build/master)](https://github.com/SixLabors/ImageSharp/actions)|[![Code coverage](https://codecov.io/gh/SixLabors/ImageSharp/branch/master/graph/badge.svg)](https://codecov.io/gh/SixLabors/ImageSharp)|
-->
### 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 not** open issues for questions!
@ -80,7 +75,7 @@ using SixLabors.ImageSharp.PixelFormats;
// Image.Load(string path) is a shortcut for our default type.
// Other pixel formats use Image.Load<TPixel>(string path))
using (Image<Rgba32> image = Image.Load("foo.jpg"))
using (Image image = Image.Load("foo.jpg"))
{
image.Mutate(x => x
.Resize(image.Width / 2, image.Height / 2)
@ -113,9 +108,9 @@ For more examples check out:
If you prefer, you can compile ImageSharp yourself (please do and help!)
- Using [Visual Studio 2017](https://visualstudio.microsoft.com/vs/)
- Using [Visual Studio 2019](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
- Make sure you have [the .NET Core 3.1 SDK](https://www.microsoft.com/net/core#windows) installed
Alternatively, you can work from command line and/or with a lightweight editor on **both Linux/Unix and Windows**:

69
appveyor.yml

@ -1,69 +0,0 @@
version: 1.0.0.{build}
image: 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: net472
is_32bit: False
- target_framework: net472
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 --info
build_script:
- cmd: build.cmd
test_script:
- ps: .\run-tests.ps1 $env:target_framework $env:is_32bit
after_test:
- cmd: appveyor PushArtifact "artifacts\SixLabors.ImageSharp.%APPVEYOR_BUILD_VERSION%.nupkg"
- cmd: appveyor PushArtifact "artifacts\SixLabors.ImageSharp.Drawing.%APPVEYOR_BUILD_VERSION%.nupkg"
deploy:
# MyGet Deployment for builds & releases
- provider: NuGet
server: https://www.myget.org/F/sixlabors/api/v2/package
symbol_server: https://www.myget.org/F/sixlabors/symbols/api/v2/package
api_key:
secure: V/lEHP0UeMWIpWd0fiNlY2IgbCnJKQlGdRksECdJbOBdaE20Fl0RNL7WyqHe02o4
artifact: /.*\.nupkg/
on:
branch: master

17
build.cmd

@ -1,17 +0,0 @@
@echo Off
PowerShell -NoProfile -ExecutionPolicy Bypass -Command "& '.\build.ps1'"
if not "%errorlevel%"=="0" goto failure
:success
ECHO successfully built project
REM exit 0
goto end
:failure
ECHO failed to build.
REM exit -1
goto end
:end

122
build.ps1

@ -1,122 +0,0 @@
# lets calulat the correct version here
$fallbackVersion = "1.0.0";
$version = ''
$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) {
Write-Debug "Building commit tagged with a compatable version number"
$version = $matches[1]
$postTag = $matches[3]
$count = $matches[4]
Write-Debug "version number: ${version} post tag: ${postTag} count: ${count}"
if("$postTag" -ne ""){
$version = "${version}-${postTag}"
}
if("$count" -ne ""){
# for consistancy with previous releases we pad the counter to only 4 places
$padded = $count.Trim().Trim('0').PadLeft(4,"0");
Write-Debug "count '$count', padded '${padded}'"
$version = "${version}${padded}"
}
}
else {
Write-Debug "Untagged"
$lastTag = (git tag --list --sort=-taggerdate) | Out-String
$list = $lastTag.Split("`n")
foreach ($tag in $list) {
Write-Debug "testing ${tag}"
$tag = $tag.Trim();
if($tag -match $tagRegex){
Write-Debug "matched ${tag}"
$version = $matches[1];
break;
}
}
if("$version" -eq ""){
$version = $fallbackVersion
Write-Debug "Failed to discover base version Fallback to '${version}'"
}else{
Write-Debug "Discovered base version from tags '${version}'"
}
$buildNumber = $env:APPVEYOR_BUILD_NUMBER
# build number replacement is padded to 6 places
$buildNumber = "$buildNumber".Trim().Trim('0').PadLeft(6,"0");
if("$env:APPVEYOR_PULL_REQUEST_NUMBER" -ne ""){
Write-Debug "building a PR"
$prNumber = "$env:APPVEYOR_PULL_REQUEST_NUMBER".Trim().Trim('0').PadLeft(5,"0");
# this is a PR
$version = "${version}-PullRequest${prNumber}${buildNumber}";
}else{
Write-Debug "building a branch commit"
# this is a general branch commit
$branch = $env:APPVEYOR_REPO_BRANCH
if("$branch" -eq ""){
$branch = ((git rev-parse --abbrev-ref HEAD) | Out-String).Trim()
if("$branch" -eq ""){
$branch = "unknown"
}
}
$branch = $branch.Replace("/","-").ToLower()
if($branch.ToLower() -eq "master"){
$branch = "dev"
}
$version = "${version}-${branch}${buildNumber}";
}
}
if("$env:APPVEYOR_API_URL" -ne ""){
# update appveyor build number for this build
Invoke-RestMethod -Method "PUT" `
-Uri "${env:APPVEYOR_API_URL}api/build" `
-Body "{version:'${version}'}" `
-ContentType "application/json"
}
Write-Host "Building version '${version}'"
dotnet restore /p:packageversion=$version /p:DisableImplicitNuGetFallbackFolder=true
Write-Host "Building projects"
dotnet build -c Release /p:packageversion=$version
if ($LASTEXITCODE ){ Exit $LASTEXITCODE }
#
# 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"
dotnet pack ./src/ImageSharp/ -c Release --output ../../artifacts --no-build /p:packageversion=$version
if ($LASTEXITCODE ){ Exit $LASTEXITCODE }
dotnet pack ./src/ImageSharp.Drawing/ -c Release --output ../../artifacts --no-build /p:packageversion=$version
if ($LASTEXITCODE ){ Exit $LASTEXITCODE }

3
build/icons/imagesharp-logo-128.png

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:148a268c589b628f5d0b5af0e86911a0b393c35b8b25233c71553657c88e0b96
size 7568

3
build/icons/imagesharp-logo-256.png

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:7e4b2ff72aef1979500cd130c28490a00be116bb833bc96ca30c85dc0596099c
size 15413

3
build/icons/imagesharp-logo-32.png

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:021c12313afbdc65f58bfea8c7b436d5c2102513bb63d9e64ee2b61a1344c56a
size 1799

3
build/icons/imagesharp-logo-512.png

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:3ae54ae0035df1f8f1459081e2f1d5cceda6f88cca6ec015d8c0209bf0d34edf
size 32534

3
build/icons/imagesharp-logo-64.png

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:92896854265693f28f9a503b9093cb2c9a4a9b329f310732efdd9c6f6c3761bc
size 3736

3
build/icons/imagesharp-logo.png

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:3ae54ae0035df1f8f1459081e2f1d5cceda6f88cca6ec015d8c0209bf0d34edf
size 32534

1
build/icons/imagesharp-logo.svg

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M955.19-89.12c1.71.76 2.92 2.23 4.1 3.64-2.36.5-4.63-1.09-4.1-3.64z" fill="#f3f3f3"/><path d="M955.99 795.86c-.55-2.11 1.59-3.28 3.42-2.81-.92 1.17-1.92 2.39-3.42 2.81zm-824.02-1.84c2.01-.67 3.78.88 3.23 2.98-1.34-.69-2.38-1.78-3.23-2.98z" fill="#f4f4f4"/><g transform="translate(3 77.213) scale(.84333)"><path d="M360.394-81.917C332.176-34.178 310.797 7.886 286.16 51.626c-38.852 5.81-87.766 35.358-108.462 53.536-23.27-39.522-47.319-80.984-72.065-121.732 48.75-44.512 145.286-87.984 254.761-65.347z" fill="#fcee21"/><path d="M585.941 121.39a63184.8 63184.8 0 0 1-162.904-.018c-26.67-31.213-61.232-56.836-94.452-65.342 23.084-40.89 47.898-86.085 70.744-127.125 75.877 25.617 155.261 90.42 186.612 192.486z" fill="#ed7124"/><path d="M78.958 9.17c27.048 46.86 52.248 90.395 75.86 129.989-17.584 46.554-19.429 90.024-5.9 130.23-50.04.125-100.355.347-143.226.41-17.334-90.382 6.06-188.551 73.266-260.63z" fill="#35a849"/><path d="M331.618 50.646c39.7 5.695 90.586 40.866 105.695 70.748-44.912-.15-107.006-.198-146.153-.135 13.192-22.859 29.853-51.82 40.458-70.613z" fill="#cd5911"/><path d="M234.715 269.473c-28.712.242-63.776.092-89.229-.09-17.285-42.947-11.055-100.462 8.472-131.656 27.3 45.036 56.142 92.792 80.757 131.746z" fill="#298138"/><path d="M444.344 158.743c49.347.175 101.697.11 150.938.113 18.912 93.176-15.004 195.992-76.919 258.997-27.185-46.24-51.866-89.439-77.095-132.613l.15-.34c10.485-22.85 15.306-48.2 14.153-73.303-1.531-18.873-5.622-37.733-11.227-52.854z" fill="#cb202d"/><path d="M367.352 158.939c26.614.068 65.477-.264 88.655-.172 17.291 42.172 7.163 95.713-11.41 132.164-24.437-42.171-54.894-93.243-77.245-131.992z" fill="#9f1923"/><path d="M165.551 305.827c23.184 34.257 60.157 58.85 100.814 66.88-25.464 42.621-47.314 80.025-70.74 120.477C108.02 463.19 42.056 388.03 15.05 305.822a79196.89 79196.89 0 0 1 150.5.005z" fill="#085ba7"/><path d="M418.737 319.328l.11.18c24.153 41.18 48.356 82.328 72.668 123.418-71.641 59.524-168.65 81.977-254.913 62.306 25.735-44.76 51.465-88.751 77.103-133.568 41.19-8.196 81.388-26.52 105.046-52.336z" fill="#5f2c83"/><path d="M164.496 305.822c47.886.079 95.948-.024 140.829.009-12.442 22.552-39.753 68.221-39.3 67.463-40.85-7.405-79.046-31.74-101.53-67.472z" fill="#064076"/><path d="M380.797 255.307c12.77 21.268 27.863 46.872 40.484 68.227-26.416 30.286-70.536 50.076-110.301 52.908 21.612-38.994 48.471-86.745 69.817-121.135z" fill="#431f5d"/><ellipse ry="59.777" rx="59.861" cy="212.001" cx="300.001" fill="#e3018f"/><path d="M288.47 47.639c-22.376 38.536-52.246 89.024-71.803 122.212-13.891-22.894-28.313-46.46-40.324-66.915 15.85-17.392 51.175-48.759 112.127-55.297z" fill="#e7d803"/></g></svg>

Before

Width:  |  Height:  |  Size: 2.7 KiB

13
ci-build.ps1

@ -0,0 +1,13 @@
param(
[Parameter(Mandatory, Position = 0)]
[string]$version,
[Parameter(Mandatory = $true, Position = 1)]
[string]$targetFramework
)
dotnet clean -c Release
$repositoryUrl = "https://github.com/$env:GITHUB_REPOSITORY"
# Building for a specific framework.
dotnet build -c Release -f $targetFramework /p:packageversion=$version /p:RepositoryUrl=$repositoryUrl

11
ci-pack.ps1

@ -0,0 +1,11 @@
param(
[Parameter(Mandatory, Position = 0)]
[string]$version
)
dotnet clean -c Release
$repositoryUrl = "https://github.com/$env:GITHUB_REPOSITORY"
# Building for packing and publishing.
dotnet pack -c Release --output "$PSScriptRoot/artifacts" /p:packageversion=$version /p:RepositoryUrl=$repositoryUrl

37
ci-test.ps1

@ -0,0 +1,37 @@
param(
[Parameter(Mandatory, Position = 0)]
[string]$os,
[Parameter(Mandatory, Position = 1)]
[string]$targetFramework,
[Parameter(Mandatory, Position = 2)]
[string]$platform,
[Parameter(Mandatory, Position = 3)]
[string]$codecov,
[Parameter(Position = 4)]
[string]$codecovProfile = 'Release'
)
$netFxRegex = '^net\d+'
if ($codecov -eq 'true') {
# Allow toggling of profile to workaround any potential JIT errors caused by code injection.
dotnet clean -c $codecovProfile
dotnet test --collect "XPlat Code Coverage" --settings .\tests\coverlet.runsettings -c $codecovProfile -f $targetFramework /p:CodeCov=true
}
elseif ($platform -eq '-x86' -and $targetFramework -match $netFxRegex) {
# xunit doesn't run on core with NET SDK 3.1+.
# xunit doesn't actually understand -x64 as an option.
#
# xunit requires explicit path.
Set-Location $env:XUNIT_PATH
dotnet xunit --no-build -c Release -f $targetFramework ${fxVersion} $platform
Set-Location $PSScriptRoot
}
else {
dotnet test --no-build -c Release -f $targetFramework
}

9
codecov.yml

@ -1,4 +1,7 @@
ignore:
"src/ImageSharp/Common/Helpers/DebugGuard.cs"
# Documentation: https://docs.codecov.io/docs/codecov-yaml
codecov:
# Avoid "Missing base report"
# https://github.com/codecov/support/issues/363
# https://docs.codecov.io/docs/comparing-commits
allow_coverage_offsets: true

112
run-tests.ps1

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

2
shared-infrastructure

@ -1 +1 @@
Subproject commit faf84e44ec90e8a42a7271bcd04fea76279efb08
Subproject commit 36b2d55f5bb0d91024955bd26ba220ee41cc96e5

13
src/Directory.Build.props

@ -22,11 +22,14 @@
<GenerateDocumentationFile>true</GenerateDocumentationFile>
</PropertyGroup>
<ItemGroup>
<AdditionalFiles Include="$(MSBuildThisFileDirectory)..\shared-infrastructure\stylecop.json" />
</ItemGroup>
<PropertyGroup Condition="'$(Configuration)' == 'Release'">
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>
<ItemGroup>
<!--TODO: Delete this once tests Stylecop issues are fixed-->
<PackageReference Include="StyleCop.Analyzers" IsImplicitlyDefined="true" />
<InternalsVisibleTo Include="DynamicProxyGenAssembly2" PublicKey="0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7" />
<InternalsVisibleTo Include="DynamicProxyGenAssembly2, PublicKeyToken=null" />
<InternalsVisibleTo Include="ImageSharp.Benchmarks" />
@ -34,8 +37,4 @@
<InternalsVisibleTo Include="SixLabors.ImageSharp.Tests" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="StyleCop.Analyzers" PrivateAssets="All" />
</ItemGroup>
</Project>

2
src/Directory.Build.targets

@ -50,6 +50,6 @@
<!-- Empty target so that `dotnet test` will work on the solution -->
<!-- https://github.com/Microsoft/vstest/issues/411 -->
<Target Name="VSTest" />
<Target Name="VSTest" Condition="'$(IsTestProject)' == 'true'"/>
</Project>

53
src/ImageSharp.Drawing/Common/Extensions/GraphicsOptionsExtensions.cs

@ -1,53 +0,0 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System.Numerics;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp
{
/// <summary>
/// Extensions methods fpor the <see cref="GraphicsOptions"/> class.
/// </summary>
internal static class GraphicsOptionsExtensions
{
/// <summary>
/// Evaluates if a given SOURCE color can completely replace a BACKDROP color given the current blending and composition settings.
/// </summary>
/// <param name="options">The graphics options.</param>
/// <param name="color">The source color.</param>
/// <returns>true if the color can be considered opaque</returns>
/// <remarks>
/// Blending and composition is an expensive operation, in some cases, like
/// filling with a solid color, the blending can be avoided by a plain color replacement.
/// This method can be useful for such processors to select the fast path.
/// </remarks>
public static bool IsOpaqueColorWithoutBlending(this GraphicsOptions options, Color color)
{
if (options.ColorBlendingMode != PixelColorBlendingMode.Normal)
{
return false;
}
if (options.AlphaCompositionMode != PixelAlphaCompositionMode.SrcOver
&& options.AlphaCompositionMode != PixelAlphaCompositionMode.Src)
{
return false;
}
const float Opaque = 1F;
if (options.BlendPercentage != Opaque)
{
return false;
}
if (((Vector4)color).W != Opaque)
{
return false;
}
return true;
}
}
}

32
src/ImageSharp.Drawing/ImageSharp.Drawing.csproj

@ -1,32 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<AssemblyName>SixLabors.ImageSharp.Drawing</AssemblyName>
<AssemblyTitle>SixLabors.ImageSharp.Drawing</AssemblyTitle>
<Description>An extension to ImageSharp that allows the drawing of images, paths, and text.</Description>
<PackageId>SixLabors.ImageSharp.Drawing</PackageId>
<PackageTags>Image Draw Shape Path Font</PackageTags>
<RootNamespace>SixLabors.ImageSharp</RootNamespace>
<TargetFrameworks>netcoreapp2.1;netstandard1.3;netstandard2.0</TargetFrameworks>
</PropertyGroup>
<!-- TODO: Include .NETSTANDARD2.1 when released-->
<PropertyGroup Condition=" $(TargetFramework.StartsWith('netcoreapp2')) ">
<DefineConstants>$(DefineConstants);SUPPORTS_MATHF</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition=" $(TargetFramework.StartsWith('netcoreapp2.1')) ">
<DefineConstants>$(DefineConstants);SUPPORTS_HASHCODE</DefineConstants>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="SixLabors.Fonts" />
<PackageReference Include="SixLabors.Shapes" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ImageSharp\ImageSharp.csproj" />
</ItemGroup>
</Project>

2
src/ImageSharp.Drawing/ImageSharp.Drawing.csproj.DotSettings

@ -1,2 +0,0 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=processing_005Cextensions/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>

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

@ -1,36 +0,0 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Primitives
{
/// <summary>
/// Represents a region of an image.
/// </summary>
public abstract class Region
{
/// <summary>
/// Gets the maximum number of intersections to could be returned.
/// </summary>
public abstract int MaxIntersections { get; }
/// <summary>
/// Gets the bounding box that entirely surrounds this region.
/// </summary>
/// <remarks>
/// This should always contains all possible points returned from <see cref="Scan"/>.
/// </remarks>
public abstract Rectangle Bounds { get; }
/// <summary>
/// Scans the X axis for intersections at the Y axis position.
/// </summary>
/// <param name="y">The position along the y axis to find intersections.</param>
/// <param name="buffer">The buffer.</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, Span<float> buffer, Configuration configuration);
}
}

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

@ -1,24 +0,0 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.Processing;
using SixLabors.Shapes;
namespace SixLabors.ImageSharp.Primitives
{
/// <summary>
/// A mapping between a <see cref="IPath"/> and a region.
/// </summary>
internal class ShapePath : ShapeRegion
{
/// <summary>
/// Initializes a new instance of the <see cref="ShapePath"/> class.
/// </summary>
/// <param name="shape">The shape.</param>
/// <param name="pen">The pen to apply to the shape.</param>
public ShapePath(IPath shape, IPen pen)
: base(shape.GenerateOutline(pen.StrokeWidth, pen.StrokePattern))
{
}
}
}

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

@ -1,64 +0,0 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Buffers;
using SixLabors.ImageSharp.Memory;
using SixLabors.Primitives;
using SixLabors.Shapes;
namespace SixLabors.ImageSharp.Primitives
{
/// <summary>
/// A mapping between a <see cref="IPath"/> and a region.
/// </summary>
internal class ShapeRegion : Region
{
/// <summary>
/// Initializes a new instance of the <see cref="ShapeRegion"/> class.
/// </summary>
/// <param name="shape">The shape.</param>
public ShapeRegion(IPath shape)
{
this.Shape = shape.AsClosedPath();
int left = (int)MathF.Floor(shape.Bounds.Left);
int top = (int)MathF.Floor(shape.Bounds.Top);
int right = (int)MathF.Ceiling(shape.Bounds.Right);
int bottom = (int)MathF.Ceiling(shape.Bounds.Bottom);
this.Bounds = Rectangle.FromLTRB(left, top, right, bottom);
}
/// <summary>
/// Gets the fillable shape
/// </summary>
public IPath Shape { get; }
/// <inheritdoc/>
public override int MaxIntersections => this.Shape.MaxIntersections;
/// <inheritdoc/>
public override Rectangle Bounds { get; }
/// <inheritdoc/>
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);
using (IMemoryOwner<PointF> tempBuffer = configuration.MemoryAllocator.Allocate<PointF>(buffer.Length))
{
Span<PointF> innerBuffer = tempBuffer.Memory.Span;
int count = this.Shape.FindIntersections(start, end, innerBuffer);
for (int i = 0; i < count; i++)
{
buffer[i] = innerBuffer[i].X;
}
return count;
}
}
}
}

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

@ -1,113 +0,0 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Buffers;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Memory;
namespace SixLabors.ImageSharp.Processing
{
/// <summary>
/// A primitive that converts a point into a color for discovering the fill color based on an implementation.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <seealso cref="IDisposable" />
public abstract class BrushApplicator<TPixel> : IDisposable
where TPixel : struct, IPixel<TPixel>
{
/// <summary>
/// Initializes a new instance of the <see cref="BrushApplicator{TPixel}"/> class.
/// </summary>
/// <param name="configuration">The configuration instance to use when performing operations.</param>
/// <param name="options">The graphics options.</param>
/// <param name="target">The target.</param>
internal BrushApplicator(Configuration configuration, GraphicsOptions options, ImageFrame<TPixel> target)
{
this.Configuration = configuration;
this.Target = target;
this.Options = options;
this.Blender = PixelOperations<TPixel>.Instance.GetPixelBlender(options);
}
/// <summary>
/// Gets the configuration instance to use when performing operations.
/// </summary>
protected Configuration Configuration { get; }
/// <summary>
/// Gets the pixel blender.
/// </summary>
internal PixelBlender<TPixel> Blender { get; }
/// <summary>
/// Gets the target image.
/// </summary>
protected ImageFrame<TPixel> Target { get; }
/// <summary>
/// Gets thegraphics options
/// </summary>
protected GraphicsOptions Options { get; }
/// <summary>
/// Gets the overlay pixel at the specified position.
/// </summary>
/// <param name="x">The x-coordinate.</param>
/// <param name="y">The y-coordinate.</param>
/// <returns>The <see typeparam="TPixel"/> at the specified position.</returns>
internal abstract TPixel this[int x, int y] { get; }
/// <inheritdoc/>
public void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}
/// <summary>
/// Disposes the object and frees resources for the Garbage Collector.
/// </summary>
/// <param name="disposing">Whether to dispose managed and unmanaged objects.</param>
protected virtual void Dispose(bool disposing)
{
}
/// <summary>
/// Applies the opacity weighting for each pixel in a scanline to the target based on the pattern contained in the brush.
/// </summary>
/// <param name="scanline">A collection of opacity values between 0 and 1 to be merged with the brushed color value before being applied to the target.</param>
/// <param name="x">The x-position in the target pixel space that the start of the scanline data corresponds to.</param>
/// <param name="y">The y-position in the target pixel space that whole scanline corresponds to.</param>
/// <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)
{
MemoryAllocator memoryAllocator = this.Target.MemoryAllocator;
using (IMemoryOwner<float> amountBuffer = memoryAllocator.Allocate<float>(scanline.Length))
using (IMemoryOwner<TPixel> overlay = memoryAllocator.Allocate<TPixel>(scanline.Length))
{
Span<float> amountSpan = amountBuffer.Memory.Span;
Span<TPixel> overlaySpan = overlay.Memory.Span;
for (int i = 0; i < scanline.Length; i++)
{
if (this.Options.BlendPercentage < 1)
{
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(this.Configuration, destinationRow, destinationRow, overlaySpan, amountSpan);
}
}
}
}

222
src/ImageSharp.Drawing/Processing/Brushes.cs

@ -1,222 +0,0 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
namespace SixLabors.ImageSharp.Processing
{
/// <summary>
/// A collection of methods for creating generic brushes.
/// </summary>
/// <returns>A New <see cref="PatternBrush"/></returns>
public static class Brushes
{
/// <summary>
/// Percent10 Hatch Pattern
/// </summary>
/// ---> x axis
/// ^
/// | y - axis
/// |
/// see PatternBrush for details about how to make new patterns work
private static readonly bool[,] Percent10Pattern =
{
{ true, false, false, false },
{ false, false, false, false },
{ false, false, true, false },
{ false, false, false, false }
};
/// <summary>
/// Percent20 pattern.
/// </summary>
private static readonly bool[,] Percent20Pattern =
{
{ true, false, false, false },
{ false, false, true, false },
{ true, false, false, false },
{ false, false, true, false }
};
/// <summary>
/// Horizontal Hatch Pattern
/// </summary>
private static readonly bool[,] HorizontalPattern =
{
{ false },
{ true },
{ false },
{ false }
};
/// <summary>
/// Min Pattern
/// </summary>
private static readonly bool[,] MinPattern =
{
{ false },
{ false },
{ false },
{ true }
};
/// <summary>
/// Vertical Pattern
/// </summary>
private static readonly bool[,] VerticalPattern =
{
{ false, true, false, false },
};
/// <summary>
/// Forward Diagonal Pattern
/// </summary>
private static readonly bool[,] ForwardDiagonalPattern =
{
{ false, false, false, true },
{ false, false, true, false },
{ false, true, false, false },
{ true, false, false, false }
};
/// <summary>
/// Backward Diagonal Pattern
/// </summary>
private static readonly bool[,] BackwardDiagonalPattern =
{
{ true, false, false, false },
{ false, true, false, false },
{ false, false, true, false },
{ false, false, false, true }
};
/// <summary>
/// Create as brush that will paint a solid color
/// </summary>
/// <param name="color">The color.</param>
/// <returns>A New <see cref="PatternBrush"/></returns>
public static SolidBrush Solid(Color color) => new SolidBrush(color);
/// <summary>
/// Create as brush that will paint a Percent10 Hatch Pattern with the specified colors
/// </summary>
/// <param name="foreColor">Color of the foreground.</param>
/// <returns>A New <see cref="PatternBrush"/></returns>
public static PatternBrush Percent10(Color foreColor) =>
new PatternBrush(foreColor, Color.Transparent, Percent10Pattern);
/// <summary>
/// Create as brush that will paint a Percent10 Hatch Pattern with the specified colors
/// </summary>
/// <param name="foreColor">Color of the foreground.</param>
/// <param name="backColor">Color of the background.</param>
/// <returns>A New <see cref="PatternBrush"/></returns>
public static PatternBrush Percent10(Color foreColor, Color backColor) =>
new PatternBrush(foreColor, backColor, Percent10Pattern);
/// <summary>
/// Create as brush that will paint a Percent20 Hatch Pattern with the specified foreground color and a
/// transparent background.
/// </summary>
/// <param name="foreColor">Color of the foreground.</param>
/// <returns>A New <see cref="PatternBrush"/></returns>
public static PatternBrush Percent20(Color foreColor) =>
new PatternBrush(foreColor, Color.Transparent, Percent20Pattern);
/// <summary>
/// Create as brush that will paint a Percent20 Hatch Pattern with the specified colors
/// </summary>
/// <param name="foreColor">Color of the foreground.</param>
/// <param name="backColor">Color of the background.</param>
/// <returns>A New <see cref="PatternBrush"/></returns>
public static PatternBrush Percent20(Color foreColor, Color backColor) =>
new PatternBrush(foreColor, backColor, Percent20Pattern);
/// <summary>
/// Create as brush that will paint a Horizontal Hatch Pattern with the specified foreground color and a
/// transparent background.
/// </summary>
/// <param name="foreColor">Color of the foreground.</param>
/// <returns>A New <see cref="PatternBrush"/></returns>
public static PatternBrush Horizontal(Color foreColor) =>
new PatternBrush(foreColor, Color.Transparent, HorizontalPattern);
/// <summary>
/// Create as brush that will paint a Horizontal Hatch Pattern with the specified colors
/// </summary>
/// <param name="foreColor">Color of the foreground.</param>
/// <param name="backColor">Color of the background.</param>
/// <returns>A New <see cref="PatternBrush"/></returns>
public static PatternBrush Horizontal(Color foreColor, Color backColor) =>
new PatternBrush(foreColor, backColor, HorizontalPattern);
/// <summary>
/// Create as brush that will paint a Min Hatch Pattern with the specified foreground color and a
/// transparent background.
/// </summary>
/// <param name="foreColor">Color of the foreground.</param>
/// <returns>A New <see cref="PatternBrush"/></returns>
public static PatternBrush Min(Color foreColor) => new PatternBrush(foreColor, Color.Transparent, MinPattern);
/// <summary>
/// Create as brush that will paint a Min Hatch Pattern with the specified colors
/// </summary>
/// <param name="foreColor">Color of the foreground.</param>
/// <param name="backColor">Color of the background.</param>
/// <returns>A New <see cref="PatternBrush"/></returns>
public static PatternBrush Min(Color foreColor, Color backColor) =>
new PatternBrush(foreColor, backColor, MinPattern);
/// <summary>
/// Create as brush that will paint a Vertical Hatch Pattern with the specified foreground color and a
/// transparent background.
/// </summary>
/// <param name="foreColor">Color of the foreground.</param>
/// <returns>A New <see cref="PatternBrush"/></returns>
public static PatternBrush Vertical(Color foreColor) =>
new PatternBrush(foreColor, Color.Transparent, VerticalPattern);
/// <summary>
/// Create as brush that will paint a Vertical Hatch Pattern with the specified colors
/// </summary>
/// <param name="foreColor">Color of the foreground.</param>
/// <param name="backColor">Color of the background.</param>
/// <returns>A New <see cref="PatternBrush"/></returns>
public static PatternBrush Vertical(Color foreColor, Color backColor) =>
new PatternBrush(foreColor, backColor, VerticalPattern);
/// <summary>
/// Create as brush that will paint a Forward Diagonal Hatch Pattern with the specified foreground color and a
/// transparent background.
/// </summary>
/// <param name="foreColor">Color of the foreground.</param>
/// <returns>A New <see cref="PatternBrush"/></returns>
public static PatternBrush ForwardDiagonal(Color foreColor) =>
new PatternBrush(foreColor, Color.Transparent, ForwardDiagonalPattern);
/// <summary>
/// Create as brush that will paint a Forward Diagonal Hatch Pattern with the specified colors
/// </summary>
/// <param name="foreColor">Color of the foreground.</param>
/// <param name="backColor">Color of the background.</param>
/// <returns>A New <see cref="PatternBrush"/></returns>
public static PatternBrush ForwardDiagonal(Color foreColor, Color backColor) =>
new PatternBrush(foreColor, backColor, ForwardDiagonalPattern);
/// <summary>
/// Create as brush that will paint a Backward Diagonal Hatch Pattern with the specified foreground color and a
/// transparent background.
/// </summary>
/// <param name="foreColor">Color of the foreground.</param>
/// <returns>A New <see cref="PatternBrush"/></returns>
public static PatternBrush BackwardDiagonal(Color foreColor) =>
new PatternBrush(foreColor, Color.Transparent, BackwardDiagonalPattern);
/// <summary>
/// Create as brush that will paint a Backward Diagonal Hatch Pattern with the specified colors
/// </summary>
/// <param name="foreColor">Color of the foreground.</param>
/// <param name="backColor">Color of the background.</param>
/// <returns>A New <see cref="PatternBrush"/></returns>
public static PatternBrush BackwardDiagonal(Color foreColor, Color backColor) =>
new PatternBrush(foreColor, backColor, BackwardDiagonalPattern);
}
}

35
src/ImageSharp.Drawing/Processing/ColorStop.cs

@ -1,35 +0,0 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System.Diagnostics;
namespace SixLabors.ImageSharp.Processing
{
/// <summary>
/// A struct that defines a single color stop.
/// </summary>
[DebuggerDisplay("ColorStop({Ratio} -> {Color}")]
public readonly struct ColorStop
{
/// <summary>
/// Initializes a new instance of the <see cref="ColorStop" /> 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, in Color 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 Color Color { get; }
}
}

22
src/ImageSharp.Drawing/Processing/DrawingHelpers.cs

@ -1,22 +0,0 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Primitives;
namespace SixLabors.ImageSharp.Processing
{
internal static class DrawingHelpers
{
/// <summary>
/// Convert a <see cref="DenseMatrix{Color}"/> to a <see cref="DenseMatrix{T}"/> of the given pixel type.
/// </summary>
public static DenseMatrix<TPixel> ToPixelMatrix<TPixel>(this DenseMatrix<Color> colorMatrix, Configuration configuration)
where TPixel : struct, IPixel<TPixel>
{
var result = new DenseMatrix<TPixel>(colorMatrix.Columns, colorMatrix.Rows);
Color.ToPixel(configuration, colorMatrix.Span, result.Span);
return result;
}
}
}

165
src/ImageSharp.Drawing/Processing/EllipticGradientBrush.cs

@ -1,165 +0,0 @@
// 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>
public sealed class EllipticGradientBrush : GradientBrush
{
private readonly PointF center;
private readonly PointF referenceAxisEnd;
private readonly float axisRatio;
/// <inheritdoc cref="GradientBrush" />
/// <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(
PointF center,
PointF referenceAxisEnd,
float axisRatio,
GradientRepetitionMode repetitionMode,
params ColorStop[] colorStops)
: base(repetitionMode, colorStops)
{
this.center = center;
this.referenceAxisEnd = referenceAxisEnd;
this.axisRatio = axisRatio;
}
/// <inheritdoc />
public override BrushApplicator<TPixel> CreateApplicator<TPixel>(
Configuration configuration,
GraphicsOptions options,
ImageFrame<TPixel> source,
RectangleF region) =>
new RadialGradientBrushApplicator<TPixel>(
configuration,
options,
source,
this.center,
this.referenceAxisEnd,
this.axisRatio,
this.ColorStops,
this.RepetitionMode);
/// <inheritdoc />
private sealed class RadialGradientBrushApplicator<TPixel> : GradientBrushApplicator<TPixel>
where TPixel : struct, IPixel<TPixel>
{
private readonly PointF center;
private readonly PointF 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{TPixel}" /> class.
/// </summary>
/// <param name="configuration">The configuration instance to use when performing operations.</param>
/// <param name="options">The graphics options.</param>
/// <param name="target">The target image.</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(
Configuration configuration,
GraphicsOptions options,
ImageFrame<TPixel> target,
PointF center,
PointF referenceAxisEnd,
float axisRatio,
ColorStop[] colorStops,
GradientRepetitionMode repetitionMode)
: base(configuration, options, target, 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 />
protected override float PositionOnGradient(float xt, float 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;
return (xSquared / this.referenceRadiusSquared) + (ySquared / this.secondRadiusSquared);
}
private float AngleBetween(PointF junction, PointF a, PointF b)
{
PointF vA = a - junction;
PointF vB = b - junction;
return MathF.Atan2(vB.Y, vB.X) - MathF.Atan2(vA.Y, vA.X);
}
private float DistanceBetween(
PointF p1,
PointF p2)
{
// TODO: Can we not just use Vector2 distance here?
float dX = p1.X - p2.X;
float dXsquared = dX * dX;
float dY = p1.Y - p2.Y;
float dYsquared = dY * dY;
return MathF.Sqrt(dXsquared + dYsquared);
}
}
}
}

106
src/ImageSharp.Drawing/Processing/Extensions/DrawBezierExtensions.cs

@ -1,106 +0,0 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.Primitives;
using SixLabors.Shapes;
namespace SixLabors.ImageSharp.Processing
{
/// <summary>
/// Adds extensions that allow the drawing of Bezier paths to the <see cref="Image{TPixel}"/> type.
/// </summary>
public static class DrawBezierExtensions
{
/// <summary>
/// Draws the provided points as an open Bezier path at the provided thickness with the supplied brush
/// </summary>
/// <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>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext DrawBeziers(
this IImageProcessingContext source,
GraphicsOptions options,
IBrush brush,
float thickness,
params PointF[] points) =>
source.Draw(options, new Pen(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
/// </summary>
/// <param name="source">The image this method extends.</param>
/// <param name="brush">The brush.</param>
/// <param name="thickness">The thickness.</param>
/// <param name="points">The points.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext DrawBeziers(
this IImageProcessingContext source,
IBrush brush,
float thickness,
params PointF[] points) =>
source.Draw(new Pen(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
/// </summary>
/// <param name="source">The image this method extends.</param>
/// <param name="color">The color.</param>
/// <param name="thickness">The thickness.</param>
/// <param name="points">The points.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext DrawBeziers(
this IImageProcessingContext source,
Color color,
float thickness,
params PointF[] points) =>
source.DrawBeziers(new SolidBrush(color), thickness, points);
/// <summary>
/// Draws the provided points as an open Bezier path at the provided thickness with the supplied brush
/// </summary>
/// <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>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext DrawBeziers(
this IImageProcessingContext source,
GraphicsOptions options,
Color color,
float thickness,
params PointF[] points) =>
source.DrawBeziers(options, new SolidBrush(color), thickness, points);
/// <summary>
/// Draws the provided points as an open Bezier path with the supplied pen
/// </summary>
/// <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>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext DrawBeziers(
this IImageProcessingContext source,
GraphicsOptions options,
IPen pen,
params PointF[] points) =>
source.Draw(options, pen, new Path(new CubicBezierLineSegment(points)));
/// <summary>
/// Draws the provided points as an open Bezier path with the supplied pen
/// </summary>
/// <param name="source">The image this method extends.</param>
/// <param name="pen">The pen.</param>
/// <param name="points">The points.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext DrawBeziers(
this IImageProcessingContext source,
IPen pen,
params PointF[] points) =>
source.Draw(pen, new Path(new CubicBezierLineSegment(points)));
}
}

106
src/ImageSharp.Drawing/Processing/Extensions/DrawLineExtensions.cs

@ -1,106 +0,0 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.Primitives;
using SixLabors.Shapes;
namespace SixLabors.ImageSharp.Processing
{
/// <summary>
/// Adds extensions that allow the drawing of lines to the <see cref="Image{TPixel}"/> type.
/// </summary>
public static class DrawLineExtensions
{
/// <summary>
/// Draws the provided Points as an open Linear path at the provided thickness with the supplied brush
/// </summary>
/// <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>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext DrawLines(
this IImageProcessingContext source,
GraphicsOptions options,
IBrush brush,
float thickness,
params PointF[] points) =>
source.Draw(options, new Pen(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
/// </summary>
/// <param name="source">The image this method extends.</param>
/// <param name="brush">The brush.</param>
/// <param name="thickness">The thickness.</param>
/// <param name="points">The points.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext DrawLines(
this IImageProcessingContext source,
IBrush brush,
float thickness,
params PointF[] points) =>
source.Draw(new Pen(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
/// </summary>
/// <param name="source">The image this method extends.</param>
/// <param name="color">The color.</param>
/// <param name="thickness">The thickness.</param>
/// <param name="points">The points.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext DrawLines(
this IImageProcessingContext source,
Color color,
float thickness,
params PointF[] points) =>
source.DrawLines(new SolidBrush(color), thickness, points);
/// <summary>
/// Draws the provided Points as an open Linear path at the provided thickness with the supplied brush
/// </summary>
/// <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>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>>
public static IImageProcessingContext DrawLines(
this IImageProcessingContext source,
GraphicsOptions options,
Color color,
float thickness,
params PointF[] points) =>
source.DrawLines(options, new SolidBrush(color), thickness, points);
/// <summary>
/// Draws the provided Points as an open Linear path with the supplied pen
/// </summary>
/// <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>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext DrawLines(
this IImageProcessingContext source,
GraphicsOptions options,
IPen pen,
params PointF[] points) =>
source.Draw(options, pen, new Path(new LinearLineSegment(points)));
/// <summary>
/// Draws the provided Points as an open Linear path with the supplied pen
/// </summary>
/// <param name="source">The image this method extends.</param>
/// <param name="pen">The pen.</param>
/// <param name="points">The points.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext DrawLines(
this IImageProcessingContext source,
IPen pen,
params PointF[] points) =>
source.Draw(pen, new Path(new LinearLineSegment(points)));
}
}

110
src/ImageSharp.Drawing/Processing/Extensions/DrawPathCollectionExtensions.cs

@ -1,110 +0,0 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.Shapes;
namespace SixLabors.ImageSharp.Processing
{
/// <summary>
/// Adds extensions that allow the drawing of collections of polygon outlines to the <see cref="Image{TPixel}"/> type.
/// </summary>
public static class DrawPathCollectionExtensions
{
/// <summary>
/// Draws the outline of the polygon with the provided pen.
/// </summary>
/// <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>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext Draw(
this IImageProcessingContext source,
GraphicsOptions options,
IPen pen,
IPathCollection paths)
{
foreach (IPath path in paths)
{
source.Draw(options, pen, path);
}
return source;
}
/// <summary>
/// Draws the outline of the polygon with the provided pen.
/// </summary>
/// <param name="source">The image this method extends.</param>
/// <param name="pen">The pen.</param>
/// <param name="paths">The paths.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext
Draw(this IImageProcessingContext source, IPen pen, IPathCollection paths) =>
source.Draw(new GraphicsOptions(), pen, paths);
/// <summary>
/// Draws the outline of the polygon with the provided brush at the provided thickness.
/// </summary>
/// <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>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext Draw(
this IImageProcessingContext source,
GraphicsOptions options,
IBrush brush,
float thickness,
IPathCollection paths) =>
source.Draw(options, new Pen(brush, thickness), paths);
/// <summary>
/// Draws the outline of the polygon with the provided brush at the provided thickness.
/// </summary>
/// <param name="source">The image this method extends.</param>
/// <param name="brush">The brush.</param>
/// <param name="thickness">The thickness.</param>
/// <param name="paths">The paths.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext Draw(
this IImageProcessingContext source,
IBrush brush,
float thickness,
IPathCollection paths) =>
source.Draw(new Pen(brush, thickness), paths);
/// <summary>
/// Draws the outline of the polygon with the provided brush at the provided thickness.
/// </summary>
/// <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>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext Draw(
this IImageProcessingContext source,
GraphicsOptions options,
Color color,
float thickness,
IPathCollection paths) =>
source.Draw(options, new SolidBrush(color), thickness, paths);
/// <summary>
/// Draws the outline of the polygon with the provided brush at the provided thickness.
/// </summary>
/// <param name="source">The image this method extends.</param>
/// <param name="color">The color.</param>
/// <param name="thickness">The thickness.</param>
/// <param name="paths">The paths.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext Draw(
this IImageProcessingContext source,
Color color,
float thickness,
IPathCollection paths) =>
source.Draw(new SolidBrush(color), thickness, paths);
}
}

103
src/ImageSharp.Drawing/Processing/Extensions/DrawPathExtensions.cs

@ -1,103 +0,0 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.Primitives;
using SixLabors.Shapes;
namespace SixLabors.ImageSharp.Processing
{
/// <summary>
/// Adds extensions that allow the drawing of polygon outlines to the <see cref="Image{TPixel}"/> type.
/// </summary>
public static class DrawPathExtensions
{
/// <summary>
/// Draws the outline of the polygon with the provided pen.
/// </summary>
/// <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>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext Draw(
this IImageProcessingContext source,
GraphicsOptions options,
IPen pen,
IPath path) =>
source.Fill(options, pen.StrokeFill, new ShapePath(path, pen));
/// <summary>
/// Draws the outline of the polygon with the provided pen.
/// </summary>
/// <param name="source">The image this method extends.</param>
/// <param name="pen">The pen.</param>
/// <param name="path">The path.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext Draw(this IImageProcessingContext source, IPen pen, IPath path) =>
source.Draw(new GraphicsOptions(), pen, path);
/// <summary>
/// Draws the outline of the polygon with the provided brush at the provided thickness.
/// </summary>
/// <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>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext Draw(
this IImageProcessingContext source,
GraphicsOptions options,
IBrush brush,
float thickness,
IPath path) =>
source.Draw(options, new Pen(brush, thickness), path);
/// <summary>
/// Draws the outline of the polygon with the provided brush at the provided thickness.
/// </summary>
/// <param name="source">The image this method extends.</param>
/// <param name="brush">The brush.</param>
/// <param name="thickness">The thickness.</param>
/// <param name="path">The path.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext Draw(
this IImageProcessingContext source,
IBrush brush,
float thickness,
IPath path) =>
source.Draw(new Pen(brush, thickness), path);
/// <summary>
/// Draws the outline of the polygon with the provided brush at the provided thickness.
/// </summary>
/// <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>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext Draw(
this IImageProcessingContext source,
GraphicsOptions options,
Color color,
float thickness,
IPath path) =>
source.Draw(options, new SolidBrush(color), thickness, path);
/// <summary>
/// Draws the outline of the polygon with the provided brush at the provided thickness.
/// </summary>
/// <param name="source">The image this method extends.</param>
/// <param name="color">The color.</param>
/// <param name="thickness">The thickness.</param>
/// <param name="path">The path.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext Draw(
this IImageProcessingContext source,
Color color,
float thickness,
IPath path) =>
source.Draw(new SolidBrush(color), thickness, path);
}
}

106
src/ImageSharp.Drawing/Processing/Extensions/DrawPolygonExtensions.cs

@ -1,106 +0,0 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.Primitives;
using SixLabors.Shapes;
namespace SixLabors.ImageSharp.Processing
{
/// <summary>
/// Adds extensions that allow the drawing of closed linear polygons to the <see cref="Image{TPixel}"/> type.
/// </summary>
public static class DrawPolygonExtensions
{
/// <summary>
/// Draws the provided Points as a closed Linear Polygon with the provided brush at the provided thickness.
/// </summary>
/// <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>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext DrawPolygon(
this IImageProcessingContext source,
GraphicsOptions options,
IBrush brush,
float thickness,
params PointF[] points) =>
source.Draw(options, new Pen(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.
/// </summary>
/// <param name="source">The image this method extends.</param>
/// <param name="brush">The brush.</param>
/// <param name="thickness">The thickness.</param>
/// <param name="points">The points.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext DrawPolygon(
this IImageProcessingContext source,
IBrush brush,
float thickness,
params PointF[] points) =>
source.Draw(new Pen(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.
/// </summary>
/// <param name="source">The image this method extends.</param>
/// <param name="color">The color.</param>
/// <param name="thickness">The thickness.</param>
/// <param name="points">The points.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext DrawPolygon(
this IImageProcessingContext source,
Color color,
float thickness,
params PointF[] points) =>
source.DrawPolygon(new SolidBrush(color), thickness, points);
/// <summary>
/// Draws the provided Points as a closed Linear Polygon with the provided brush at the provided thickness.
/// </summary>
/// <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>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext DrawPolygon(
this IImageProcessingContext source,
GraphicsOptions options,
Color color,
float thickness,
params PointF[] points) =>
source.DrawPolygon(options, new SolidBrush(color), thickness, points);
/// <summary>
/// Draws the provided Points as a closed Linear Polygon with the provided Pen.
/// </summary>
/// <param name="source">The image this method extends.</param>
/// <param name="pen">The pen.</param>
/// <param name="points">The points.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext DrawPolygon(
this IImageProcessingContext source,
IPen pen,
params PointF[] points) =>
source.Draw(new GraphicsOptions(), pen, new Polygon(new LinearLineSegment(points)));
/// <summary>
/// Draws the provided Points as a closed Linear Polygon with the provided Pen.
/// </summary>
/// <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>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext DrawPolygon(
this IImageProcessingContext source,
GraphicsOptions options,
IPen pen,
params PointF[] points) =>
source.Draw(options, pen, new Polygon(new LinearLineSegment(points)));
}
}

103
src/ImageSharp.Drawing/Processing/Extensions/DrawRectangleExtensions.cs

@ -1,103 +0,0 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.Primitives;
using SixLabors.Shapes;
namespace SixLabors.ImageSharp.Processing
{
/// <summary>
/// Adds extensions that allow the drawing of rectangles to the <see cref="Image{TPixel}"/> type.
/// </summary>
public static class DrawRectangleExtensions
{
/// <summary>
/// Draws the outline of the rectangle with the provided pen.
/// </summary>
/// <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>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext Draw(
this IImageProcessingContext source,
GraphicsOptions options,
IPen pen,
RectangleF shape) =>
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.
/// </summary>
/// <param name="source">The image this method extends.</param>
/// <param name="pen">The pen.</param>
/// <param name="shape">The shape.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext Draw(this IImageProcessingContext source, IPen pen, RectangleF shape) =>
source.Draw(new GraphicsOptions(), pen, shape);
/// <summary>
/// Draws the outline of the rectangle with the provided brush at the provided thickness.
/// </summary>
/// <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>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext Draw(
this IImageProcessingContext source,
GraphicsOptions options,
IBrush brush,
float thickness,
RectangleF shape) =>
source.Draw(options, new Pen(brush, thickness), shape);
/// <summary>
/// Draws the outline of the rectangle with the provided brush at the provided thickness.
/// </summary>
/// <param name="source">The image this method extends.</param>
/// <param name="brush">The brush.</param>
/// <param name="thickness">The thickness.</param>
/// <param name="shape">The shape.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext Draw(
this IImageProcessingContext source,
IBrush brush,
float thickness,
RectangleF shape) =>
source.Draw(new Pen(brush, thickness), shape);
/// <summary>
/// Draws the outline of the rectangle with the provided brush at the provided thickness.
/// </summary>
/// <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>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext Draw(
this IImageProcessingContext source,
GraphicsOptions options,
Color color,
float thickness,
RectangleF shape) =>
source.Draw(options, new SolidBrush(color), thickness, shape);
/// <summary>
/// Draws the outline of the rectangle with the provided brush at the provided thickness.
/// </summary>
/// <param name="source">The image this method extends.</param>
/// <param name="color">The color.</param>
/// <param name="thickness">The thickness.</param>
/// <param name="shape">The shape.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext Draw(
this IImageProcessingContext source,
Color color,
float thickness,
RectangleF shape) =>
source.Draw(new SolidBrush(color), thickness, shape);
}
}

179
src/ImageSharp.Drawing/Processing/Extensions/DrawTextExtensions.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.Processing.Processors.Text;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing
{
/// <summary>
/// Adds extensions that allow the drawing of text to the <see cref="Image{TPixel}"/> type.
/// </summary>
public static class DrawTextExtensions
{
/// <summary>
/// Draws the text onto the the image filled via the brush.
/// </summary>
/// <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="location">The location.</param>
/// <returns>
/// The <see cref="Image{TPixel}" />.
/// </returns>
public static IImageProcessingContext DrawText(
this IImageProcessingContext source,
string text,
Font font,
Color color,
PointF location) =>
source.DrawText(new TextGraphicsOptions(), text, font, color, location);
/// <summary>
/// Draws the text onto the the image filled via the brush.
/// </summary>
/// <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>
/// <returns>
/// The <see cref="Image{TPixel}" />.
/// </returns>
public static IImageProcessingContext DrawText(
this IImageProcessingContext source,
TextGraphicsOptions options,
string text,
Font font,
Color color,
PointF location) =>
source.DrawText(options, text, font, Brushes.Solid(color), null, location);
/// <summary>
/// Draws the text onto the the image filled via the brush.
/// </summary>
/// <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="location">The location.</param>
/// <returns>
/// The <see cref="Image{TPixel}" />.
/// </returns>
public static IImageProcessingContext DrawText(
this IImageProcessingContext source,
string text,
Font font,
IBrush brush,
PointF location) =>
source.DrawText(new TextGraphicsOptions(), text, font, brush, location);
/// <summary>
/// Draws the text onto the the image filled via the brush.
/// </summary>
/// <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>
/// <returns>
/// The <see cref="Image{TPixel}" />.
/// </returns>
public static IImageProcessingContext DrawText(
this IImageProcessingContext source,
TextGraphicsOptions options,
string text,
Font font,
IBrush brush,
PointF location) =>
source.DrawText(options, text, font, brush, null, location);
/// <summary>
/// Draws the text onto the the image outlined via the pen.
/// </summary>
/// <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="location">The location.</param>
/// <returns>
/// The <see cref="Image{TPixel}" />.
/// </returns>
public static IImageProcessingContext DrawText(
this IImageProcessingContext source,
string text,
Font font,
IPen pen,
PointF location) =>
source.DrawText(new TextGraphicsOptions(), text, font, pen, location);
/// <summary>
/// Draws the text onto the the image outlined via the pen.
/// </summary>
/// <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>
/// <returns>
/// The <see cref="Image{TPixel}" />.
/// </returns>
public static IImageProcessingContext DrawText(
this IImageProcessingContext source,
TextGraphicsOptions options,
string text,
Font font,
IPen pen,
PointF location) =>
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.
/// </summary>
/// <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="location">The location.</param>
/// <returns>
/// The <see cref="Image{TPixel}" />.
/// </returns>
public static IImageProcessingContext DrawText(
this IImageProcessingContext source,
string text,
Font font,
IBrush brush,
IPen pen,
PointF location) =>
source.DrawText(new TextGraphicsOptions(), 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>
/// <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>
/// <returns>
/// The <see cref="Image{TPixel}" />.
/// </returns>
public static IImageProcessingContext DrawText(
this IImageProcessingContext source,
TextGraphicsOptions options,
string text,
Font font,
IBrush brush,
IPen pen,
PointF location) =>
source.ApplyProcessor(new DrawTextProcessor(options, text, font, brush, pen, location));
}
}

76
src/ImageSharp.Drawing/Processing/Extensions/FillPathBuilderExtensions.cs

@ -1,76 +0,0 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using SixLabors.Shapes;
namespace SixLabors.ImageSharp.Processing
{
/// <summary>
/// Adds extensions that allow the filling of polygons with various brushes to the <see cref="Image{TPixel}"/> type.
/// </summary>
public static class FillPathBuilderExtensions
{
/// <summary>
/// Flood fills the image in the shape of the provided polygon with the specified brush.
/// </summary>
/// <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>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext Fill(
this IImageProcessingContext source,
GraphicsOptions options,
IBrush brush,
Action<PathBuilder> path)
{
var pb = new PathBuilder();
path(pb);
return source.Fill(options, brush, pb.Build());
}
/// <summary>
/// Flood fills the image in the shape of the provided polygon with the specified brush.
/// </summary>
/// <param name="source">The image this method extends.</param>
/// <param name="brush">The brush.</param>
/// <param name="path">The path.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext Fill(
this IImageProcessingContext source,
IBrush brush,
Action<PathBuilder> path) =>
source.Fill(new GraphicsOptions(), brush, path);
/// <summary>
/// Flood fills the image in the shape of the provided polygon with the specified brush.
/// </summary>
/// <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>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext Fill(
this IImageProcessingContext source,
GraphicsOptions options,
Color color,
Action<PathBuilder> path) =>
source.Fill(options, new SolidBrush(color), path);
/// <summary>
/// Flood fills the image in the shape of the provided polygon with the specified brush.
/// </summary>
/// <param name="source">The image this method extends.</param>
/// <param name="color">The color.</param>
/// <param name="path">The path.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext Fill(
this IImageProcessingContext source,
Color color,
Action<PathBuilder> path) =>
source.Fill(new SolidBrush(color), path);
}
}

76
src/ImageSharp.Drawing/Processing/Extensions/FillPathCollectionExtensions.cs

@ -1,76 +0,0 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.Shapes;
namespace SixLabors.ImageSharp.Processing
{
/// <summary>
/// Adds extensions that allow the filling of collections of polygon outlines to the <see cref="Image{TPixel}"/> type.
/// </summary>
public static class FillPathCollectionExtensions
{
/// <summary>
/// Flood fills the image in the shape of the provided polygon with the specified brush.
/// </summary>
/// <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>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext Fill(
this IImageProcessingContext source,
GraphicsOptions options,
IBrush brush,
IPathCollection paths)
{
foreach (IPath s in paths)
{
source.Fill(options, brush, s);
}
return source;
}
/// <summary>
/// Flood fills the image in the shape of the provided polygon with the specified brush.
/// </summary>
/// <param name="source">The image this method extends.</param>
/// <param name="brush">The brush.</param>
/// <param name="paths">The paths.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext Fill(
this IImageProcessingContext source,
IBrush brush,
IPathCollection paths) =>
source.Fill(new GraphicsOptions(), brush, paths);
/// <summary>
/// Flood fills the image in the shape of the provided polygon with the specified brush.
/// </summary>
/// <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>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext Fill(
this IImageProcessingContext source,
GraphicsOptions options,
Color color,
IPathCollection paths) =>
source.Fill(options, new SolidBrush(color), paths);
/// <summary>
/// Flood fills the image in the shape of the provided polygon with the specified brush.
/// </summary>
/// <param name="source">The image this method extends.</param>
/// <param name="color">The color.</param>
/// <param name="paths">The paths.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext Fill(
this IImageProcessingContext source,
Color color,
IPathCollection paths) =>
source.Fill(new SolidBrush(color), paths);
}
}

64
src/ImageSharp.Drawing/Processing/Extensions/FillPathExtensions.cs

@ -1,64 +0,0 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.Primitives;
using SixLabors.Shapes;
namespace SixLabors.ImageSharp.Processing
{
/// <summary>
/// Adds extensions that allow the filling of polygon outlines to the <see cref="Image{TPixel}"/> type.
/// </summary>
public static class FillPathExtensions
{
/// <summary>
/// Flood fills the image in the shape of the provided polygon with the specified brush.
/// </summary>
/// <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>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext Fill(
this IImageProcessingContext source,
GraphicsOptions options,
IBrush brush,
IPath path) =>
source.Fill(options, brush, new ShapeRegion(path));
/// <summary>
/// Flood fills the image in the shape of the provided polygon with the specified brush.
/// </summary>
/// <param name="source">The image this method extends.</param>
/// <param name="brush">The brush.</param>
/// <param name="path">The path.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext Fill(this IImageProcessingContext source, IBrush brush, IPath path) =>
source.Fill(new GraphicsOptions(), brush, new ShapeRegion(path));
/// <summary>
/// Flood fills the image in the shape of the provided polygon with the specified brush..
/// </summary>
/// <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>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext Fill(
this IImageProcessingContext source,
GraphicsOptions options,
Color color,
IPath path) =>
source.Fill(options, new SolidBrush(color), path);
/// <summary>
/// Flood fills the image in the shape of the provided polygon with the specified brush..
/// </summary>
/// <param name="source">The image this method extends.</param>
/// <param name="color">The color.</param>
/// <param name="path">The path.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext Fill(this IImageProcessingContext source, Color color, IPath path) =>
source.Fill(new SolidBrush(color), path);
}
}

70
src/ImageSharp.Drawing/Processing/Extensions/FillPolygonExtensions.cs

@ -1,70 +0,0 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.Primitives;
using SixLabors.Shapes;
namespace SixLabors.ImageSharp.Processing
{
/// <summary>
/// Adds extensions that allow the filling of closed linear polygons to the <see cref="Image{TPixel}"/> type.
/// </summary>
public static class FillPolygonExtensions
{
/// <summary>
/// Flood fills the image in the shape of a Linear polygon described by the points
/// </summary>
/// <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>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext FillPolygon(
this IImageProcessingContext source,
GraphicsOptions options,
IBrush brush,
params PointF[] points) =>
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
/// </summary>
/// <param name="source">The image this method extends.</param>
/// <param name="brush">The brush.</param>
/// <param name="points">The points.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext FillPolygon(
this IImageProcessingContext source,
IBrush brush,
params PointF[] points) =>
source.Fill(brush, new Polygon(new LinearLineSegment(points)));
/// <summary>
/// Flood fills the image in the shape of a Linear polygon described by the points
/// </summary>
/// <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>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext FillPolygon(
this IImageProcessingContext source,
GraphicsOptions options,
Color color,
params PointF[] points) =>
source.Fill(options, new SolidBrush(color), new Polygon(new LinearLineSegment(points)));
/// <summary>
/// Flood fills the image in the shape of a Linear polygon described by the points
/// </summary>
/// <param name="source">The image this method extends.</param>
/// <param name="color">The color.</param>
/// <param name="points">The points.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext FillPolygon(
this IImageProcessingContext source,
Color color,
params PointF[] points) =>
source.Fill(new SolidBrush(color), new Polygon(new LinearLineSegment(points)));
}
}

66
src/ImageSharp.Drawing/Processing/Extensions/FillRectangleExtensions.cs

@ -1,66 +0,0 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.Primitives;
using SixLabors.Shapes;
namespace SixLabors.ImageSharp.Processing
{
/// <summary>
/// Adds extensions that allow the filling of rectangles to the <see cref="Image{TPixel}"/> type.
/// </summary>
public static class FillRectangleExtensions
{
/// <summary>
/// Flood fills the image in the shape of the provided rectangle with the specified brush.
/// </summary>
/// <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>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext Fill(
this IImageProcessingContext source,
GraphicsOptions options,
IBrush brush,
RectangleF shape) =>
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.
/// </summary>
/// <param name="source">The image this method extends.</param>
/// <param name="brush">The brush.</param>
/// <param name="shape">The shape.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext
Fill(this IImageProcessingContext source, IBrush brush, RectangleF shape) =>
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>
/// <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>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext Fill(
this IImageProcessingContext source,
GraphicsOptions options,
Color color,
RectangleF shape) =>
source.Fill(options, new SolidBrush(color), shape);
/// <summary>
/// Flood fills the image in the shape of the provided rectangle with the specified brush.
/// </summary>
/// <param name="source">The image this method extends.</param>
/// <param name="color">The color.</param>
/// <param name="shape">The shape.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext
Fill(this IImageProcessingContext source, Color color, RectangleF shape) =>
source.Fill(new SolidBrush(color), shape);
}
}

95
src/ImageSharp.Drawing/Processing/Extensions/FillRegionExtensions.cs

@ -1,95 +0,0 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.Primitives;
using SixLabors.ImageSharp.Processing.Processors.Drawing;
namespace SixLabors.ImageSharp.Processing
{
/// <summary>
/// Adds extensions that allow the filling of regions with various brushes to the <see cref="Image{TPixel}"/> type.
/// </summary>
public static class FillRegionExtensions
{
/// <summary>
/// Flood fills the image with the specified brush.
/// </summary>
/// <param name="source">The image this method extends.</param>
/// <param name="brush">The details how to fill the region of interest.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext Fill(this IImageProcessingContext source, IBrush brush) =>
source.Fill(new GraphicsOptions(), brush);
/// <summary>
/// Flood fills the image with the specified color.
/// </summary>
/// <param name="source">The image this method extends.</param>
/// <param name="color">The color.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext Fill(this IImageProcessingContext source, Color color) =>
source.Fill(new SolidBrush(color));
/// <summary>
/// Flood fills the image with in the region with the specified brush.
/// </summary>
/// <param name="source">The image this method extends.</param>
/// <param name="brush">The brush.</param>
/// <param name="region">The region.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext Fill(this IImageProcessingContext source, IBrush brush, Region region) =>
source.Fill(new GraphicsOptions(), brush, region);
/// <summary>
/// Flood fills the image with in the region with the specified color.
/// </summary>
/// <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>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext Fill(
this IImageProcessingContext source,
GraphicsOptions options,
Color color,
Region region) =>
source.Fill(options, new SolidBrush(color), region);
/// <summary>
/// Flood fills the image with in the region with the specified color.
/// </summary>
/// <param name="source">The image this method extends.</param>
/// <param name="color">The color.</param>
/// <param name="region">The region.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext Fill(this IImageProcessingContext source, Color color, Region region) =>
source.Fill(new SolidBrush(color), region);
/// <summary>
/// Flood fills the image with in the region with the specified brush.
/// </summary>
/// <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>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext Fill(
this IImageProcessingContext source,
GraphicsOptions options,
IBrush brush,
Region region) =>
source.ApplyProcessor(new FillRegionProcessor(options, brush, region));
/// <summary>
/// Flood fills the image with the specified brush.
/// </summary>
/// <param name="source">The image this method extends.</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 Fill(
this IImageProcessingContext source,
GraphicsOptions options,
IBrush brush) =>
source.ApplyProcessor(new FillProcessor(options, brush));
}
}

164
src/ImageSharp.Drawing/Processing/GradientBrush.cs

@ -1,164 +0,0 @@
// 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.Primitives;
namespace SixLabors.ImageSharp.Processing
{
/// <summary>
/// Base class for Gradient brushes
/// </summary>
public abstract class GradientBrush : IBrush
{
/// <inheritdoc cref="IBrush"/>
/// <param name="repetitionMode">Defines how the colors are repeated beyond the interval [0..1]</param>
/// <param name="colorStops">The gradient colors.</param>
protected GradientBrush(
GradientRepetitionMode repetitionMode,
params ColorStop[] 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[] ColorStops { get; }
/// <inheritdoc />
public abstract BrushApplicator<TPixel> CreateApplicator<TPixel>(
Configuration configuration,
GraphicsOptions options,
ImageFrame<TPixel> source,
RectangleF region)
where TPixel : struct, IPixel<TPixel>;
/// <summary>
/// Base class for gradient brush applicators
/// </summary>
internal abstract class GradientBrushApplicator<TPixel> : BrushApplicator<TPixel>
where TPixel : struct, IPixel<TPixel>
{
private static readonly TPixel Transparent = Color.Transparent.ToPixel<TPixel>();
private readonly ColorStop[] colorStops;
private readonly GradientRepetitionMode repetitionMode;
/// <summary>
/// Initializes a new instance of the <see cref="GradientBrushApplicator{TPixel}"/> class.
/// </summary>
/// <param name="configuration">The configuration instance to use when performing operations.</param>
/// <param name="options">The graphics options.</param>
/// <param name="target">The target image.</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 GradientBrushApplicator(
Configuration configuration,
GraphicsOptions options,
ImageFrame<TPixel> target,
ColorStop[] colorStops,
GradientRepetitionMode repetitionMode)
: base(configuration, options, target)
{
this.colorStops = colorStops; // TODO: requires colorStops to be sorted by position - should that be checked?
this.repetitionMode = repetitionMode;
}
/// <inheritdoc/>
internal override TPixel this[int x, int y]
{
get
{
float positionOnCompleteGradient = this.PositionOnGradient(x + 0.5f, y + 0.5f);
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 %= 1;
break;
case GradientRepetitionMode.Reflect:
positionOnCompleteGradient %= 2;
if (positionOnCompleteGradient > 1)
{
positionOnCompleteGradient = 2 - positionOnCompleteGradient;
}
break;
case GradientRepetitionMode.DontFill:
if (positionOnCompleteGradient > 1 || positionOnCompleteGradient < 0)
{
return Transparent;
}
break;
default:
throw new ArgumentOutOfRangeException();
}
(ColorStop from, ColorStop to) = this.GetGradientSegment(positionOnCompleteGradient);
if (from.Color.Equals(to.Color))
{
return from.Color.ToPixel<TPixel>();
}
else
{
float onLocalGradient = (positionOnCompleteGradient - from.Ratio) / (to.Ratio - from.Ratio);
return new Color(Vector4.Lerp((Vector4)from.Color, (Vector4)to.Color, onLocalGradient)).ToPixel<TPixel>();
}
}
}
/// <summary>
/// calculates the position on the gradient for a given point.
/// This method is abstract as it's content depends on the shape of the gradient.
/// </summary>
/// <param name="x">The x-coordinate of the point.</param>
/// <param name="y">The y-coordinate of the point.</param>
/// <returns>
/// The position the given point has on the gradient.
/// The position is not bound to the [0..1] interval.
/// Values outside of that interval may be treated differently,
/// e.g. for the <see cref="GradientRepetitionMode" /> enum.
/// </returns>
protected abstract float PositionOnGradient(float x, float y);
private (ColorStop from, ColorStop to) GetGradientSegment(
float positionOnCompleteGradient)
{
ColorStop localGradientFrom = this.colorStops[0];
ColorStop localGradientTo = default;
// TODO: ensure colorStops has at least 2 items (technically 1 would be okay, but that's no gradient)
foreach (ColorStop 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

@ -1,37 +0,0 @@
// 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"/>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" /> this is beyond the orthogonal through start and end,
/// TODO For the cref="PolygonalGradientBrush" it's outside the polygon,
/// For <see cref="RadialGradientBrush" /> and <see cref="EllipticGradientBrush" /> it's beyond 1.0.
/// </summary>
DontFill
}
}

40
src/ImageSharp.Drawing/Processing/IBrush.cs

@ -1,40 +0,0 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing
{
/// <summary>
/// Brush represents a logical configuration of a brush which can be used to source pixel colors
/// </summary>
/// <remarks>
/// A brush is a simple class that will return an <see cref="BrushApplicator{TPixel}" /> that will perform the
/// logic for retrieving pixel values for specific locations.
/// </remarks>
public interface IBrush
{
/// <summary>
/// Creates the applicator for this brush.
/// </summary>
/// <typeparam name="TPixel">The pixel type.</typeparam>
/// <param name="configuration">The configuration instance to use when performing operations.</param>
/// <param name="options">The graphic options.</param>
/// <param name="source">The source image.</param>
/// <param name="region">The region the brush will be applied to.</param>
/// <returns>
/// The <see cref="BrushApplicator{TPixel}"/> for this brush.
/// </returns>
/// <remarks>
/// The <paramref name="region" /> when being applied to things like shapes would usually be the
/// bounding box of the shape not necessarily the bounds of the whole image.
/// </remarks>
BrushApplicator<TPixel> CreateApplicator<TPixel>(
Configuration configuration,
GraphicsOptions options,
ImageFrame<TPixel> source,
RectangleF region)
where TPixel : struct, IPixel<TPixel>;
}
}

28
src/ImageSharp.Drawing/Processing/IPen.cs

@ -1,28 +0,0 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
namespace SixLabors.ImageSharp.Processing
{
/// <summary>
/// Interface representing the pattern and size of the stroke to apply with a Pen.
/// </summary>
public interface IPen
{
/// <summary>
/// Gets the stroke fill.
/// </summary>
IBrush StrokeFill { get; }
/// <summary>
/// Gets the width to apply to the stroke
/// </summary>
float StrokeWidth { get; }
/// <summary>
/// Gets the stoke pattern.
/// </summary>
ReadOnlySpan<float> StrokePattern { get; }
}
}

173
src/ImageSharp.Drawing/Processing/ImageBrush.cs

@ -1,173 +0,0 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Buffers;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing
{
/// <summary>
/// Provides an implementation of an image brush for painting images within areas.
/// </summary>
public class ImageBrush : IBrush
{
/// <summary>
/// The image to paint.
/// </summary>
private readonly Image image;
/// <summary>
/// Initializes a new instance of the <see cref="ImageBrush"/> class.
/// </summary>
/// <param name="image">The image.</param>
public ImageBrush(Image image)
{
this.image = image;
}
/// <inheritdoc />
public BrushApplicator<TPixel> CreateApplicator<TPixel>(
Configuration configuration,
GraphicsOptions options,
ImageFrame<TPixel> source,
RectangleF region)
where TPixel : struct, IPixel<TPixel>
{
if (this.image is Image<TPixel> specificImage)
{
return new ImageBrushApplicator<TPixel>(configuration, options, source, specificImage, region, false);
}
specificImage = this.image.CloneAs<TPixel>();
return new ImageBrushApplicator<TPixel>(configuration, options, source, specificImage, region, true);
}
/// <summary>
/// The image brush applicator.
/// </summary>
private class ImageBrushApplicator<TPixel> : BrushApplicator<TPixel>
where TPixel : struct, IPixel<TPixel>
{
private ImageFrame<TPixel> sourceFrame;
private Image<TPixel> sourceImage;
private readonly bool shouldDisposeImage;
/// <summary>
/// The y-length.
/// </summary>
private readonly int yLength;
/// <summary>
/// The x-length.
/// </summary>
private readonly int xLength;
/// <summary>
/// The Y offset.
/// </summary>
private readonly int offsetY;
/// <summary>
/// The X offset.
/// </summary>
private readonly int offsetX;
private bool isDisposed;
/// <summary>
/// Initializes a new instance of the <see cref="ImageBrushApplicator{TPixel}"/> class.
/// </summary>
/// <param name="configuration">The configuration instance to use when performing operations.</param>
/// <param name="options">The graphics options.</param>
/// <param name="target">The target image.</param>
/// <param name="image">The image.</param>
/// <param name="region">The region.</param>
/// <param name="shouldDisposeImage">Whether to dispose the image on disposal of the applicator.</param>
public ImageBrushApplicator(
Configuration configuration,
GraphicsOptions options,
ImageFrame<TPixel> target,
Image<TPixel> image,
RectangleF region,
bool shouldDisposeImage)
: base(configuration, options, target)
{
this.sourceImage = image;
this.sourceFrame = image.Frames.RootFrame;
this.shouldDisposeImage = shouldDisposeImage;
this.xLength = image.Width;
this.yLength = image.Height;
this.offsetY = (int)MathF.Max(MathF.Floor(region.Top), 0);
this.offsetX = (int)MathF.Max(MathF.Floor(region.Left), 0);
}
/// <inheritdoc/>
internal override TPixel this[int x, int y]
{
get
{
int srcX = (x - this.offsetX) % this.xLength;
int srcY = (y - this.offsetY) % this.yLength;
return this.sourceFrame[srcX, srcY];
}
}
/// <inheritdoc />
protected override void Dispose(bool disposing)
{
if (this.isDisposed)
{
return;
}
if (disposing && this.shouldDisposeImage)
{
this.sourceImage?.Dispose();
}
this.sourceImage = null;
this.sourceFrame = null;
this.isDisposed = true;
}
/// <inheritdoc />
internal override void Apply(Span<float> scanline, int x, int y)
{
// Create a span for colors
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.Memory.Span;
Span<TPixel> overlaySpan = overlay.Memory.Span;
int sourceY = (y - this.offsetY) % this.yLength;
int offsetX = x - this.offsetX;
Span<TPixel> sourceRow = this.sourceFrame.GetPixelRowSpan(sourceY);
for (int i = 0; i < scanline.Length; i++)
{
amountSpan[i] = scanline[i] * this.Options.BlendPercentage;
int sourceX = (i + offsetX) % this.xLength;
overlaySpan[i] = sourceRow[sourceX];
}
Span<TPixel> destinationRow = this.Target.GetPixelRowSpan(y).Slice(x, scanline.Length);
this.Blender.Blend(
this.Configuration,
destinationRow,
destinationRow,
overlaySpan,
amountSpan);
}
}
}
}
}

160
src/ImageSharp.Drawing/Processing/LinearGradientBrush.cs

@ -1,160 +0,0 @@
// 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>
public sealed class LinearGradientBrush : GradientBrush
{
private readonly PointF p1;
private readonly PointF p2;
/// <summary>
/// Initializes a new instance of the <see cref="LinearGradientBrush"/> 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(
PointF p1,
PointF p2,
GradientRepetitionMode repetitionMode,
params ColorStop[] colorStops)
: base(repetitionMode, colorStops)
{
this.p1 = p1;
this.p2 = p2;
}
/// <inheritdoc />
public override BrushApplicator<TPixel> CreateApplicator<TPixel>(
Configuration configuration,
GraphicsOptions options,
ImageFrame<TPixel> source,
RectangleF region) =>
new LinearGradientBrushApplicator<TPixel>(
configuration,
options,
source,
this.p1,
this.p2,
this.ColorStops,
this.RepetitionMode);
/// <summary>
/// The linear gradient brush applicator.
/// </summary>
private sealed class LinearGradientBrushApplicator<TPixel> : GradientBrushApplicator<TPixel>
where TPixel : struct, IPixel<TPixel>
{
private readonly PointF start;
private readonly PointF 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{TPixel}" /> class.
/// </summary>
/// <param name="configuration">The configuration instance to use when performing operations.</param>
/// <param name="options">The graphics options.</param>
/// <param name="source">The source image.</param>
/// <param name="start">The start point of the gradient.</param>
/// <param name="end">The end point of the gradient.</param>
/// <param name="colorStops">A 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>
public LinearGradientBrushApplicator(
Configuration configuration,
GraphicsOptions options,
ImageFrame<TPixel> source,
PointF start,
PointF end,
ColorStop[] colorStops,
GradientRepetitionMode repetitionMode)
: base(configuration, options, source, 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 = MathF.Sqrt(this.alongsSquared);
}
protected override float PositionOnGradient(float x, float y)
{
if (this.acrossX == 0)
{
return (x - this.start.X) / (this.end.X - this.start.X);
}
else if (this.acrossY == 0)
{
return (y - this.start.Y) / (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 = MathF.Sqrt(MathF.Pow(x4 - this.start.X, 2) + MathF.Pow(y4 - this.start.Y, 2));
// get and return ratio
return distance / this.length;
}
}
}
}
}

285
src/ImageSharp.Drawing/Processing/PathGradientBrush.cs

@ -1,285 +0,0 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Primitives;
using SixLabors.Shapes;
namespace SixLabors.ImageSharp.Processing
{
/// <summary>
/// Provides an implementation of a brush for painting gradients between multiple color positions in 2D coordinates.
/// It works similarly with the class in System.Drawing.Drawing2D of the same name.
/// </summary>
public sealed class PathGradientBrush : IBrush
{
private readonly IList<Edge> edges;
private readonly Color centerColor;
/// <summary>
/// Initializes a new instance of the <see cref="PathGradientBrush"/> class.
/// </summary>
/// <param name="points">Points that constitute a polygon that represents the gradient area.</param>
/// <param name="colors">Array of colors that correspond to each point in the polygon.</param>
/// <param name="centerColor">Color at the center of the gradient area to which the other colors converge.</param>
public PathGradientBrush(PointF[] points, Color[] colors, Color centerColor)
{
if (points == null)
{
throw new ArgumentNullException(nameof(points));
}
if (points.Length < 3)
{
throw new ArgumentOutOfRangeException(
nameof(points),
"There must be at least 3 lines to construct a path gradient brush.");
}
if (colors == null)
{
throw new ArgumentNullException(nameof(colors));
}
if (!colors.Any())
{
throw new ArgumentOutOfRangeException(
nameof(colors),
"One or more color is needed to construct a path gradient brush.");
}
int size = points.Length;
var lines = new ILineSegment[size];
for (int i = 0; i < size; i++)
{
lines[i] = new LinearLineSegment(points[i % size], points[(i + 1) % size]);
}
this.centerColor = centerColor;
Color ColorAt(int index) => colors[index % colors.Length];
this.edges = lines.Select(s => new Path(s))
.Select((path, i) => new Edge(path, ColorAt(i), ColorAt(i + 1))).ToList();
}
/// <summary>
/// Initializes a new instance of the <see cref="PathGradientBrush"/> class.
/// </summary>
/// <param name="points">Points that constitute a polygon that represents the gradient area.</param>
/// <param name="colors">Array of colors that correspond to each point in the polygon.</param>
public PathGradientBrush(PointF[] points, Color[] colors)
: this(points, colors, CalculateCenterColor(colors))
{
}
/// <inheritdoc />
public BrushApplicator<TPixel> CreateApplicator<TPixel>(
Configuration configuration,
GraphicsOptions options,
ImageFrame<TPixel> source,
RectangleF region)
where TPixel : struct, IPixel<TPixel>
{
return new PathGradientBrushApplicator<TPixel>(configuration, options, source, this.edges, this.centerColor);
}
private static Color CalculateCenterColor(Color[] colors)
{
if (colors == null)
{
throw new ArgumentNullException(nameof(colors));
}
if (!colors.Any())
{
throw new ArgumentOutOfRangeException(
nameof(colors),
"One or more color is needed to construct a path gradient brush.");
}
return new Color(colors.Select(c => (Vector4)c).Aggregate((p1, p2) => p1 + p2) / colors.Length);
}
private static float DistanceBetween(PointF p1, PointF p2) => ((Vector2)(p2 - p1)).Length();
private struct Intersection
{
public Intersection(PointF point, float distance)
{
this.Point = point;
this.Distance = distance;
}
public PointF Point { get; }
public float Distance { get; }
}
/// <summary>
/// An edge of the polygon that represents the gradient area.
/// </summary>
private class Edge
{
private readonly Path path;
private readonly float length;
private readonly PointF[] buffer;
public Edge(Path path, Color startColor, Color endColor)
{
this.path = path;
Vector2[] points = path.LineSegments.SelectMany(s => s.Flatten()).Select(p => (Vector2)p).ToArray();
this.Start = points.First();
this.StartColor = (Vector4)startColor;
this.End = points.Last();
this.EndColor = (Vector4)endColor;
this.length = DistanceBetween(this.End, this.Start);
this.buffer = new PointF[this.path.MaxIntersections];
}
public PointF Start { get; }
public Vector4 StartColor { get; }
public PointF End { get; }
public Vector4 EndColor { get; }
public Intersection? FindIntersection(PointF start, PointF end)
{
int intersections = this.path.FindIntersections(start, end, this.buffer);
if (intersections == 0)
{
return null;
}
return this.buffer.Take(intersections)
.Select(p => new Intersection(point: p, distance: ((Vector2)(p - start)).LengthSquared()))
.Aggregate((min, current) => min.Distance > current.Distance ? current : min);
}
public Vector4 ColorAt(float distance)
{
float ratio = this.length > 0 ? distance / this.length : 0;
return Vector4.Lerp(this.StartColor, this.EndColor, ratio);
}
public Vector4 ColorAt(PointF point) => this.ColorAt(DistanceBetween(point, this.Start));
}
/// <summary>
/// The path gradient brush applicator.
/// </summary>
private class PathGradientBrushApplicator<TPixel> : BrushApplicator<TPixel>
where TPixel : struct, IPixel<TPixel>
{
private readonly PointF center;
private readonly Vector4 centerColor;
private readonly float maxDistance;
private readonly IList<Edge> edges;
/// <summary>
/// Initializes a new instance of the <see cref="PathGradientBrushApplicator{TPixel}"/> class.
/// </summary>
/// <param name="configuration">The configuration instance to use when performing operations.</param>
/// <param name="options">The graphics options.</param>
/// <param name="source">The source image.</param>
/// <param name="edges">Edges of the polygon.</param>
/// <param name="centerColor">Color at the center of the gradient area to which the other colors converge.</param>
public PathGradientBrushApplicator(
Configuration configuration,
GraphicsOptions options,
ImageFrame<TPixel> source,
IList<Edge> edges,
Color centerColor)
: base(configuration, options, source)
{
this.edges = edges;
PointF[] points = edges.Select(s => s.Start).ToArray();
this.center = points.Aggregate((p1, p2) => p1 + p2) / edges.Count;
this.centerColor = (Vector4)centerColor;
this.maxDistance = points.Select(p => (Vector2)(p - this.center)).Select(d => d.Length()).Max();
}
/// <inheritdoc />
internal override TPixel this[int x, int y]
{
get
{
var point = new PointF(x, y);
if (point == this.center)
{
return new Color(this.centerColor).ToPixel<TPixel>();
}
var direction = Vector2.Normalize(point - this.center);
PointF end = point + (PointF)(direction * this.maxDistance);
(Edge edge, Intersection? info) = this.FindIntersection(point, end);
if (!info.HasValue)
{
return Color.Transparent.ToPixel<TPixel>();
}
PointF intersection = info.Value.Point;
Vector4 edgeColor = edge.ColorAt(intersection);
float length = DistanceBetween(intersection, this.center);
float ratio = length > 0 ? DistanceBetween(intersection, point) / length : 0;
var color = Vector4.Lerp(edgeColor, this.centerColor, ratio);
return new Color(color).ToPixel<TPixel>();
}
}
private (Edge edge, Intersection? info) FindIntersection(PointF start, PointF end)
{
(Edge edge, Intersection? info) closest = default;
foreach (Edge edge in this.edges)
{
Intersection? intersection = edge.FindIntersection(start, end);
if (!intersection.HasValue)
{
continue;
}
if (closest.info == null || closest.info.Value.Distance > intersection.Value.Distance)
{
closest = (edge, intersection);
}
}
return closest;
}
}
}
}

178
src/ImageSharp.Drawing/Processing/PatternBrush.cs

@ -1,178 +0,0 @@
// Copyright (c) Six Labors and contributors.
// 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
{
/// <summary>
/// Provides an implementation of a pattern brush for painting patterns.
/// </summary>
/// <remarks>
/// The patterns that are used to create a custom pattern brush are made up of a repeating matrix of flags,
/// where each flag denotes whether to draw the foreground color or the background color.
/// so to create a new bool[,] with your flags
/// <para>
/// For example if you wanted to create a diagonal line that repeat every 4 pixels you would use a pattern like so
/// 1000
/// 0100
/// 0010
/// 0001
/// </para>
/// <para>
/// or you want a horizontal stripe which is 3 pixels apart you would use a pattern like
/// 1
/// 0
/// 0
/// </para>
/// </remarks>
public class PatternBrush : IBrush
{
/// <summary>
/// The pattern.
/// </summary>
private readonly DenseMatrix<Color> pattern;
private readonly DenseMatrix<Vector4> patternVector;
/// <summary>
/// Initializes a new instance of the <see cref="PatternBrush"/> class.
/// </summary>
/// <param name="foreColor">Color of the fore.</param>
/// <param name="backColor">Color of the back.</param>
/// <param name="pattern">The pattern.</param>
public PatternBrush(Color foreColor, Color backColor, bool[,] pattern)
: this(foreColor, backColor, new DenseMatrix<bool>(pattern))
{
}
/// <summary>
/// Initializes a new instance of the <see cref="PatternBrush"/> class.
/// </summary>
/// <param name="foreColor">Color of the fore.</param>
/// <param name="backColor">Color of the back.</param>
/// <param name="pattern">The pattern.</param>
internal PatternBrush(Color foreColor, Color backColor, in DenseMatrix<bool> pattern)
{
var foreColorVector = (Vector4)foreColor;
var backColorVector = (Vector4)backColor;
this.pattern = new DenseMatrix<Color>(pattern.Columns, pattern.Rows);
this.patternVector = new DenseMatrix<Vector4>(pattern.Columns, pattern.Rows);
for (int i = 0; i < pattern.Data.Length; i++)
{
if (pattern.Data[i])
{
this.pattern.Data[i] = foreColor;
this.patternVector.Data[i] = foreColorVector;
}
else
{
this.pattern.Data[i] = backColor;
this.patternVector.Data[i] = backColorVector;
}
}
}
/// <summary>
/// Initializes a new instance of the <see cref="PatternBrush"/> class.
/// </summary>
/// <param name="brush">The brush.</param>
internal PatternBrush(PatternBrush brush)
{
this.pattern = brush.pattern;
this.patternVector = brush.patternVector;
}
/// <inheritdoc />
public BrushApplicator<TPixel> CreateApplicator<TPixel>(
Configuration configuration,
GraphicsOptions options,
ImageFrame<TPixel> source,
RectangleF region)
where TPixel : struct, IPixel<TPixel> =>
new PatternBrushApplicator<TPixel>(
configuration,
options,
source,
this.pattern.ToPixelMatrix<TPixel>(configuration));
/// <summary>
/// The pattern brush applicator.
/// </summary>
private class PatternBrushApplicator<TPixel> : BrushApplicator<TPixel>
where TPixel : struct, IPixel<TPixel>
{
/// <summary>
/// The pattern.
/// </summary>
private readonly DenseMatrix<TPixel> pattern;
/// <summary>
/// Initializes a new instance of the <see cref="PatternBrushApplicator{TPixel}" /> class.
/// </summary>
/// <param name="configuration">The configuration instance to use when performing operations.</param>
/// <param name="options">The graphics options.</param>
/// <param name="source">The source image.</param>
/// <param name="pattern">The pattern.</param>
public PatternBrushApplicator(
Configuration configuration,
GraphicsOptions options,
ImageFrame<TPixel> source,
in DenseMatrix<TPixel> pattern)
: base(configuration, options, source)
{
this.pattern = pattern;
}
/// <inheritdoc/>
internal override TPixel this[int x, int y]
{
get
{
x %= this.pattern.Columns;
y %= this.pattern.Rows;
// 2d array index at row/column
return this.pattern[y, x];
}
}
/// <inheritdoc />
internal override void Apply(Span<float> scanline, int x, int y)
{
int patternY = y % this.pattern.Rows;
MemoryAllocator memoryAllocator = this.Target.MemoryAllocator;
using (IMemoryOwner<float> amountBuffer = memoryAllocator.Allocate<float>(scanline.Length))
using (IMemoryOwner<TPixel> overlay = memoryAllocator.Allocate<TPixel>(scanline.Length))
{
Span<float> amountSpan = amountBuffer.Memory.Span;
Span<TPixel> overlaySpan = overlay.Memory.Span;
for (int i = 0; i < scanline.Length; i++)
{
amountSpan[i] = NumberUtils.ClampFloat(scanline[i] * this.Options.BlendPercentage, 0, 1F);
int patternX = (x + i) % this.pattern.Columns;
overlaySpan[i] = this.pattern[patternY, patternX];
}
Span<TPixel> destinationRow = this.Target.GetPixelRowSpan(y).Slice(x, scanline.Length);
this.Blender.Blend(
this.Configuration,
destinationRow,
destinationRow,
overlaySpan,
amountSpan);
}
}
}
}
}

76
src/ImageSharp.Drawing/Processing/Pen.cs

@ -1,76 +0,0 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
namespace SixLabors.ImageSharp.Processing
{
/// <summary>
/// Provides a pen that can apply a pattern to a line with a set brush and thickness
/// </summary>
/// <remarks>
/// The pattern will be in to the form of new float[]{ 1f, 2f, 0.5f} this will be
/// converted into a pattern that is 3.5 times longer that the width with 3 sections
/// section 1 will be width long (making a square) and will be filled by the brush
/// section 2 will be width * 2 long and will be empty
/// section 3 will be width/2 long and will be filled
/// the the pattern will immediately repeat without gap.
/// </remarks>
public class Pen : IPen
{
private readonly float[] pattern;
/// <summary>
/// Initializes a new instance of the <see cref="Pen"/> class.
/// </summary>
/// <param name="color">The color.</param>
/// <param name="width">The width.</param>
/// <param name="pattern">The pattern.</param>
public Pen(Color color, float width, float[] pattern)
: this(new SolidBrush(color), width, pattern)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="Pen"/> class.
/// </summary>
/// <param name="brush">The brush.</param>
/// <param name="width">The width.</param>
/// <param name="pattern">The pattern.</param>
public Pen(IBrush brush, float width, float[] pattern)
{
this.StrokeFill = brush;
this.StrokeWidth = width;
this.pattern = pattern;
}
/// <summary>
/// Initializes a new instance of the <see cref="Pen"/> class.
/// </summary>
/// <param name="color">The color.</param>
/// <param name="width">The width.</param>
public Pen(Color color, float width)
: this(new SolidBrush(color), width)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="Pen"/> class.
/// </summary>
/// <param name="brush">The brush.</param>
/// <param name="width">The width.</param>
public Pen(IBrush brush, float width)
: this(brush, width, Pens.EmptyPattern)
{
}
/// <inheritdoc/>
public IBrush StrokeFill { get; }
/// <inheritdoc/>
public float StrokeWidth { get; }
/// <inheritdoc/>
public ReadOnlySpan<float> StrokePattern => this.pattern;
}
}

97
src/ImageSharp.Drawing/Processing/Pens.cs

@ -1,97 +0,0 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
namespace SixLabors.ImageSharp.Processing
{
/// <summary>
/// Contains a collection of common Pen styles
/// </summary>
public static class Pens
{
private static readonly float[] DashDotPattern = { 3f, 1f, 1f, 1f };
private static readonly float[] DashDotDotPattern = { 3f, 1f, 1f, 1f, 1f, 1f };
private static readonly float[] DottedPattern = { 1f, 1f };
private static readonly float[] DashedPattern = { 3f, 1f };
internal static readonly float[] EmptyPattern = new float[0];
/// <summary>
/// Create a solid pen with out any drawing patterns
/// </summary>
/// <param name="color">The color.</param>
/// <param name="width">The width.</param>
/// <returns>The Pen</returns>
public static Pen Solid(Color color, float width) => new Pen(color, width);
/// <summary>
/// Create a solid pen with out any drawing patterns
/// </summary>
/// <param name="brush">The brush.</param>
/// <param name="width">The width.</param>
/// <returns>The Pen</returns>
public static Pen Solid(IBrush brush, float width) => new Pen(brush, width);
/// <summary>
/// Create a pen with a 'Dash' drawing patterns
/// </summary>
/// <param name="color">The color.</param>
/// <param name="width">The width.</param>
/// <returns>The Pen</returns>
public static Pen Dash(Color color, float width) => new Pen(color, width, DashedPattern);
/// <summary>
/// Create a pen with a 'Dash' drawing patterns
/// </summary>
/// <param name="brush">The brush.</param>
/// <param name="width">The width.</param>
/// <returns>The Pen</returns>
public static Pen Dash(IBrush brush, float width) => new Pen(brush, width, DashedPattern);
/// <summary>
/// Create a pen with a 'Dot' drawing patterns
/// </summary>
/// <param name="color">The color.</param>
/// <param name="width">The width.</param>
/// <returns>The Pen</returns>
public static Pen Dot(Color color, float width) => new Pen(color, width, DottedPattern);
/// <summary>
/// Create a pen with a 'Dot' drawing patterns
/// </summary>
/// <param name="brush">The brush.</param>
/// <param name="width">The width.</param>
/// <returns>The Pen</returns>
public static Pen Dot(IBrush brush, float width) => new Pen(brush, width, DottedPattern);
/// <summary>
/// Create a pen with a 'Dash Dot' drawing patterns
/// </summary>
/// <param name="color">The color.</param>
/// <param name="width">The width.</param>
/// <returns>The Pen</returns>
public static Pen DashDot(Color color, float width) => new Pen(color, width, DashDotPattern);
/// <summary>
/// Create a pen with a 'Dash Dot' drawing patterns
/// </summary>
/// <param name="brush">The brush.</param>
/// <param name="width">The width.</param>
/// <returns>The Pen</returns>
public static Pen DashDot(IBrush brush, float width) => new Pen(brush, width, DashDotPattern);
/// <summary>
/// Create a pen with a 'Dash Dot Dot' drawing patterns
/// </summary>
/// <param name="color">The color.</param>
/// <param name="width">The width.</param>
/// <returns>The Pen</returns>
public static Pen DashDotDot(Color color, float width) => new Pen(color, width, DashDotDotPattern);
/// <summary>
/// Create a pen with a 'Dash Dot Dot' drawing patterns
/// </summary>
/// <param name="brush">The brush.</param>
/// <param name="width">The width.</param>
/// <returns>The Pen</returns>
public static Pen DashDotDot(IBrush brush, float width) => new Pen(brush, width, DashDotDotPattern);
}
}

41
src/ImageSharp.Drawing/Processing/Processors/Drawing/FillProcessor.cs

@ -1,41 +0,0 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Processors.Drawing
{
/// <summary>
/// Defines a processor to fill an <see cref="Image"/> with the given <see cref="IBrush"/>
/// using blending defined by the given <see cref="GraphicsOptions"/>.
/// </summary>
public class FillProcessor : IImageProcessor
{
/// <summary>
/// Initializes a new instance of the <see cref="FillProcessor"/> class.
/// </summary>
/// <param name="options">The <see cref="GraphicsOptions"/> defining how to blend the brush pixels over the image pixels.</param>
/// <param name="brush">The brush to use for filling.</param>
public FillProcessor(GraphicsOptions options, IBrush brush)
{
this.Brush = brush;
this.Options = options;
}
/// <summary>
/// Gets the <see cref="IBrush"/> used for filling the destination image.
/// </summary>
public IBrush Brush { get; }
/// <summary>
/// Gets the <see cref="GraphicsOptions"/> defining how to blend the brush pixels over the image pixels.
/// </summary>
public GraphicsOptions Options { get; }
/// <inheritdoc />
public IImageProcessor<TPixel> CreatePixelSpecificProcessor<TPixel>(Configuration configuration, Image<TPixel> source, Rectangle sourceRectangle)
where TPixel : struct, IPixel<TPixel>
=> new FillProcessor<TPixel>(configuration, this, source, sourceRectangle);
}
}

122
src/ImageSharp.Drawing/Processing/Processors/Drawing/FillProcessor{TPixel}.cs

@ -1,122 +0,0 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Buffers;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Advanced.ParallelUtils;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Processors.Drawing
{
/// <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 FillProcessor<TPixel> : ImageProcessor<TPixel>
where TPixel : struct, IPixel<TPixel>
{
private readonly FillProcessor definition;
public FillProcessor(Configuration configuration, FillProcessor definition, Image<TPixel> source, Rectangle sourceRectangle)
: base(configuration, source, sourceRectangle)
{
this.definition = definition;
}
/// <inheritdoc/>
protected override void OnFrameApply(ImageFrame<TPixel> source)
{
Rectangle sourceRectangle = this.SourceRectangle;
Configuration configuration = this.Configuration;
int startX = sourceRectangle.X;
int endX = sourceRectangle.Right;
int startY = sourceRectangle.Y;
int endY = sourceRectangle.Bottom;
// Align start/end positions.
int minX = Math.Max(0, startX);
int maxX = Math.Min(source.Width, endX);
int minY = Math.Max(0, startY);
int maxY = Math.Min(source.Height, endY);
int width = maxX - minX;
var workingRect = Rectangle.FromLTRB(minX, minY, maxX, maxY);
IBrush brush = this.definition.Brush;
GraphicsOptions options = this.definition.Options;
// If there's no reason for blending, then avoid it.
if (this.IsSolidBrushWithoutBlending(out SolidBrush solidBrush))
{
ParallelExecutionSettings parallelSettings = ParallelExecutionSettings.FromConfiguration(configuration)
.MultiplyMinimumPixelsPerTask(4);
TPixel colorPixel = solidBrush.Color.ToPixel<TPixel>();
ParallelHelper.IterateRows(
workingRect,
parallelSettings,
rows =>
{
for (int y = rows.Min; y < rows.Max; y++)
{
source.GetPixelRowSpan(y).Slice(minX, width).Fill(colorPixel);
}
});
}
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 = brush.CreateApplicator(
configuration,
options,
source,
sourceRectangle))
{
amount.Memory.Span.Fill(1f);
ParallelHelper.IterateRows(
workingRect,
configuration,
rows =>
{
for (int y = rows.Min; y < rows.Max; y++)
{
int offsetY = y - startY;
int offsetX = minX - startX;
applicator.Apply(amount.Memory.Span, offsetX, offsetY);
}
});
}
}
}
private bool IsSolidBrushWithoutBlending(out SolidBrush solidBrush)
{
solidBrush = this.definition.Brush as SolidBrush;
if (solidBrush is null)
{
return false;
}
return this.definition.Options.IsOpaqueColorWithoutBlending(solidBrush.Color);
}
}
}

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

@ -1,49 +0,0 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Primitives;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Processors.Drawing
{
/// <summary>
/// Defines a processor to fill <see cref="Image"/> pixels withing a given <see cref="Region"/>
/// with the given <see cref="IBrush"/> and blending defined by the given <see cref="GraphicsOptions"/>.
/// </summary>
public class FillRegionProcessor : IImageProcessor
{
/// <summary>
/// Initializes a new instance of the <see cref="FillRegionProcessor" /> class.
/// </summary>
/// <param name="options">The graphics options.</param>
/// <param name="brush">The details how to fill the region of interest.</param>
/// <param name="region">The region of interest to be filled.</param>
public FillRegionProcessor(GraphicsOptions options, IBrush brush, Region region)
{
this.Region = region;
this.Brush = brush;
this.Options = options;
}
/// <summary>
/// Gets the <see cref="IBrush"/> used for filling the destination image.
/// </summary>
public IBrush Brush { get; }
/// <summary>
/// Gets the region that this processor applies to.
/// </summary>
public Region Region { get; }
/// <summary>
/// Gets the <see cref="GraphicsOptions"/> defining how to blend the brush pixels over the image pixels.
/// </summary>
public GraphicsOptions Options { get; }
/// <inheritdoc />
public IImageProcessor<TPixel> CreatePixelSpecificProcessor<TPixel>(Configuration configuration, Image<TPixel> source, Rectangle sourceRectangle)
where TPixel : struct, IPixel<TPixel>
=> new FillRegionProcessor<TPixel>(configuration, this, source, sourceRectangle);
}
}

197
src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor{TPixel}.cs

@ -1,197 +0,0 @@
// Copyright (c) Six Labors and contributors.
// 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.ImageSharp.Primitives;
using SixLabors.ImageSharp.Utils;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Processors.Drawing
{
/// <summary>
/// Using a brush and a shape fills shape with contents of brush the
/// </summary>
/// <typeparam name="TPixel">The type of the color.</typeparam>
/// <seealso cref="ImageProcessor{TPixel}" />
internal class FillRegionProcessor<TPixel> : ImageProcessor<TPixel>
where TPixel : struct, IPixel<TPixel>
{
private readonly FillRegionProcessor definition;
public FillRegionProcessor(Configuration configuration, FillRegionProcessor definition, Image<TPixel> source, Rectangle sourceRectangle)
: base(configuration, source, sourceRectangle)
{
this.definition = definition;
}
/// <inheritdoc/>
protected override void OnFrameApply(ImageFrame<TPixel> source)
{
Configuration configuration = this.Configuration;
GraphicsOptions options = this.definition.Options;
IBrush brush = this.definition.Brush;
Region region = this.definition.Region;
Rectangle rect = region.Bounds;
// Align start/end positions.
int minX = Math.Max(0, rect.Left);
int maxX = Math.Min(source.Width, rect.Right);
int minY = Math.Max(0, rect.Top);
int maxY = Math.Min(source.Height, rect.Bottom);
if (minX >= maxX)
{
return; // no effect inside image;
}
if (minY >= maxY)
{
return; // no effect inside image;
}
int maxIntersections = region.MaxIntersections;
float subpixelCount = 4;
// we need to offset the pixel grid to account for when we outline a path.
// basically if the line is [1,2] => [3,2] then when outlining at 1 we end up with a region of [0.5,1.5],[1.5, 1.5],[3.5,2.5],[2.5,2.5]
// and this can cause missed fills when not using antialiasing.so we offset the pixel grid by 0.5 in the x & y direction thus causing the#
// region to align with the pixel grid.
float offset = 0.5f;
if (options.Antialias)
{
offset = 0f; // we are antialiasing skip offsetting as real antialiasing should take care of offset.
subpixelCount = options.AntialiasSubpixelDepth;
if (subpixelCount < 4)
{
subpixelCount = 4;
}
}
using (BrushApplicator<TPixel> applicator = brush.CreateApplicator(configuration, options, source, rect))
{
int scanlineWidth = maxX - minX;
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.Memory.Span;
Span<float> scanline = bScanline.Memory.Span;
bool isSolidBrushWithoutBlending = this.IsSolidBrushWithoutBlending(out SolidBrush solidBrush);
TPixel solidBrushColor = isSolidBrushWithoutBlending ? solidBrush.Color.ToPixel<TPixel>() : default;
for (int y = minY; y < maxY; y++)
{
if (scanlineDirty)
{
scanline.Clear();
scanlineDirty = false;
}
float yPlusOne = y + 1;
for (float subPixel = y; subPixel < yPlusOne; subPixel += subpixelFraction)
{
int pointsFound = region.Scan(subPixel + offset, buffer, configuration);
if (pointsFound == 0)
{
// nothing on this line, skip
continue;
}
QuickSort.Sort(buffer.Slice(0, pointsFound));
for (int point = 0; point < pointsFound && point < buffer.Length - 1; point += 2)
{
// points will be paired up
float scanStart = buffer[point] - minX;
float scanEnd = buffer[point + 1] - minX;
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 (!options.Antialias)
{
bool hasOnes = false;
bool hasZeros = false;
for (int x = 0; x < scanlineWidth; x++)
{
if (scanline[x] >= 0.5)
{
scanline[x] = 1;
hasOnes = true;
}
else
{
scanline[x] = 0;
hasZeros = true;
}
}
if (isSolidBrushWithoutBlending && hasOnes != hasZeros)
{
if (hasOnes)
{
source.GetPixelRowSpan(y).Slice(minX, scanlineWidth).Fill(solidBrushColor);
}
continue;
}
}
applicator.Apply(scanline, minX, y);
}
}
}
}
}
private bool IsSolidBrushWithoutBlending(out SolidBrush solidBrush)
{
solidBrush = this.definition.Brush as SolidBrush;
if (solidBrush == null)
{
return false;
}
return this.definition.Options.IsOpaqueColorWithoutBlending(solidBrush.Color);
}
}
}

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

@ -1,79 +0,0 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using SixLabors.Fonts;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Processors.Text
{
/// <summary>
/// Defines a processor to draw text on an <see cref="Image"/>.
/// </summary>
public class DrawTextProcessor : IImageProcessor
{
/// <summary>
/// Initializes a new instance of the <see cref="DrawTextProcessor"/> 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 drawing the text from.</param>
public DrawTextProcessor(TextGraphicsOptions options, string text, Font font, IBrush brush, IPen 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 used to fill the glyphs.
/// </summary>
public IBrush Brush { get; }
/// <summary>
/// Gets the <see cref="TextGraphicsOptions"/> defining blending modes and text-specific drawing settings.
/// </summary>
public TextGraphicsOptions Options { get; }
/// <summary>
/// Gets the text to draw.
/// </summary>
public string Text { get; }
/// <summary>
/// Gets the pen used for outlining the text, if Null then we will not outline
/// </summary>
public IPen 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; }
/// <inheritdoc />
public IImageProcessor<TPixel> CreatePixelSpecificProcessor<TPixel>(Configuration configuration, Image<TPixel> source, Rectangle sourceRectangle)
where TPixel : struct, IPixel<TPixel>
=> new DrawTextProcessor<TPixel>(configuration, this, source, sourceRectangle);
}
}

453
src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor{TPixel}.cs

@ -1,453 +0,0 @@
// 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;
private readonly DrawTextProcessor definition;
public DrawTextProcessor(Configuration configuration, DrawTextProcessor definition, Image<TPixel> source, Rectangle sourceRectangle)
: base(configuration, source, sourceRectangle)
{
this.definition = definition;
}
private TextGraphicsOptions Options => this.definition.Options;
private Font Font => this.definition.Font;
private PointF Location => this.definition.Location;
private string Text => this.definition.Text;
private IPen Pen => this.definition.Pen;
private IBrush Brush => this.definition.Brush;
protected override void BeforeImageApply()
{
base.BeforeImageApply();
// do everything at the image level as we are delegating the processing down to other processors
var style = new RendererOptions(this.Font, this.Options.DpiX, this.Options.DpiY, this.Location)
{
ApplyKerning = this.Options.ApplyKerning,
TabWidth = this.Options.TabWidth,
WrappingWidth = this.Options.WrapTextWidth,
HorizontalAlignment = this.Options.HorizontalAlignment,
VerticalAlignment = this.Options.VerticalAlignment
};
this.textRenderer = new CachingGlyphRenderer(this.Configuration.MemoryAllocator, this.Text.Length, this.Pen, this.Brush != null);
this.textRenderer.Options = (GraphicsOptions)this.Options;
var renderer = new TextRenderer(this.textRenderer);
renderer.RenderText(this.Text, style);
}
protected override void AfterImageApply()
{
base.AfterImageApply();
this.textRenderer?.Dispose();
this.textRenderer = null;
}
/// <inheritdoc/>
protected override void OnFrameApply(ImageFrame<TPixel> source)
{
// 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 brush)
{
if (operations?.Count > 0)
{
using (BrushApplicator<TPixel> app = brush.CreateApplicator(this.Configuration, this.textRenderer.Options, source, this.SourceRectangle))
{
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;
}
if (startX >= source.Width)
{
continue;
}
int firstRow = 0;
if (startY < 0)
{
firstRow = -startY;
}
int maxHeight = source.Height - startY;
int end = Math.Min(operation.Map.Height, maxHeight);
for (int row = firstRow; 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
{
// just enough accuracy to allow for 1/8 pixel differences which
// later are accumulated while rendering, but do not grow into full pixel offsets
// The value 8 is benchmarked to:
// - Provide a good accuracy (smaller than 0.2% image difference compared to the non-caching variant)
// - Cache hit ratio above 60%
private const float AccuracyMultiple = 8;
private readonly PathBuilder builder;
private Point currentRenderPosition;
private (GlyphRendererParameters glyph, PointF subPixelOffset) currentGlyphRenderParams;
private readonly int offset;
private PointF currentPoint;
private readonly Dictionary<(GlyphRendererParameters glyph, PointF subPixelOffset), GlyphRenderData>
glyphData = new Dictionary<(GlyphRendererParameters glyph, PointF subPixelOffset), GlyphRenderData>();
private readonly bool renderOutline;
private readonly bool renderFill;
private bool rasterizationRequired;
public CachingGlyphRenderer(MemoryAllocator memoryAllocator, int size, IPen pen, bool renderFill)
{
this.MemoryAllocator = memoryAllocator;
this.currentRenderPosition = default;
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 parameters)
{
this.currentRenderPosition = Point.Truncate(bounds.Location);
PointF subPixelOffset = bounds.Location - this.currentRenderPosition;
subPixelOffset.X = MathF.Round(subPixelOffset.X * AccuracyMultiple) / AccuracyMultiple;
subPixelOffset.Y = MathF.Round(subPixelOffset.Y * AccuracyMultiple) / AccuracyMultiple;
// we have offset our rendering origin 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 = (parameters, subPixelOffset);
if (this.glyphData.ContainsKey(this.currentGlyphRenderParams))
{
// we have already drawn the glyph vectors skip trying again
this.rasterizationRequired = 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 offset it back
this.builder.SetOrigin(new PointF(-(int)bounds.X + this.offset, -(int)bounds.Y + this.offset));
this.rasterizationRequired = 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 glyph, PointF subPixelOffset), 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 glyph been rendered already?
if (this.rasterizationRequired)
{
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 antialiasing skip offsetting as real antialiasing 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;
Span<PointF> intersectionSpan = rowIntersectionBuffer.Memory.Span;
Span<float> buffer = bufferBacking.Memory.Span;
for (int y = 0; y <= size.Height; y++)
{
Span<float> scanline = fullBuffer.GetRowSpan(y);
bool scanlineDirty = false;
float yPlusOne = y + 1;
for (float subPixel = y; subPixel < yPlusOne; subPixel += subpixelFraction)
{
var start = new PointF(path.Bounds.Left - 1, subPixel);
var end = new PointF(path.Bounds.Right + 1, subPixel);
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();
}
}
}
}
}

104
src/ImageSharp.Drawing/Processing/RadialGradientBrush.cs

@ -1,104 +0,0 @@
// 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 radial gradient brush, defined by center point and radius.
/// </summary>
public sealed class RadialGradientBrush : GradientBrush
{
private readonly PointF center;
private readonly float radius;
/// <inheritdoc cref="GradientBrush" />
/// <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(
PointF center,
float radius,
GradientRepetitionMode repetitionMode,
params ColorStop[] colorStops)
: base(repetitionMode, colorStops)
{
this.center = center;
this.radius = radius;
}
/// <inheritdoc />
public override BrushApplicator<TPixel> CreateApplicator<TPixel>(
Configuration configuration,
GraphicsOptions options,
ImageFrame<TPixel> source,
RectangleF region) =>
new RadialGradientBrushApplicator<TPixel>(
configuration,
options,
source,
this.center,
this.radius,
this.ColorStops,
this.RepetitionMode);
/// <inheritdoc />
private sealed class RadialGradientBrushApplicator<TPixel> : GradientBrushApplicator<TPixel>
where TPixel : struct, IPixel<TPixel>
{
private readonly PointF center;
private readonly float radius;
/// <summary>
/// Initializes a new instance of the <see cref="RadialGradientBrushApplicator{TPixel}" /> class.
/// </summary>
/// <param name="configuration">The configuration instance to use when performing operations.</param>
/// <param name="options">The graphics options.</param>
/// <param name="target">The target image.</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(
Configuration configuration,
GraphicsOptions options,
ImageFrame<TPixel> target,
PointF center,
float radius,
ColorStop[] colorStops,
GradientRepetitionMode repetitionMode)
: base(configuration, options, target, colorStops, repetitionMode)
{
this.center = center;
this.radius = radius;
}
/// <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(float x, float y)
{
// TODO: Can this not use Vector2 distance?
float distance = MathF.Sqrt(MathF.Pow(this.center.X - x, 2) + MathF.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);
}
}
}
}

166
src/ImageSharp.Drawing/Processing/RecolorBrush.cs

@ -1,166 +0,0 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Buffers;
using System.Numerics;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Memory;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing
{
/// <summary>
/// Provides an implementation of a brush that can recolor an image
/// </summary>
public class RecolorBrush : IBrush
{
/// <summary>
/// Initializes a new instance of the <see cref="RecolorBrush" /> class.
/// </summary>
/// <param name="sourceColor">Color of the source.</param>
/// <param name="targetColor">Color of the target.</param>
/// <param name="threshold">The threshold as a value between 0 and 1.</param>
public RecolorBrush(Color sourceColor, Color targetColor, float threshold)
{
this.SourceColor = sourceColor;
this.Threshold = threshold;
this.TargetColor = targetColor;
}
/// <summary>
/// Gets the threshold.
/// </summary>
public float Threshold { get; }
/// <summary>
/// Gets the source color.
/// </summary>
public Color SourceColor { get; }
/// <summary>
/// Gets the target color.
/// </summary>
public Color TargetColor { get; }
/// <inheritdoc />
public BrushApplicator<TPixel> CreateApplicator<TPixel>(
Configuration configuration,
GraphicsOptions options,
ImageFrame<TPixel> source,
RectangleF region)
where TPixel : struct, IPixel<TPixel>
{
return new RecolorBrushApplicator<TPixel>(
configuration,
options,
source,
this.SourceColor.ToPixel<TPixel>(),
this.TargetColor.ToPixel<TPixel>(),
this.Threshold);
}
/// <summary>
/// The recolor brush applicator.
/// </summary>
private class RecolorBrushApplicator<TPixel> : BrushApplicator<TPixel>
where TPixel : struct, IPixel<TPixel>
{
/// <summary>
/// The source color.
/// </summary>
private readonly Vector4 sourceColor;
/// <summary>
/// The threshold.
/// </summary>
private readonly float threshold;
private readonly TPixel targetColorPixel;
/// <summary>
/// Initializes a new instance of the <see cref="RecolorBrushApplicator{TPixel}" /> class.
/// </summary>
/// <param name="configuration">The configuration instance to use when performing operations.</param>
/// <param name="options">The options</param>
/// <param name="source">The source image.</param>
/// <param name="sourceColor">Color of the source.</param>
/// <param name="targetColor">Color of the target.</param>
/// <param name="threshold">The threshold .</param>
public RecolorBrushApplicator(
Configuration configuration,
GraphicsOptions options,
ImageFrame<TPixel> source,
TPixel sourceColor,
TPixel targetColor,
float threshold)
: base(configuration, options, source)
{
this.sourceColor = sourceColor.ToVector4();
this.targetColorPixel = targetColor;
// Lets hack a min max extremes for a color space by letting the IPackedPixel clamp our values to something in the correct spaces :)
var maxColor = default(TPixel);
maxColor.FromVector4(new Vector4(float.MaxValue));
var minColor = default(TPixel);
minColor.FromVector4(new Vector4(float.MinValue));
this.threshold = Vector4.DistanceSquared(maxColor.ToVector4(), minColor.ToVector4()) * threshold;
}
/// <inheritdoc />
internal override TPixel this[int x, int y]
{
get
{
// Offset the requested pixel by the value in the rectangle (the shapes position)
TPixel result = this.Target[x, y];
var background = result.ToVector4();
float distance = Vector4.DistanceSquared(background, this.sourceColor);
if (distance <= this.threshold)
{
float lerpAmount = (this.threshold - distance) / this.threshold;
return this.Blender.Blend(
result,
this.targetColorPixel,
lerpAmount);
}
return result;
}
}
/// <inheritdoc />
internal override void Apply(Span<float> scanline, int x, int y)
{
MemoryAllocator memoryAllocator = this.Target.MemoryAllocator;
using (IMemoryOwner<float> amountBuffer = memoryAllocator.Allocate<float>(scanline.Length))
using (IMemoryOwner<TPixel> overlay = memoryAllocator.Allocate<TPixel>(scanline.Length))
{
Span<float> amountSpan = amountBuffer.Memory.Span;
Span<TPixel> overlaySpan = overlay.Memory.Span;
for (int i = 0; i < scanline.Length; i++)
{
amountSpan[i] = scanline[i] * this.Options.BlendPercentage;
int offsetX = x + i;
// No doubt this one can be optimized further but I can't imagine its
// actually being used and can probably be removed/internalized for now
overlaySpan[i] = this[offsetX, y];
}
Span<TPixel> destinationRow = this.Target.GetPixelRowSpan(y).Slice(x, scanline.Length);
this.Blender.Blend(
this.Configuration,
destinationRow,
destinationRow,
overlaySpan,
amountSpan);
}
}
}
}
}

139
src/ImageSharp.Drawing/Processing/SolidBrush.cs

@ -1,139 +0,0 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Buffers;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Memory;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing
{
/// <summary>
/// Provides an implementation of a solid brush for painting solid color areas.
/// </summary>
public class SolidBrush : IBrush
{
/// <summary>
/// Initializes a new instance of the <see cref="SolidBrush"/> class.
/// </summary>
/// <param name="color">The color.</param>
public SolidBrush(Color color)
{
this.Color = color;
}
/// <summary>
/// Gets the color.
/// </summary>
public Color Color { get; }
/// <inheritdoc />
public BrushApplicator<TPixel> CreateApplicator<TPixel>(
Configuration configuration,
GraphicsOptions options,
ImageFrame<TPixel> source,
RectangleF region)
where TPixel : struct, IPixel<TPixel>
{
return new SolidBrushApplicator<TPixel>(configuration, options, source, this.Color.ToPixel<TPixel>());
}
/// <summary>
/// The solid brush applicator.
/// </summary>
private class SolidBrushApplicator<TPixel> : BrushApplicator<TPixel>
where TPixel : struct, IPixel<TPixel>
{
private bool isDisposed;
/// <summary>
/// Initializes a new instance of the <see cref="SolidBrushApplicator{TPixel}"/> class.
/// </summary>
/// <param name="configuration">The configuration instance to use when performing operations.</param>
/// <param name="options">The graphics options.</param>
/// <param name="source">The source image.</param>
/// <param name="color">The color.</param>
public SolidBrushApplicator(
Configuration configuration,
GraphicsOptions options,
ImageFrame<TPixel> source,
TPixel color)
: base(configuration, options, source)
{
this.Colors = source.MemoryAllocator.Allocate<TPixel>(source.Width);
this.Colors.Memory.Span.Fill(color);
}
/// <summary>
/// Gets the colors.
/// </summary>
protected IMemoryOwner<TPixel> Colors { get; private set; }
/// <inheritdoc/>
internal override TPixel this[int x, int y] => this.Colors.Memory.Span[x];
/// <inheritdoc />
protected override void Dispose(bool disposing)
{
if (this.isDisposed)
{
return;
}
if (disposing)
{
this.Colors.Dispose();
}
this.Colors = null;
this.isDisposed = true;
}
/// <inheritdoc />
internal override void Apply(Span<float> scanline, int x, int y)
{
Span<TPixel> destinationRow = this.Target.GetPixelRowSpan(y).Slice(x);
// constrain the spans to each other
if (destinationRow.Length > scanline.Length)
{
destinationRow = destinationRow.Slice(0, scanline.Length);
}
else
{
scanline = scanline.Slice(0, destinationRow.Length);
}
MemoryAllocator memoryAllocator = this.Target.MemoryAllocator;
Configuration configuration = this.Configuration;
if (this.Options.BlendPercentage == 1f)
{
this.Blender.Blend(configuration, destinationRow, destinationRow, this.Colors.Memory.Span, scanline);
}
else
{
using (IMemoryOwner<float> amountBuffer = memoryAllocator.Allocate<float>(scanline.Length))
{
Span<float> amountSpan = amountBuffer.Memory.Span;
for (int i = 0; i < scanline.Length; i++)
{
amountSpan[i] = scanline[i] * this.Options.BlendPercentage;
}
this.Blender.Blend(
configuration,
destinationRow,
destinationRow,
this.Colors.Memory.Span,
amountSpan);
}
}
}
}
}
}

217
src/ImageSharp.Drawing/Processing/TextGraphicsOptions.cs

@ -1,217 +0,0 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.Fonts;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Processing
{
/// <summary>
/// Options for influencing the drawing functions.
/// </summary>
public class TextGraphicsOptions : IDeepCloneable<TextGraphicsOptions>
{
private int antialiasSubpixelDepth = 16;
private float blendPercentage = 1F;
private float tabWidth = 4F;
private float dpiX = 72F;
private float dpiY = 72F;
/// <summary>
/// Initializes a new instance of the <see cref="TextGraphicsOptions"/> class.
/// </summary>
public TextGraphicsOptions()
{
}
private TextGraphicsOptions(TextGraphicsOptions source)
{
this.AlphaCompositionMode = source.AlphaCompositionMode;
this.Antialias = source.Antialias;
this.AntialiasSubpixelDepth = source.AntialiasSubpixelDepth;
this.ApplyKerning = source.ApplyKerning;
this.BlendPercentage = source.BlendPercentage;
this.ColorBlendingMode = source.ColorBlendingMode;
this.DpiX = source.DpiX;
this.DpiY = source.DpiY;
this.HorizontalAlignment = source.HorizontalAlignment;
this.TabWidth = source.TabWidth;
this.WrapTextWidth = source.WrapTextWidth;
this.VerticalAlignment = source.VerticalAlignment;
}
/// <summary>
/// Gets or sets a value indicating whether antialiasing should be applied.
/// Defaults to true.
/// </summary>
public bool Antialias { get; set; } = true;
/// <summary>
/// Gets or sets a value indicating the number of subpixels to use while rendering with antialiasing enabled.
/// </summary>
public int AntialiasSubpixelDepth
{
get
{
return this.antialiasSubpixelDepth;
}
set
{
Guard.MustBeGreaterThanOrEqualTo(value, 0, nameof(this.AntialiasSubpixelDepth));
this.antialiasSubpixelDepth = value;
}
}
/// <summary>
/// Gets or sets a value indicating the blending percentage to apply to the drawing operation.
/// </summary>
public float BlendPercentage
{
get
{
return this.blendPercentage;
}
set
{
Guard.MustBeBetweenOrEqualTo(value, 0, 1F, nameof(this.BlendPercentage));
this.blendPercentage = value;
}
}
/// <summary>
/// Gets or sets a value indicating the color blending percentage to apply to the drawing operation.
/// Defaults to <see cref= "PixelColorBlendingMode.Normal" />.
/// </summary>
public PixelColorBlendingMode ColorBlendingMode { get; set; } = PixelColorBlendingMode.Normal;
/// <summary>
/// Gets or sets a value indicating the color blending percentage to apply to the drawing operation
/// Defaults to <see cref= "PixelAlphaCompositionMode.SrcOver" />.
/// </summary>
public PixelAlphaCompositionMode AlphaCompositionMode { get; set; } = PixelAlphaCompositionMode.SrcOver;
/// <summary>
/// Gets or sets a value indicating whether the text should be drawing with kerning enabled.
/// Defaults to true;
/// </summary>
public bool ApplyKerning { get; set; } = true;
/// <summary>
/// Gets or sets a value indicating the number of space widths a tab should lock to.
/// Defaults to 4.
/// </summary>
public float TabWidth
{
get
{
return this.tabWidth;
}
set
{
Guard.MustBeGreaterThanOrEqualTo(value, 0, nameof(this.TabWidth));
this.tabWidth = value;
}
}
/// <summary>
/// Gets or sets a value, if greater than 0, indicating the width at which text should wrap.
/// Defaults to 0.
/// </summary>
public float WrapTextWidth { get; set; }
/// <summary>
/// Gets or sets a value indicating the DPI (Dots Per Inch) to render text along the X axis.
/// Defaults to 72.
/// </summary>
public float DpiX
{
get
{
return this.dpiX;
}
set
{
Guard.MustBeGreaterThanOrEqualTo(value, 0, nameof(this.DpiX));
this.dpiX = value;
}
}
/// <summary>
/// Gets or sets a value indicating the DPI (Dots Per Inch) to render text along the Y axis.
/// Defaults to 72.
/// </summary>
public float DpiY
{
get
{
return this.dpiY;
}
set
{
Guard.MustBeGreaterThanOrEqualTo(value, 0, nameof(this.DpiY));
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
/// defined by the location and width, if <see cref="WrapTextWidth"/> equals zero, and thus
/// wrapping disabled, then the alignment is relative to the drawing location.
/// Defaults to <see cref="HorizontalAlignment.Left"/>.
/// </summary>
public HorizontalAlignment HorizontalAlignment { get; set; } = HorizontalAlignment.Left;
/// <summary>
/// Gets or sets a value indicating how to align the text relative to the rendering space.
/// Defaults to <see cref="VerticalAlignment.Top"/>.
/// </summary>
public VerticalAlignment VerticalAlignment { get; set; } = VerticalAlignment.Top;
/// <summary>
/// Performs an implicit conversion from <see cref="GraphicsOptions"/> to <see cref="TextGraphicsOptions"/>.
/// </summary>
/// <param name="options">The options.</param>
/// <returns>
/// The result of the conversion.
/// </returns>
public static implicit operator TextGraphicsOptions(GraphicsOptions options)
{
return new TextGraphicsOptions()
{
Antialias = options.Antialias,
AntialiasSubpixelDepth = options.AntialiasSubpixelDepth,
blendPercentage = options.BlendPercentage,
ColorBlendingMode = options.ColorBlendingMode,
AlphaCompositionMode = options.AlphaCompositionMode
};
}
/// <summary>
/// Performs an explicit conversion from <see cref="TextGraphicsOptions"/> to <see cref="GraphicsOptions"/>.
/// </summary>
/// <param name="options">The options.</param>
/// <returns>
/// The result of the conversion.
/// </returns>
public static explicit operator GraphicsOptions(TextGraphicsOptions options)
{
return new GraphicsOptions()
{
Antialias = options.Antialias,
AntialiasSubpixelDepth = options.AntialiasSubpixelDepth,
ColorBlendingMode = options.ColorBlendingMode,
AlphaCompositionMode = options.AlphaCompositionMode,
BlendPercentage = options.BlendPercentage
};
}
/// <inheritdoc/>
public TextGraphicsOptions DeepClone() => new TextGraphicsOptions(this);
}
}

29
src/ImageSharp.Drawing/Utils/NumberUtils.cs

@ -1,29 +0,0 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp
{
/// <summary>
/// Utility methods for numeric primitives.
/// </summary>
internal static class NumberUtils
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float ClampFloat(float value, float min, float max)
{
if (value >= max)
{
return max;
}
if (value <= min)
{
return min;
}
return value;
}
}
}

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

@ -1,84 +0,0 @@
// 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));
}
}
}
}

1
src/ImageSharp/Advanced/AdvancedImageExtensions.cs

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

2
src/ImageSharp/Advanced/AotCompilerTools.cs

@ -1,6 +1,7 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System.Diagnostics.CodeAnalysis;
using System.Numerics;
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Formats;
@ -19,6 +20,7 @@ namespace SixLabors.ImageSharp.Advanced
/// None of the methods in this class should ever be called, the code only has to exist at compile-time to be picked up by the AoT compiler.
/// (Very similar to the LinkerIncludes.cs technique used in Xamarin.Android projects.)
/// </summary>
[ExcludeFromCodeCoverage]
internal static class AotCompilerTools
{
static AotCompilerTools()

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

@ -4,7 +4,7 @@
using System;
using System.Threading.Tasks;
using SixLabors.Memory;
using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp.Advanced.ParallelUtils
{

2
src/ImageSharp/Advanced/ParallelUtils/ParallelHelper.cs

@ -7,8 +7,6 @@ using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using SixLabors.ImageSharp.Memory;
using SixLabors.Memory;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Advanced.ParallelUtils
{

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

@ -1,7 +1,7 @@
// Copyright (c) Six Labors and contributors.
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
#if !NETCOREAPP2_1
#if !SUPPORTS_ENCODING_STRING
using System;
using System.Text;
@ -32,4 +32,4 @@ namespace SixLabors.ImageSharp
}
}
}
#endif
#endif

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

@ -4,9 +4,7 @@
using System;
using System.Buffers;
using System.IO;
using SixLabors.ImageSharp.Memory;
using SixLabors.Memory;
namespace SixLabors.ImageSharp
{
@ -15,7 +13,6 @@ namespace SixLabors.ImageSharp
/// </summary>
internal static class StreamExtensions
{
#if NETCOREAPP2_1
/// <summary>
/// Writes data from a stream into the provided buffer.
/// </summary>
@ -24,23 +21,18 @@ namespace SixLabors.ImageSharp
/// <param name="offset">The offset within the buffer to begin writing.</param>
/// <param name="count">The number of bytes to write to the stream.</param>
public static void Write(this Stream stream, Span<byte> buffer, int offset, int count)
{
stream.Write(buffer.Slice(offset, count));
}
=> stream.Write(buffer.Slice(offset, count));
/// <summary>
/// Reads data from a stream into the provided buffer.
/// </summary>
/// <param name="stream">The stream.</param>
/// <param name="buffer">The buffer..</param>
/// <param name="buffer">The buffer.</param>
/// <param name="offset">The offset within the buffer where the bytes are read into.</param>
/// <param name="count">The number of bytes, if available, to read.</param>
/// <returns>The actual number of bytes read.</returns>
public static int Read(this Stream stream, Span<byte> buffer, int offset, int count)
{
return stream.Read(buffer.Slice(offset, count));
}
#endif
=> stream.Read(buffer.Slice(offset, count));
/// <summary>
/// Skips the number of bytes in the given stream.
@ -75,17 +67,39 @@ namespace SixLabors.ImageSharp
}
public static void Read(this Stream stream, IManagedByteBuffer buffer)
{
stream.Read(buffer.Array, 0, buffer.Length());
}
=> stream.Read(buffer.Array, 0, buffer.Length());
public static void Write(this Stream stream, IManagedByteBuffer buffer)
=> stream.Write(buffer.Array, 0, buffer.Length());
#if !SUPPORTS_SPAN_STREAM
// This is a port of the CoreFX implementation and is MIT Licensed:
// https://github.com/dotnet/corefx/blob/17300169760c61a90cab8d913636c1058a30a8c1/src/Common/src/CoreLib/System/IO/Stream.cs#L742
public static int Read(this Stream stream, Span<byte> buffer)
{
stream.Write(buffer.Array, 0, buffer.Length());
// This uses ArrayPool<byte>.Shared, rather than taking a MemoryAllocator,
// in order to match the signature of the framework method that exists in
// .NET Core.
byte[] sharedBuffer = ArrayPool<byte>.Shared.Rent(buffer.Length);
try
{
int numRead = stream.Read(sharedBuffer, 0, buffer.Length);
if ((uint)numRead > (uint)buffer.Length)
{
throw new IOException("Stream was too long.");
}
new Span<byte>(sharedBuffer, 0, numRead).CopyTo(buffer);
return numRead;
}
finally
{
ArrayPool<byte>.Shared.Return(sharedBuffer);
}
}
#if NET472 || NETSTANDARD1_3 || NETSTANDARD2_0
// This is a port of the CoreFX implementation and is MIT Licensed: https://github.com/dotnet/coreclr/blob/c4dca1072d15bdda64c754ad1ea474b1580fa554/src/System.Private.CoreLib/shared/System/IO/Stream.cs#L770
// This is a port of the CoreFX implementation and is MIT Licensed:
// https://github.com/dotnet/corefx/blob/17300169760c61a90cab8d913636c1058a30a8c1/src/Common/src/CoreLib/System/IO/Stream.cs#L775
public static void Write(this Stream stream, ReadOnlySpan<byte> buffer)
{
// This uses ArrayPool<byte>.Shared, rather than taking a MemoryAllocator,

1
src/ImageSharp/Common/Helpers/Buffer2DUtils.cs

@ -8,7 +8,6 @@ using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Primitives;
namespace SixLabors.ImageSharp
{

1
src/ImageSharp/Common/Helpers/DenseMatrixUtils.cs

@ -6,7 +6,6 @@ using System.Numerics;
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Primitives;
namespace SixLabors.ImageSharp
{

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

@ -6,7 +6,6 @@ using System.Numerics;
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp
{

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

@ -1,4 +1,4 @@
// Copyright (c) Six Labors and contributors.
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
namespace SixLabors.ImageSharp.Common.Helpers
@ -13,14 +13,18 @@ namespace SixLabors.ImageSharp.Common.Helpers
/// Only intended to be used in tests!
/// </summary>
internal const string ImageSharpBuiltAgainst =
#if NET472
"netfx4.7.2";
#if NETCOREAPP3_1
"netcoreapp3.1";
#elif NETCOREAPP2_1
"netcoreapp2.1";
#elif NETSTANDARD2_1
"netstandard2.1";
#elif NETSTANDARD2_0
"netstandard2.0";
#elif NETSTANDARD1_3
"netstandard1.3";
#else
"netstandard2.0";
"net472";
#endif
}
}
}

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

@ -5,7 +5,6 @@ using System;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Primitives;
namespace SixLabors.ImageSharp
{

2
src/ImageSharp/Configuration.cs

@ -10,8 +10,8 @@ using SixLabors.ImageSharp.Formats.Jpeg;
using SixLabors.ImageSharp.Formats.Png;
using SixLabors.ImageSharp.Formats.Tga;
using SixLabors.ImageSharp.IO;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Processing;
using SixLabors.Memory;
namespace SixLabors.ImageSharp
{

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

@ -11,7 +11,6 @@ using SixLabors.ImageSharp.Common.Helpers;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Metadata;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Memory;
namespace SixLabors.ImageSharp.Formats.Bmp
{
@ -445,11 +444,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
/// <param name="rowsWithUndefinedPixels">Keeps track of rows, which have undefined pixels.</param>
private void UncompressRle4(int w, Span<byte> buffer, Span<bool> undefinedPixels, Span<bool> rowsWithUndefinedPixels)
{
#if NETCOREAPP2_1
Span<byte> cmd = stackalloc byte[2];
#else
var cmd = new byte[2];
#endif
int count = 0;
while (count < buffer.Length)
@ -556,11 +551,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
/// <param name="rowsWithUndefinedPixels">Keeps track of rows, which have undefined pixels.</param>
private void UncompressRle8(int w, Span<byte> buffer, Span<bool> undefinedPixels, Span<bool> rowsWithUndefinedPixels)
{
#if NETCOREAPP2_1
Span<byte> cmd = stackalloc byte[2];
#else
var cmd = new byte[2];
#endif
int count = 0;
while (count < buffer.Length)
@ -639,11 +630,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
/// <param name="rowsWithUndefinedPixels">Keeps track of rows, which have undefined pixels.</param>
private void UncompressRle24(int w, Span<byte> buffer, Span<bool> undefinedPixels, Span<bool> rowsWithUndefinedPixels)
{
#if NETCOREAPP2_1
Span<byte> cmd = stackalloc byte[2];
#else
var cmd = new byte[2];
#endif
int uncompressedPixels = 0;
while (uncompressedPixels < buffer.Length)
@ -1213,11 +1200,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
/// </summary>
private void ReadInfoHeader()
{
#if NETCOREAPP2_1
Span<byte> buffer = stackalloc byte[BmpInfoHeader.MaxHeaderSize];
#else
var buffer = new byte[BmpInfoHeader.MaxHeaderSize];
#endif
// Read the header size.
this.stream.Read(buffer, 0, BmpInfoHeader.HeaderSizeSize);
@ -1339,11 +1322,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
/// </summary>
private void ReadFileHeader()
{
#if NETCOREAPP2_1
Span<byte> buffer = stackalloc byte[BmpFileHeader.Size];
#else
var buffer = new byte[BmpFileHeader.Size];
#endif
this.stream.Read(buffer, 0, BmpFileHeader.Size);
short fileTypeMarker = BinaryPrimitives.ReadInt16LittleEndian(buffer);

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

@ -12,7 +12,6 @@ using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Metadata;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Processors.Quantization;
using SixLabors.Memory;
namespace SixLabors.ImageSharp.Formats.Bmp
{
@ -173,11 +172,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
reserved: 0,
offset: BmpFileHeader.Size + infoHeaderSize + colorPaletteSize);
#if NETCOREAPP2_1
Span<byte> buffer = stackalloc byte[infoHeaderSize];
#else
var buffer = new byte[infoHeaderSize];
#endif
fileHeader.WriteTo(buffer);
stream.Write(buffer, 0, BmpFileHeader.Size);

2
src/ImageSharp/Formats/Gif/GifDecoderCore.cs

@ -10,8 +10,6 @@ using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Metadata;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Memory;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Formats.Gif
{

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

@ -12,7 +12,6 @@ using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Metadata;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Processors.Quantization;
using SixLabors.Memory;
namespace SixLabors.ImageSharp.Formats.Gif
{

9
src/ImageSharp/Formats/Gif/LzwDecoder.cs

@ -8,7 +8,6 @@ using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Memory;
using SixLabors.Memory;
namespace SixLabors.ImageSharp.Formats.Gif
{
@ -113,11 +112,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
Unsafe.Add(ref suffixRef, code) = (byte)code;
}
#if NETCOREAPP2_1
Span<byte> buffer = stackalloc byte[255];
#else
var buffer = new byte[255];
#endif
while (xyz < length)
{
@ -227,11 +222,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
/// The <see cref="int"/>.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#if NETCOREAPP2_1
private int ReadBlock(Span<byte> buffer)
#else
private int ReadBlock(byte[] buffer)
#endif
{
int bufferSize = this.stream.ReadByte();

1
src/ImageSharp/Formats/Gif/LzwEncoder.cs

@ -8,7 +8,6 @@ using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Memory;
using SixLabors.Memory;
namespace SixLabors.ImageSharp.Formats.Gif
{

1
src/ImageSharp/Formats/Jpeg/Components/Decoder/IJpegComponent.cs

@ -2,7 +2,6 @@
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.Memory;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
{

2
src/ImageSharp/Formats/Jpeg/Components/Decoder/IRawJpegData.cs

@ -3,8 +3,6 @@
using System;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
{
/// <inheritdoc />

1
src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegBlockPostProcessor.cs

@ -4,7 +4,6 @@
using System;
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Memory;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
{

13
src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponent.cs

@ -1,11 +1,9 @@
// Copyright (c) Six Labors and contributors.
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using SixLabors.ImageSharp.Memory;
using SixLabors.Memory;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
{
@ -22,11 +20,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
this.Frame = frame;
this.Id = id;
// Valid sampling factors are 1..2
if (horizontalFactor == 0
|| verticalFactor == 0
|| horizontalFactor > 2
|| verticalFactor > 2)
// Validate sampling factors.
if (horizontalFactor == 0 || verticalFactor == 0)
{
JpegThrowHelper.ThrowBadSampling();
}
@ -138,4 +133,4 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
this.SpectralBlocks = this.memoryAllocator.Allocate2D<Block8x8>(width, height, AllocationOptions.Clean);
}
}
}
}

2
src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponentPostProcessor.cs

@ -6,8 +6,6 @@ using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Memory;
using SixLabors.Memory;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
{

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

Loading…
Cancel
Save