mirror of https://github.com/SixLabors/ImageSharp
committed by
GitHub
513 changed files with 6136 additions and 11293 deletions
@ -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 |
|||
@ -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 |
|||
@ -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}" |
|||
} |
|||
] |
|||
} |
|||
@ -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" |
|||
} |
|||
] |
|||
} |
|||
@ -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> |
|||
@ -0,0 +1,7 @@ |
|||
continuous-delivery-fallback-tag: ci |
|||
branches: |
|||
master: |
|||
tag: unstable |
|||
mode: ContinuousDeployment |
|||
pull-request: |
|||
tag: pr |
|||
@ -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"><?xml version="1.0" encoding="utf-16"?> |
|||
<Profile name="StyleCop"> |
|||
<CSUpdateFileHeader>False</CSUpdateFileHeader> |
|||
<CSArrangeQualifiers>True</CSArrangeQualifiers> |
|||
<CSOptimizeUsings> |
|||
<OptimizeUsings>True</OptimizeUsings> |
|||
<EmbraceInRegion>False</EmbraceInRegion> |
|||
<RegionName></RegionName> |
|||
</CSOptimizeUsings> |
|||
<CSReformatCode>True</CSReformatCode> |
|||
<CSReorderTypeMembers>True</CSReorderTypeMembers> |
|||
</Profile></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"><?xml version="1.0" encoding="utf-16"?>
 |
|||
<Patterns xmlns="urn:schemas-jetbrains-com:member-reordering-patterns">
 |
|||
<TypePattern DisplayName="COM interfaces or structs">
 |
|||
<TypePattern.Match>
 |
|||
<Or>
 |
|||
<And>
 |
|||
<Kind Is="Interface" />
 |
|||
<Or>
 |
|||
<HasAttribute Name="System.Runtime.InteropServices.InterfaceTypeAttribute" />
 |
|||
<HasAttribute Name="System.Runtime.InteropServices.ComImport" />
 |
|||
</Or>
 |
|||
</And>
 |
|||
<Kind Is="Struct" />
 |
|||
</Or>
 |
|||
</TypePattern.Match>
 |
|||
</TypePattern>
 |
|||
<TypePattern DisplayName="P/Invoke classes called 'NativeMethods' (StyleCop)">
 |
|||
<TypePattern.Match>
 |
|||
<And>
 |
|||
<Kind Is="Class" />
 |
|||
<Name Is=".*NativeMethods" />
 |
|||
</And>
 |
|||
</TypePattern.Match>
 |
|||
</TypePattern>
 |
|||
<TypePattern DisplayName="DataMember serialisation classes (StyleCop)">
 |
|||
<TypePattern.Match>
 |
|||
<And>
 |
|||
<Or>
 |
|||
<Kind Is="Field" />
 |
|||
<Kind Is="Property" />
 |
|||
</Or>
 |
|||
<HasAttribute Name="System.Runtime.Serialization.DataMemberAttribute" />
 |
|||
</And>
 |
|||
</TypePattern.Match>
 |
|||
</TypePattern>
 |
|||
<TypePattern DisplayName="Default Pattern (StyleCop)" RemoveRegions="All">
 |
|||
<Entry DisplayName="Constants">
 |
|||
<Entry.Match>
 |
|||
<Kind Is="Constant" />
 |
|||
</Entry.Match>
 |
|||
<Entry.SortBy>
 |
|||
<Access Order="Public Internal ProtectedInternal Protected Private" />
 |
|||
<Name />
 |
|||
</Entry.SortBy>
 |
|||
</Entry>
 |
|||
<Entry DisplayName="Static fields">
 |
|||
<Entry.Match>
 |
|||
<And>
 |
|||
<Kind Is="Field" />
 |
|||
<Static />
 |
|||
</And>
 |
|||
</Entry.Match>
 |
|||
<Entry.SortBy>
 |
|||
<Access Order="Public Internal ProtectedInternal Protected Private" />
 |
|||
<Readonly />
 |
|||
<Name />
 |
|||
</Entry.SortBy>
 |
|||
</Entry>
 |
|||
<Entry DisplayName="Fields">
 |
|||
<Entry.Match>
 |
|||
<Kind Is="Field" />
 |
|||
</Entry.Match>
 |
|||
<Entry.SortBy>
 |
|||
<Access Order="Public Internal ProtectedInternal Protected Private" />
 |
|||
<Readonly />
 |
|||
<Name />
 |
|||
</Entry.SortBy>
 |
|||
</Entry>
 |
|||
<Entry Priority="200" DisplayName="Constructors and Destructors">
 |
|||
<Entry.Match>
 |
|||
<Or>
 |
|||
<Kind Is="Constructor" />
 |
|||
<Kind Is="Destructor" />
 |
|||
</Or>
 |
|||
</Entry.Match>
 |
|||
<Entry.SortBy>
 |
|||
<Static />
 |
|||
<Kind Order="Constructor Destructor" />
 |
|||
<Access Order="Public Internal ProtectedInternal Protected Private" />
 |
|||
</Entry.SortBy>
 |
|||
</Entry>
 |
|||
<Entry DisplayName="Delegates">
 |
|||
<Entry.Match>
 |
|||
<Kind Is="Delegate" />
 |
|||
</Entry.Match>
 |
|||
<Entry.SortBy>
 |
|||
<Access Order="Public Internal ProtectedInternal Protected Private" />
 |
|||
<Static />
 |
|||
<Name />
 |
|||
</Entry.SortBy>
 |
|||
</Entry>
 |
|||
<Entry DisplayName="Public events">
 |
|||
<Entry.Match>
 |
|||
<And>
 |
|||
<Kind Is="Event" />
 |
|||
<Access Is="Public" />
 |
|||
</And>
 |
|||
</Entry.Match>
 |
|||
<Entry.SortBy>
 |
|||
<Access Order="Public" />
 |
|||
<Static />
 |
|||
<Name />
 |
|||
</Entry.SortBy>
 |
|||
</Entry>
 |
|||
<Entry DisplayName="Interface events">
 |
|||
<Entry.Match>
 |
|||
<And>
 |
|||
<Kind Is="Event" />
 |
|||
<ImplementsInterface />
 |
|||
</And>
 |
|||
</Entry.Match>
 |
|||
<Entry.SortBy>
 |
|||
<ImplementsInterface Immediate="True" />
 |
|||
<Name />
 |
|||
</Entry.SortBy>
 |
|||
</Entry>
 |
|||
<Entry DisplayName="Other events">
 |
|||
<Entry.Match>
 |
|||
<Kind Is="Event" />
 |
|||
</Entry.Match>
 |
|||
<Entry.SortBy>
 |
|||
<Access Order="Public Internal ProtectedInternal Protected Private" />
 |
|||
<Static />
 |
|||
<Name />
 |
|||
</Entry.SortBy>
 |
|||
</Entry>
 |
|||
<Entry DisplayName="Enums">
 |
|||
<Entry.Match>
 |
|||
<Kind Is="Enum" />
 |
|||
</Entry.Match>
 |
|||
<Entry.SortBy>
 |
|||
<Access Order="Public Internal ProtectedInternal Protected Private" />
 |
|||
<Name />
 |
|||
</Entry.SortBy>
 |
|||
</Entry>
 |
|||
<Entry DisplayName="Interfaces">
 |
|||
<Entry.Match>
 |
|||
<Kind Is="Interface" />
 |
|||
</Entry.Match>
 |
|||
<Entry.SortBy>
 |
|||
<Access Order="Public Internal ProtectedInternal Protected Private" />
 |
|||
<Name />
 |
|||
</Entry.SortBy>
 |
|||
</Entry>
 |
|||
<Entry DisplayName="Public properties">
 |
|||
<Entry.Match>
 |
|||
<And>
 |
|||
<Kind Is="Property" />
 |
|||
<Access Is="Public" />
 |
|||
</And>
 |
|||
</Entry.Match>
 |
|||
<Entry.SortBy>
 |
|||
<Static />
 |
|||
<Name />
 |
|||
</Entry.SortBy>
 |
|||
</Entry>
 |
|||
<Entry DisplayName="Interface properties">
 |
|||
<Entry.Match>
 |
|||
<And>
 |
|||
<Kind Is="Property" />
 |
|||
<ImplementsInterface />
 |
|||
</And>
 |
|||
</Entry.Match>
 |
|||
<Entry.SortBy>
 |
|||
<ImplementsInterface Immediate="True" />
 |
|||
<Name />
 |
|||
</Entry.SortBy>
 |
|||
</Entry>
 |
|||
<Entry DisplayName="Other properties">
 |
|||
<Entry.Match>
 |
|||
<Kind Is="Property" />
 |
|||
</Entry.Match>
 |
|||
<Entry.SortBy>
 |
|||
<Access Order="Public Internal ProtectedInternal Protected Private" />
 |
|||
<Static />
 |
|||
<Name />
 |
|||
</Entry.SortBy>
 |
|||
</Entry>
 |
|||
<Entry Priority="1000" DisplayName="Public indexers">
 |
|||
<Entry.Match>
 |
|||
<And>
 |
|||
<Kind Is="Indexer" />
 |
|||
<Access Is="Public" />
 |
|||
</And>
 |
|||
</Entry.Match>
 |
|||
<Entry.SortBy>
 |
|||
<Static />
 |
|||
<Name />
 |
|||
</Entry.SortBy>
 |
|||
</Entry>
 |
|||
<Entry Priority="1000" DisplayName="Interface indexers">
 |
|||
<Entry.Match>
 |
|||
<And>
 |
|||
<Kind Is="Indexer" />
 |
|||
<ImplementsInterface />
 |
|||
</And>
 |
|||
</Entry.Match>
 |
|||
<Entry.SortBy>
 |
|||
<ImplementsInterface Immediate="True" />
 |
|||
<Name />
 |
|||
</Entry.SortBy>
 |
|||
</Entry>
 |
|||
<Entry Priority="1000" DisplayName="Other indexers">
 |
|||
<Entry.Match>
 |
|||
<Kind Is="Indexer" />
 |
|||
</Entry.Match>
 |
|||
<Entry.SortBy>
 |
|||
<Access Order="Public Internal ProtectedInternal Protected Private" />
 |
|||
<Static />
 |
|||
<Name />
 |
|||
</Entry.SortBy>
 |
|||
</Entry>
 |
|||
<Entry DisplayName="Public methods and operators">
 |
|||
<Entry.Match>
 |
|||
<And>
 |
|||
<Or>
 |
|||
<Kind Is="Method" />
 |
|||
<Kind Is="Operator" />
 |
|||
</Or>
 |
|||
<Access Is="Public" />
 |
|||
</And>
 |
|||
</Entry.Match>
 |
|||
<Entry.SortBy>
 |
|||
<Static />
 |
|||
<Name />
 |
|||
</Entry.SortBy>
 |
|||
</Entry>
 |
|||
<Entry DisplayName="Interface methods">
 |
|||
<Entry.Match>
 |
|||
<And>
 |
|||
<Kind Is="Method" />
 |
|||
<ImplementsInterface />
 |
|||
</And>
 |
|||
</Entry.Match>
 |
|||
<Entry.SortBy>
 |
|||
<ImplementsInterface Immediate="True" />
 |
|||
<Name />
 |
|||
</Entry.SortBy>
 |
|||
</Entry>
 |
|||
<Entry DisplayName="Other methods">
 |
|||
<Entry.Match>
 |
|||
<Kind Is="Method" />
 |
|||
</Entry.Match>
 |
|||
<Entry.SortBy>
 |
|||
<Access Order="Public Internal ProtectedInternal Protected Private" />
 |
|||
<Static />
 |
|||
<Name />
 |
|||
</Entry.SortBy>
 |
|||
</Entry>
 |
|||
<Entry DisplayName="Operators">
 |
|||
<Entry.Match>
 |
|||
<Kind Is="Operator" />
 |
|||
</Entry.Match>
 |
|||
<Entry.SortBy>
 |
|||
<Access Order="Public Internal ProtectedInternal Protected Private" />
 |
|||
<Static />
 |
|||
<Name />
 |
|||
</Entry.SortBy>
 |
|||
</Entry>
 |
|||
<Entry Priority="600" DisplayName="Nested structs">
 |
|||
<Entry.Match>
 |
|||
<Kind Is="Struct" />
 |
|||
</Entry.Match>
 |
|||
<Entry.SortBy>
 |
|||
<Static />
 |
|||
<Access Order="Public Internal ProtectedInternal Protected Private" />
 |
|||
<Name />
 |
|||
</Entry.SortBy>
 |
|||
</Entry>
 |
|||
<Entry Priority="700" DisplayName="Nested classes">
 |
|||
<Entry.Match>
 |
|||
<Kind Is="Class" />
 |
|||
</Entry.Match>
 |
|||
<Entry.SortBy>
 |
|||
<Static />
 |
|||
<Access Order="Public Internal ProtectedInternal Protected Private" />
 |
|||
<Name />
 |
|||
</Entry.SortBy>
 |
|||
</Entry>
 |
|||
<Entry DisplayName="All other members" />
 |
|||
</TypePattern>
 |
|||
</Patterns></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.
 |
|||
// Licensed under the Apache License, Version 2.0.
 |
|||
</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"><Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /></s:String> |
|||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=EnumMember/@EntryIndexedValue"><Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /></s:String> |
|||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=Interfaces/@EntryIndexedValue"><Policy Inspect="True" Prefix="I" Suffix="" Style="AaBb" /></s:String> |
|||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=LocalConstants/@EntryIndexedValue"><Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /></s:String> |
|||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=Locals/@EntryIndexedValue"><Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /></s:String> |
|||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=MethodPropertyEvent/@EntryIndexedValue"><Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /></s:String> |
|||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=Other/@EntryIndexedValue"><Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /></s:String> |
|||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=Parameters/@EntryIndexedValue"><Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /></s:String> |
|||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateConstants/@EntryIndexedValue"><Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /></s:String> |
|||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateInstanceFields/@EntryIndexedValue"><Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /></s:String> |
|||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateStaticFields/@EntryIndexedValue"><Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /></s:String> |
|||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateStaticReadonly/@EntryIndexedValue"><Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /></s:String> |
|||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PublicFields/@EntryIndexedValue"><Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /></s:String> |
|||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=StaticReadonly/@EntryIndexedValue"><Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /></s:String> |
|||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=TypeParameters/@EntryIndexedValue"><Policy Inspect="True" Prefix="T" Suffix="" Style="AaBb" /></s:String> |
|||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=TypesAndNamespaces/@EntryIndexedValue"><Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /></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> |
|||
@ -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 |
|||
@ -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 |
|||
@ -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 } |
|||
@ -1,3 +0,0 @@ |
|||
version https://git-lfs.github.com/spec/v1 |
|||
oid sha256:148a268c589b628f5d0b5af0e86911a0b393c35b8b25233c71553657c88e0b96 |
|||
size 7568 |
|||
@ -1,3 +0,0 @@ |
|||
version https://git-lfs.github.com/spec/v1 |
|||
oid sha256:7e4b2ff72aef1979500cd130c28490a00be116bb833bc96ca30c85dc0596099c |
|||
size 15413 |
|||
@ -1,3 +0,0 @@ |
|||
version https://git-lfs.github.com/spec/v1 |
|||
oid sha256:021c12313afbdc65f58bfea8c7b436d5c2102513bb63d9e64ee2b61a1344c56a |
|||
size 1799 |
|||
@ -1,3 +0,0 @@ |
|||
version https://git-lfs.github.com/spec/v1 |
|||
oid sha256:3ae54ae0035df1f8f1459081e2f1d5cceda6f88cca6ec015d8c0209bf0d34edf |
|||
size 32534 |
|||
@ -1,3 +0,0 @@ |
|||
version https://git-lfs.github.com/spec/v1 |
|||
oid sha256:92896854265693f28f9a503b9093cb2c9a4a9b329f310732efdd9c6f6c3761bc |
|||
size 3736 |
|||
@ -1,3 +0,0 @@ |
|||
version https://git-lfs.github.com/spec/v1 |
|||
oid sha256:3ae54ae0035df1f8f1459081e2f1d5cceda6f88cca6ec015d8c0209bf0d34edf |
|||
size 32534 |
|||
|
Before Width: | Height: | Size: 2.7 KiB |
@ -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 |
|||
@ -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 |
|||
@ -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 |
|||
} |
|||
@ -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 |
|||
|
|||
@ -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 |
|||
@ -1 +1 @@ |
|||
Subproject commit faf84e44ec90e8a42a7271bcd04fea76279efb08 |
|||
Subproject commit 36b2d55f5bb0d91024955bd26ba220ee41cc96e5 |
|||
@ -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; |
|||
} |
|||
} |
|||
} |
|||
@ -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> |
|||
@ -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> |
|||
@ -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); |
|||
} |
|||
} |
|||
@ -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)) |
|||
{ |
|||
} |
|||
} |
|||
} |
|||
@ -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; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -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); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -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); |
|||
} |
|||
} |
|||
@ -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; } |
|||
} |
|||
} |
|||
@ -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; |
|||
} |
|||
} |
|||
} |
|||
@ -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); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -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))); |
|||
} |
|||
} |
|||
@ -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))); |
|||
} |
|||
} |
|||
@ -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); |
|||
} |
|||
} |
|||
@ -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); |
|||
} |
|||
} |
|||
@ -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))); |
|||
} |
|||
} |
|||
@ -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); |
|||
} |
|||
} |
|||
@ -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)); |
|||
} |
|||
} |
|||
@ -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); |
|||
} |
|||
} |
|||
@ -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); |
|||
} |
|||
} |
|||
@ -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); |
|||
} |
|||
} |
|||
@ -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))); |
|||
} |
|||
} |
|||
@ -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); |
|||
} |
|||
} |
|||
@ -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)); |
|||
} |
|||
} |
|||
@ -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); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -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 |
|||
} |
|||
} |
|||
@ -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>; |
|||
} |
|||
} |
|||
@ -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; } |
|||
} |
|||
} |
|||
@ -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); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -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; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -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; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -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); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -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; |
|||
} |
|||
} |
|||
@ -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); |
|||
} |
|||
} |
|||
@ -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); |
|||
} |
|||
} |
|||
@ -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); |
|||
} |
|||
} |
|||
} |
|||
@ -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); |
|||
} |
|||
} |
|||
@ -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); |
|||
} |
|||
} |
|||
} |
|||
@ -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); |
|||
} |
|||
} |
|||
@ -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(); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -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); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -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); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -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); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -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); |
|||
} |
|||
} |
|||
@ -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; |
|||
} |
|||
} |
|||
} |
|||
@ -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)); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue