diff --git a/.editorconfig b/.editorconfig
index 83670fa830..03036f8a53 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -1,5 +1,5 @@
-# Version: 1.6.2 (Using https://semver.org/)
-# Updated: 2020-11-02
+# Version: 2.1.0 (Using https://semver.org/)
+# Updated: 2021-03-03
# See https://github.com/RehanSaeed/EditorConfig/releases for release notes.
# See https://github.com/RehanSaeed/EditorConfig for updates to this file.
# See http://EditorConfig.org for more information about .editorconfig files.
@@ -60,87 +60,84 @@ indent_size = 2
[*.{cmd,bat}]
end_of_line = crlf
+# Bash Files
+[*.sh]
+end_of_line = lf
+
# Makefiles
[Makefile]
indent_style = tab
##########################################
-# File Header (Uncomment to support file headers)
-# https://docs.microsoft.com/visualstudio/ide/reference/add-file-header
+# Default .NET Code Style Severities
+# https://docs.microsoft.com/dotnet/fundamentals/code-analysis/configuration-options#scope
##########################################
-# [*.{cs,csx,cake,vb,vbx,tt,ttinclude}]
-file_header_template = Copyright (c) Six Labors.\nLicensed under the Apache License, Version 2.0.
-
-# SA1636: File header copyright text should match
-# Justification: .editorconfig supports file headers. If this is changed to a value other than "none", a stylecop.json file will need to added to the project.
-# dotnet_diagnostic.SA1636.severity = none
+[*.{cs,csx,cake,vb,vbx}]
+# Default Severity for all .NET Code Style rules below
+dotnet_analyzer_diagnostic.severity = warning
##########################################
-# .NET Language Conventions
-# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions
+# Language Rules
+# https://docs.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/language-rules
##########################################
-# .NET Code Style Settings
-# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#net-code-style-settings
+# .NET Style Rules
+# https://docs.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/language-rules#net-style-rules
[*.{cs,csx,cake,vb,vbx}]
# "this." and "Me." qualifiers
-# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#this-and-me
dotnet_style_qualification_for_field = true:warning
dotnet_style_qualification_for_property = true:warning
dotnet_style_qualification_for_method = true:warning
dotnet_style_qualification_for_event = true:warning
# Language keywords instead of framework type names for type references
-# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#language-keywords
dotnet_style_predefined_type_for_locals_parameters_members = true:warning
dotnet_style_predefined_type_for_member_access = true:warning
# Modifier preferences
-# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#normalize-modifiers
dotnet_style_require_accessibility_modifiers = always:warning
csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:warning
visual_basic_preferred_modifier_order = Partial,Default,Private,Protected,Public,Friend,NotOverridable,Overridable,MustOverride,Overloads,Overrides,MustInherit,NotInheritable,Static,Shared,Shadows,ReadOnly,WriteOnly,Dim,Const,WithEvents,Widening,Narrowing,Custom,Async:warning
dotnet_style_readonly_field = true:warning
# Parentheses preferences
-# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#parentheses-preferences
dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:warning
dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:warning
dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:warning
-dotnet_style_parentheses_in_other_operators = never_if_unnecessary:suggestion
+dotnet_style_parentheses_in_other_operators = always_for_clarity:suggestion
# Expression-level preferences
-# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#expression-level-preferences
dotnet_style_object_initializer = true:warning
dotnet_style_collection_initializer = true:warning
dotnet_style_explicit_tuple_names = true:warning
dotnet_style_prefer_inferred_tuple_names = true:warning
dotnet_style_prefer_inferred_anonymous_type_member_names = true:warning
dotnet_style_prefer_auto_properties = true:warning
-dotnet_style_prefer_is_null_check_over_reference_equality_method = true:warning
dotnet_style_prefer_conditional_expression_over_assignment = false:suggestion
+dotnet_diagnostic.IDE0045.severity = suggestion
dotnet_style_prefer_conditional_expression_over_return = false:suggestion
+dotnet_diagnostic.IDE0046.severity = suggestion
dotnet_style_prefer_compound_assignment = true:warning
+dotnet_style_prefer_simplified_interpolation = true:warning
+dotnet_style_prefer_simplified_boolean_expressions = true:warning
# Null-checking preferences
-# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#null-checking-preferences
dotnet_style_coalesce_expression = true:warning
dotnet_style_null_propagation = true:warning
-# Parameter preferences
-# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#parameter-preferences
-dotnet_code_quality_unused_parameters = all:warning
-# More style options (Undocumented)
-# https://github.com/MicrosoftDocs/visualstudio-docs/issues/3641
+dotnet_style_prefer_is_null_check_over_reference_equality_method = true:warning
+# File header preferences
+file_header_template = Copyright (c) Six Labors.\nLicensed under the Apache License, Version 2.0.
+# SA1636: File header copyright text should match
+# Justification: .editorconfig supports file headers. If this is changed to a value other than "none", a stylecop.json file will need to added to the project.
+# dotnet_diagnostic.SA1636.severity = none
+
+# Undocumented
dotnet_style_operator_placement_when_wrapping = end_of_line
-# https://github.com/dotnet/roslyn/pull/40070
-dotnet_style_prefer_simplified_interpolation = true:warning
-# C# Code Style Settings
-# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#c-code-style-settings
+# C# Style Rules
+# https://docs.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/language-rules#c-style-rules
[*.{cs,csx,cake}]
-# Implicit and explicit types
-# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#implicit-and-explicit-types
+# 'var' preferences
csharp_style_var_for_built_in_types = never
csharp_style_var_when_type_is_apparent = true:warning
csharp_style_var_elsewhere = false:warning
# Expression-bodied members
-# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#expression-bodied-members
csharp_style_expression_bodied_methods = true:warning
csharp_style_expression_bodied_constructors = true:warning
csharp_style_expression_bodied_operators = true:warning
@@ -149,47 +146,64 @@ csharp_style_expression_bodied_indexers = true:warning
csharp_style_expression_bodied_accessors = true:warning
csharp_style_expression_bodied_lambdas = true:warning
csharp_style_expression_bodied_local_functions = true:warning
-# Pattern matching
-# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#pattern-matching
+# Pattern matching preferences
csharp_style_pattern_matching_over_is_with_cast_check = true:warning
csharp_style_pattern_matching_over_as_with_null_check = true:warning
-# Inlined variable declarations
-# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#inlined-variable-declarations
-csharp_style_inlined_variable_declaration = true:warning
+csharp_style_prefer_switch_expression = true:warning
+csharp_style_prefer_pattern_matching = true:warning
+csharp_style_prefer_not_pattern = true:warning
# Expression-level preferences
-# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#expression-level-preferences
+csharp_style_inlined_variable_declaration = true:warning
csharp_prefer_simple_default_expression = true:warning
+csharp_style_pattern_local_over_anonymous_function = true:warning
+csharp_style_deconstructed_variable_declaration = true:warning
+csharp_style_prefer_index_operator = true:warning
+csharp_style_prefer_range_operator = true:warning
+csharp_style_implicit_object_creation_when_type_is_apparent = true:warning
# "Null" checking preferences
-# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#c-null-checking-preferences
csharp_style_throw_expression = true:warning
csharp_style_conditional_delegate_call = true:warning
# Code block preferences
-# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#code-block-preferences
csharp_prefer_braces = true:warning
-# Unused value preferences
-# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#unused-value-preferences
-csharp_style_unused_value_expression_statement_preference = discard_variable:suggestion
-csharp_style_unused_value_assignment_preference = discard_variable:suggestion
-# Index and range preferences
-# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#index-and-range-preferences
-csharp_style_prefer_index_operator = true:warning
-csharp_style_prefer_range_operator = true:warning
-# Miscellaneous preferences
-# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#miscellaneous-preferences
-csharp_style_deconstructed_variable_declaration = true:warning
-csharp_style_pattern_local_over_anonymous_function = true:warning
+csharp_prefer_simple_using_statement = true:suggestion
+dotnet_diagnostic.IDE0063.severity = suggestion
+# 'using' directive preferences
csharp_using_directive_placement = outside_namespace:warning
+# Modifier preferences
csharp_prefer_static_local_function = true:warning
-csharp_prefer_simple_using_statement = true:suggestion
##########################################
-# .NET Formatting Conventions
-# https://docs.microsoft.com/visualstudio/ide/editorconfig-code-style-settings-reference#formatting-conventions
+# Unnecessary Code Rules
+# https://docs.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/unnecessary-code-rules
##########################################
-# Organize usings
-# https://docs.microsoft.com/visualstudio/ide/editorconfig-formatting-conventions#organize-using-directives
+# .NET Unnecessary code rules
+[*.{cs,csx,cake,vb,vbx}]
+dotnet_code_quality_unused_parameters = all:warning
+dotnet_remove_unnecessary_suppression_exclusions = none:warning
+
+# C# Unnecessary code rules
+[*.{cs,csx,cake}]
+csharp_style_unused_value_expression_statement_preference = discard_variable:suggestion
+dotnet_diagnostic.IDE0058.severity = suggestion
+csharp_style_unused_value_assignment_preference = discard_variable:suggestion
+dotnet_diagnostic.IDE0059.severity = suggestion
+
+##########################################
+# Formatting Rules
+# https://docs.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/formatting-rules
+##########################################
+
+# .NET formatting rules
+# https://docs.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/formatting-rules#net-formatting-rules
+[*.{cs,csx,cake,vb,vbx}]
+# Organize using directives
dotnet_sort_system_directives_first = true
+dotnet_separate_import_directive_groups = false
+
+# C# formatting rules
+# https://docs.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/formatting-rules#c-formatting-rules
+[*.{cs,csx,cake}]
# Newline options
# https://docs.microsoft.com/visualstudio/ide/editorconfig-formatting-conventions#new-line-options
csharp_new_line_before_open_brace = all
@@ -231,14 +245,14 @@ csharp_space_around_declaration_statements = false
csharp_space_before_open_square_brackets = false
csharp_space_between_empty_square_brackets = false
csharp_space_between_square_brackets = false
-# Wrapping options
+# Wrap options
# https://docs.microsoft.com/visualstudio/ide/editorconfig-formatting-conventions#wrap-options
csharp_preserve_single_line_statements = false
csharp_preserve_single_line_blocks = true
##########################################
-# .NET Naming Conventions
-# https://docs.microsoft.com/visualstudio/ide/editorconfig-naming-conventions
+# .NET Naming Rules
+# https://docs.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/naming-rules
##########################################
[*.{cs,csx,cake,vb,vbx}]
@@ -261,8 +275,9 @@ dotnet_naming_style.prefix_type_parameters_with_t_style.capitalization = pascal_
dotnet_naming_style.prefix_type_parameters_with_t_style.required_prefix = T
# disallowed_style - Anything that has this style applied is marked as disallowed
dotnet_naming_style.disallowed_style.capitalization = pascal_case
-dotnet_naming_style.disallowed_style.required_prefix = ____RULE_VIOLATION____
-dotnet_naming_style.disallowed_style.required_suffix = ____RULE_VIOLATION____
+# Disabled while we investigate compatibility with VS 16.10
+#dotnet_naming_style.disallowed_style.required_prefix = ____RULE_VIOLATION____
+#dotnet_naming_style.disallowed_style.required_suffix = ____RULE_VIOLATION____
# internal_error_style - This style should never occur... if it does, it indicates a bug in file or in the parser using the file
dotnet_naming_style.internal_error_style.capitalization = pascal_case
dotnet_naming_style.internal_error_style.required_prefix = ____INTERNAL_ERROR____
diff --git a/.gitattributes b/.gitattributes
index 416dd0d06f..70ced69033 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -86,7 +86,6 @@
*.dll binary
*.eot binary
*.exe binary
-*.ktx binary
*.otf binary
*.pbm binary
*.pdf binary
@@ -125,3 +124,5 @@
*.tga filter=lfs diff=lfs merge=lfs -text
*.webp filter=lfs diff=lfs merge=lfs -text
*.dds filter=lfs diff=lfs merge=lfs -text
+*.ktx filter=lfs diff=lfs merge=lfs -text
+*.ktx2 filter=lfs diff=lfs merge=lfs -text
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
index 4be3511650..8709e1318d 100644
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -2,7 +2,7 @@
- [ ] I have written a descriptive pull-request title
- [ ] I have verified that there are no overlapping [pull-requests](https://github.com/SixLabors/ImageSharp/pulls) open
-- [ ] I have verified that I am following matches the existing coding patterns and practice as demonstrated in the repository. These follow strict Stylecop rules :cop:.
+- [ ] I have verified that I am following the existing coding patterns and practice as demonstrated in the repository. These follow strict Stylecop rules :cop:.
- [ ] I have provided test coverage for my change (where applicable)
### Description
diff --git a/Directory.Build.props b/Directory.Build.props
index 3a133efe7a..3df93fcd40 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -18,4 +18,13 @@
+
+
+ false
+
+
+
+ true
+
+
diff --git a/ImageSharp.sln b/ImageSharp.sln
index c640478be9..a8a69d128c 100644
--- a/ImageSharp.sln
+++ b/ImageSharp.sln
@@ -623,9 +623,15 @@ Global
Debug|Any CPU = Debug|Any CPU
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
+ Debug-InnerLoop|Any CPU = Debug-InnerLoop|Any CPU
+ Debug-InnerLoop|x64 = Debug-InnerLoop|x64
+ Debug-InnerLoop|x86 = Debug-InnerLoop|x86
Release|Any CPU = Release|Any CPU
Release|x64 = Release|x64
Release|x86 = Release|x86
+ Release-InnerLoop|Any CPU = Release-InnerLoop|Any CPU
+ Release-InnerLoop|x64 = Release-InnerLoop|x64
+ Release-InnerLoop|x86 = Release-InnerLoop|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{2AA31A1F-142C-43F4-8687-09ABCA4B3A26}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
@@ -634,48 +640,96 @@ Global
{2AA31A1F-142C-43F4-8687-09ABCA4B3A26}.Debug|x64.Build.0 = Debug|Any CPU
{2AA31A1F-142C-43F4-8687-09ABCA4B3A26}.Debug|x86.ActiveCfg = Debug|Any CPU
{2AA31A1F-142C-43F4-8687-09ABCA4B3A26}.Debug|x86.Build.0 = Debug|Any CPU
+ {2AA31A1F-142C-43F4-8687-09ABCA4B3A26}.Debug-InnerLoop|Any CPU.ActiveCfg = Debug-InnerLoop|Any CPU
+ {2AA31A1F-142C-43F4-8687-09ABCA4B3A26}.Debug-InnerLoop|Any CPU.Build.0 = Debug-InnerLoop|Any CPU
+ {2AA31A1F-142C-43F4-8687-09ABCA4B3A26}.Debug-InnerLoop|x64.ActiveCfg = Debug-InnerLoop|Any CPU
+ {2AA31A1F-142C-43F4-8687-09ABCA4B3A26}.Debug-InnerLoop|x64.Build.0 = Debug-InnerLoop|Any CPU
+ {2AA31A1F-142C-43F4-8687-09ABCA4B3A26}.Debug-InnerLoop|x86.ActiveCfg = Debug-InnerLoop|Any CPU
+ {2AA31A1F-142C-43F4-8687-09ABCA4B3A26}.Debug-InnerLoop|x86.Build.0 = Debug-InnerLoop|Any CPU
{2AA31A1F-142C-43F4-8687-09ABCA4B3A26}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2AA31A1F-142C-43F4-8687-09ABCA4B3A26}.Release|Any CPU.Build.0 = Release|Any CPU
{2AA31A1F-142C-43F4-8687-09ABCA4B3A26}.Release|x64.ActiveCfg = Release|Any CPU
{2AA31A1F-142C-43F4-8687-09ABCA4B3A26}.Release|x64.Build.0 = Release|Any CPU
{2AA31A1F-142C-43F4-8687-09ABCA4B3A26}.Release|x86.ActiveCfg = Release|Any CPU
{2AA31A1F-142C-43F4-8687-09ABCA4B3A26}.Release|x86.Build.0 = Release|Any CPU
+ {2AA31A1F-142C-43F4-8687-09ABCA4B3A26}.Release-InnerLoop|Any CPU.ActiveCfg = Release-InnerLoop|Any CPU
+ {2AA31A1F-142C-43F4-8687-09ABCA4B3A26}.Release-InnerLoop|Any CPU.Build.0 = Release-InnerLoop|Any CPU
+ {2AA31A1F-142C-43F4-8687-09ABCA4B3A26}.Release-InnerLoop|x64.ActiveCfg = Release-InnerLoop|Any CPU
+ {2AA31A1F-142C-43F4-8687-09ABCA4B3A26}.Release-InnerLoop|x64.Build.0 = Release-InnerLoop|Any CPU
+ {2AA31A1F-142C-43F4-8687-09ABCA4B3A26}.Release-InnerLoop|x86.ActiveCfg = Release-InnerLoop|Any CPU
+ {2AA31A1F-142C-43F4-8687-09ABCA4B3A26}.Release-InnerLoop|x86.Build.0 = Release-InnerLoop|Any CPU
{EA3000E9-2A91-4EC4-8A68-E566DEBDC4F6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EA3000E9-2A91-4EC4-8A68-E566DEBDC4F6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EA3000E9-2A91-4EC4-8A68-E566DEBDC4F6}.Debug|x64.ActiveCfg = Debug|Any CPU
{EA3000E9-2A91-4EC4-8A68-E566DEBDC4F6}.Debug|x64.Build.0 = Debug|Any CPU
{EA3000E9-2A91-4EC4-8A68-E566DEBDC4F6}.Debug|x86.ActiveCfg = Debug|Any CPU
{EA3000E9-2A91-4EC4-8A68-E566DEBDC4F6}.Debug|x86.Build.0 = Debug|Any CPU
+ {EA3000E9-2A91-4EC4-8A68-E566DEBDC4F6}.Debug-InnerLoop|Any CPU.ActiveCfg = Debug-InnerLoop|Any CPU
+ {EA3000E9-2A91-4EC4-8A68-E566DEBDC4F6}.Debug-InnerLoop|Any CPU.Build.0 = Debug-InnerLoop|Any CPU
+ {EA3000E9-2A91-4EC4-8A68-E566DEBDC4F6}.Debug-InnerLoop|x64.ActiveCfg = Debug-InnerLoop|x64
+ {EA3000E9-2A91-4EC4-8A68-E566DEBDC4F6}.Debug-InnerLoop|x64.Build.0 = Debug-InnerLoop|x64
+ {EA3000E9-2A91-4EC4-8A68-E566DEBDC4F6}.Debug-InnerLoop|x86.ActiveCfg = Debug-InnerLoop|x86
+ {EA3000E9-2A91-4EC4-8A68-E566DEBDC4F6}.Debug-InnerLoop|x86.Build.0 = Debug-InnerLoop|x86
{EA3000E9-2A91-4EC4-8A68-E566DEBDC4F6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EA3000E9-2A91-4EC4-8A68-E566DEBDC4F6}.Release|Any CPU.Build.0 = Release|Any CPU
{EA3000E9-2A91-4EC4-8A68-E566DEBDC4F6}.Release|x64.ActiveCfg = Release|Any CPU
{EA3000E9-2A91-4EC4-8A68-E566DEBDC4F6}.Release|x64.Build.0 = Release|Any CPU
{EA3000E9-2A91-4EC4-8A68-E566DEBDC4F6}.Release|x86.ActiveCfg = Release|Any CPU
{EA3000E9-2A91-4EC4-8A68-E566DEBDC4F6}.Release|x86.Build.0 = Release|Any CPU
+ {EA3000E9-2A91-4EC4-8A68-E566DEBDC4F6}.Release-InnerLoop|Any CPU.ActiveCfg = Release-InnerLoop|Any CPU
+ {EA3000E9-2A91-4EC4-8A68-E566DEBDC4F6}.Release-InnerLoop|Any CPU.Build.0 = Release-InnerLoop|Any CPU
+ {EA3000E9-2A91-4EC4-8A68-E566DEBDC4F6}.Release-InnerLoop|x64.ActiveCfg = Release-InnerLoop|x64
+ {EA3000E9-2A91-4EC4-8A68-E566DEBDC4F6}.Release-InnerLoop|x64.Build.0 = Release-InnerLoop|x64
+ {EA3000E9-2A91-4EC4-8A68-E566DEBDC4F6}.Release-InnerLoop|x86.ActiveCfg = Release-InnerLoop|x86
+ {EA3000E9-2A91-4EC4-8A68-E566DEBDC4F6}.Release-InnerLoop|x86.Build.0 = Release-InnerLoop|x86
{2BF743D8-2A06-412D-96D7-F448F00C5EA5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2BF743D8-2A06-412D-96D7-F448F00C5EA5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2BF743D8-2A06-412D-96D7-F448F00C5EA5}.Debug|x64.ActiveCfg = Debug|Any CPU
{2BF743D8-2A06-412D-96D7-F448F00C5EA5}.Debug|x64.Build.0 = Debug|Any CPU
{2BF743D8-2A06-412D-96D7-F448F00C5EA5}.Debug|x86.ActiveCfg = Debug|Any CPU
{2BF743D8-2A06-412D-96D7-F448F00C5EA5}.Debug|x86.Build.0 = Debug|Any CPU
+ {2BF743D8-2A06-412D-96D7-F448F00C5EA5}.Debug-InnerLoop|Any CPU.ActiveCfg = Debug-InnerLoop|Any CPU
+ {2BF743D8-2A06-412D-96D7-F448F00C5EA5}.Debug-InnerLoop|Any CPU.Build.0 = Debug-InnerLoop|Any CPU
+ {2BF743D8-2A06-412D-96D7-F448F00C5EA5}.Debug-InnerLoop|x64.ActiveCfg = Debug-InnerLoop|Any CPU
+ {2BF743D8-2A06-412D-96D7-F448F00C5EA5}.Debug-InnerLoop|x64.Build.0 = Debug-InnerLoop|Any CPU
+ {2BF743D8-2A06-412D-96D7-F448F00C5EA5}.Debug-InnerLoop|x86.ActiveCfg = Debug-InnerLoop|Any CPU
+ {2BF743D8-2A06-412D-96D7-F448F00C5EA5}.Debug-InnerLoop|x86.Build.0 = Debug-InnerLoop|Any CPU
{2BF743D8-2A06-412D-96D7-F448F00C5EA5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2BF743D8-2A06-412D-96D7-F448F00C5EA5}.Release|Any CPU.Build.0 = Release|Any CPU
{2BF743D8-2A06-412D-96D7-F448F00C5EA5}.Release|x64.ActiveCfg = Release|Any CPU
{2BF743D8-2A06-412D-96D7-F448F00C5EA5}.Release|x64.Build.0 = Release|Any CPU
{2BF743D8-2A06-412D-96D7-F448F00C5EA5}.Release|x86.ActiveCfg = Release|Any CPU
{2BF743D8-2A06-412D-96D7-F448F00C5EA5}.Release|x86.Build.0 = Release|Any CPU
+ {2BF743D8-2A06-412D-96D7-F448F00C5EA5}.Release-InnerLoop|Any CPU.ActiveCfg = Release-InnerLoop|Any CPU
+ {2BF743D8-2A06-412D-96D7-F448F00C5EA5}.Release-InnerLoop|Any CPU.Build.0 = Release-InnerLoop|Any CPU
+ {2BF743D8-2A06-412D-96D7-F448F00C5EA5}.Release-InnerLoop|x64.ActiveCfg = Release-InnerLoop|Any CPU
+ {2BF743D8-2A06-412D-96D7-F448F00C5EA5}.Release-InnerLoop|x64.Build.0 = Release-InnerLoop|Any CPU
+ {2BF743D8-2A06-412D-96D7-F448F00C5EA5}.Release-InnerLoop|x86.ActiveCfg = Release-InnerLoop|Any CPU
+ {2BF743D8-2A06-412D-96D7-F448F00C5EA5}.Release-InnerLoop|x86.Build.0 = Release-InnerLoop|Any CPU
{FC527290-2F22-432C-B77B-6E815726B02C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FC527290-2F22-432C-B77B-6E815726B02C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FC527290-2F22-432C-B77B-6E815726B02C}.Debug|x64.ActiveCfg = Debug|Any CPU
{FC527290-2F22-432C-B77B-6E815726B02C}.Debug|x64.Build.0 = Debug|Any CPU
{FC527290-2F22-432C-B77B-6E815726B02C}.Debug|x86.ActiveCfg = Debug|Any CPU
{FC527290-2F22-432C-B77B-6E815726B02C}.Debug|x86.Build.0 = Debug|Any CPU
+ {FC527290-2F22-432C-B77B-6E815726B02C}.Debug-InnerLoop|Any CPU.ActiveCfg = Debug-InnerLoop|Any CPU
+ {FC527290-2F22-432C-B77B-6E815726B02C}.Debug-InnerLoop|Any CPU.Build.0 = Debug-InnerLoop|Any CPU
+ {FC527290-2F22-432C-B77B-6E815726B02C}.Debug-InnerLoop|x64.ActiveCfg = Debug-InnerLoop|Any CPU
+ {FC527290-2F22-432C-B77B-6E815726B02C}.Debug-InnerLoop|x64.Build.0 = Debug-InnerLoop|Any CPU
+ {FC527290-2F22-432C-B77B-6E815726B02C}.Debug-InnerLoop|x86.ActiveCfg = Debug-InnerLoop|Any CPU
+ {FC527290-2F22-432C-B77B-6E815726B02C}.Debug-InnerLoop|x86.Build.0 = Debug-InnerLoop|Any CPU
{FC527290-2F22-432C-B77B-6E815726B02C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FC527290-2F22-432C-B77B-6E815726B02C}.Release|Any CPU.Build.0 = Release|Any CPU
{FC527290-2F22-432C-B77B-6E815726B02C}.Release|x64.ActiveCfg = Release|Any CPU
{FC527290-2F22-432C-B77B-6E815726B02C}.Release|x64.Build.0 = Release|Any CPU
{FC527290-2F22-432C-B77B-6E815726B02C}.Release|x86.ActiveCfg = Release|Any CPU
{FC527290-2F22-432C-B77B-6E815726B02C}.Release|x86.Build.0 = Release|Any CPU
+ {FC527290-2F22-432C-B77B-6E815726B02C}.Release-InnerLoop|Any CPU.ActiveCfg = Release-InnerLoop|Any CPU
+ {FC527290-2F22-432C-B77B-6E815726B02C}.Release-InnerLoop|Any CPU.Build.0 = Release-InnerLoop|Any CPU
+ {FC527290-2F22-432C-B77B-6E815726B02C}.Release-InnerLoop|x64.ActiveCfg = Release-InnerLoop|Any CPU
+ {FC527290-2F22-432C-B77B-6E815726B02C}.Release-InnerLoop|x64.Build.0 = Release-InnerLoop|Any CPU
+ {FC527290-2F22-432C-B77B-6E815726B02C}.Release-InnerLoop|x86.ActiveCfg = Release-InnerLoop|Any CPU
+ {FC527290-2F22-432C-B77B-6E815726B02C}.Release-InnerLoop|x86.Build.0 = Release-InnerLoop|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/shared-infrastructure b/shared-infrastructure
index 9b1179f0eb..41fff7bf7d 160000
--- a/shared-infrastructure
+++ b/shared-infrastructure
@@ -1 +1 @@
-Subproject commit 9b1179f0ebe6a4dfed998252b860fa07fee54363
+Subproject commit 41fff7bf7ddb1d118898db1ddba43b95ba6ed0bb
diff --git a/src/ImageSharp/Common/Helpers/RuntimeEnvironment.cs b/src/ImageSharp/Common/Helpers/RuntimeEnvironment.cs
new file mode 100644
index 0000000000..5525d3de50
--- /dev/null
+++ b/src/ImageSharp/Common/Helpers/RuntimeEnvironment.cs
@@ -0,0 +1,32 @@
+// Copyright (c) Six Labors.
+// Licensed under the Apache License, Version 2.0.
+
+using System;
+using System.Runtime.InteropServices;
+
+namespace SixLabors.ImageSharp
+{
+ ///
+ /// Provides information about the .NET runtime installation.
+ /// Many methods defer to when available.
+ ///
+ internal static class RuntimeEnvironment
+ {
+ private static readonly Lazy IsNetCoreLazy = new Lazy(() => FrameworkDescription.StartsWith(".NET Core", StringComparison.OrdinalIgnoreCase));
+
+ ///
+ /// Gets a value indicating whether the .NET installation is .NET Core 3.1 or lower.
+ ///
+ public static bool IsNetCore => IsNetCoreLazy.Value;
+
+ ///
+ /// Gets the name of the .NET installation on which an app is running.
+ ///
+ public static string FrameworkDescription => RuntimeInformation.FrameworkDescription;
+
+ ///
+ /// Indicates whether the current application is running on the specified platform.
+ ///
+ public static bool IsOSPlatform(OSPlatform osPlatform) => RuntimeInformation.IsOSPlatform(osPlatform);
+ }
+}
diff --git a/src/ImageSharp/ImageSharp.csproj b/src/ImageSharp/ImageSharp.csproj
index 832d551fd7..510f34dc7d 100644
--- a/src/ImageSharp/ImageSharp.csproj
+++ b/src/ImageSharp/ImageSharp.csproj
@@ -12,6 +12,7 @@
$(RepositoryUrl)
Image Resize Crop Gif Jpg Jpeg Bitmap Png Tga NetCore
A new, fully featured, fully managed, cross-platform, 2D graphics API for .NET
+ Debug;Release;Release-InnerLoop;Debug-InnerLoop
@@ -20,6 +21,11 @@
net5.0;netcoreapp3.1;netcoreapp2.1;netstandard2.1;netstandard2.0;netstandard1.3;net472
+
+
+ netcoreapp3.1
+
+
netcoreapp3.1;netcoreapp2.1;netstandard2.1;netstandard2.0;netstandard1.3;net472
diff --git a/src/ImageSharp/Processing/Processors/Transforms/Linear/AffineTransformProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Transforms/Linear/AffineTransformProcessor{TPixel}.cs
index c08f5d3d3b..5f04918e09 100644
--- a/src/ImageSharp/Processing/Processors/Transforms/Linear/AffineTransformProcessor{TPixel}.cs
+++ b/src/ImageSharp/Processing/Processors/Transforms/Linear/AffineTransformProcessor{TPixel}.cs
@@ -2,6 +2,8 @@
// Licensed under the Apache License, Version 2.0.
using System;
+using System.Buffers;
+using System.Diagnostics.CodeAnalysis;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
@@ -80,32 +82,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
return;
}
- int yRadius = LinearTransformUtils.GetSamplingRadius(in sampler, source.Height, destination.Height);
- int xRadius = LinearTransformUtils.GetSamplingRadius(in sampler, source.Width, destination.Width);
- var radialExtents = new Vector2(xRadius, yRadius);
- int yLength = (yRadius * 2) + 1;
- int xLength = (xRadius * 2) + 1;
-
- // We use 2D buffers so that we can access the weight spans per row in parallel.
- using Buffer2D yKernelBuffer = configuration.MemoryAllocator.Allocate2D(yLength, destination.Height);
- using Buffer2D xKernelBuffer = configuration.MemoryAllocator.Allocate2D(xLength, destination.Height);
-
- int maxX = source.Width - 1;
- int maxY = source.Height - 1;
- var maxSourceExtents = new Vector4(maxX, maxY, maxX, maxY);
-
var operation = new AffineOperation(
configuration,
source,
destination,
- yKernelBuffer,
- xKernelBuffer,
in sampler,
- matrix,
- radialExtents,
- maxSourceExtents);
+ matrix);
- ParallelRowIterator.IterateRows, Vector4>(
+ ParallelRowIterator.IterateRowIntervals, Vector4>(
configuration,
destination.Bounds(),
in operation);
@@ -117,7 +101,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
private readonly ImageFrame destination;
private readonly Rectangle bounds;
private readonly Matrix3x2 matrix;
- private readonly int maxX;
[MethodImpl(InliningOptions.ShortMethod)]
public NNAffineOperation(
@@ -129,15 +112,15 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
this.destination = destination;
this.bounds = source.Bounds();
this.matrix = matrix;
- this.maxX = destination.Width;
}
[MethodImpl(InliningOptions.ShortMethod)]
public void Invoke(int y)
{
+ Buffer2D sourceBuffer = this.source.PixelBuffer;
Span destRow = this.destination.GetPixelRowSpan(y);
- for (int x = 0; x < this.maxX; x++)
+ for (int x = 0; x < destRow.Length; x++)
{
var point = Vector2.Transform(new Vector2(x, y), this.matrix);
int px = (int)MathF.Round(point.X);
@@ -145,84 +128,181 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
if (this.bounds.Contains(px, py))
{
- destRow[x] = this.source[px, py];
+ destRow[x] = sourceBuffer.GetElementUnsafe(px, py);
}
}
}
}
- private readonly struct AffineOperation : IRowOperation
+ private readonly struct AffineOperation : IRowIntervalOperation
where TResampler : struct, IResampler
{
private readonly Configuration configuration;
private readonly ImageFrame source;
private readonly ImageFrame destination;
- private readonly Buffer2D yKernelBuffer;
- private readonly Buffer2D xKernelBuffer;
private readonly TResampler sampler;
private readonly Matrix3x2 matrix;
- private readonly Vector2 radialExtents;
- private readonly Vector4 maxSourceExtents;
- private readonly int maxX;
+ private readonly float yRadius;
+ private readonly float xRadius;
[MethodImpl(InliningOptions.ShortMethod)]
public AffineOperation(
Configuration configuration,
ImageFrame source,
ImageFrame destination,
- Buffer2D yKernelBuffer,
- Buffer2D xKernelBuffer,
in TResampler sampler,
- Matrix3x2 matrix,
- Vector2 radialExtents,
- Vector4 maxSourceExtents)
+ Matrix3x2 matrix)
{
this.configuration = configuration;
this.source = source;
this.destination = destination;
- this.yKernelBuffer = yKernelBuffer;
- this.xKernelBuffer = xKernelBuffer;
this.sampler = sampler;
this.matrix = matrix;
- this.radialExtents = radialExtents;
- this.maxSourceExtents = maxSourceExtents;
- this.maxX = destination.Width;
+
+ this.yRadius = LinearTransformUtility.GetSamplingRadius(in sampler, source.Height, destination.Height);
+ this.xRadius = LinearTransformUtility.GetSamplingRadius(in sampler, source.Width, destination.Width);
}
[MethodImpl(InliningOptions.ShortMethod)]
- public void Invoke(int y, Span span)
+ public void Invoke(in RowInterval rows, Span span)
{
- Buffer2D sourceBuffer = this.source.PixelBuffer;
+ if (RuntimeEnvironment.IsOSPlatform(OSPlatform.OSX)
+ && RuntimeEnvironment.IsNetCore)
+ {
+ // There's something wrong with the JIT in .NET Core 3.1 on certain
+ // MacOSX machines so we have to use different pipelines.
+ // It's:
+ // - Not reproducable locally
+ // - Doesn't seem to be triggered by the bulk Numerics.UnPremultiply method but by caller.
+ // https://github.com/SixLabors/ImageSharp/pull/1591
+ this.InvokeMacOSX(in rows, span);
+ return;
+ }
- PixelOperations.Instance.ToVector4(
- this.configuration,
- this.destination.GetPixelRowSpan(y),
- span);
+ Matrix3x2 matrix = this.matrix;
+ TResampler sampler = this.sampler;
+ float yRadius = this.yRadius;
+ float xRadius = this.xRadius;
+ int maxY = this.source.Height - 1;
+ int maxX = this.source.Width - 1;
- ref float yKernelSpanRef = ref MemoryMarshal.GetReference(this.yKernelBuffer.GetRowSpan(y));
- ref float xKernelSpanRef = ref MemoryMarshal.GetReference(this.xKernelBuffer.GetRowSpan(y));
+ Buffer2D sourceBuffer = this.source.PixelBuffer;
- for (int x = 0; x < this.maxX; x++)
+ for (int y = rows.Min; y < rows.Max; y++)
{
- // Use the single precision position to calculate correct bounding pixels
- // otherwise we get rogue pixels outside of the bounds.
- var point = Vector2.Transform(new Vector2(x, y), this.matrix);
- LinearTransformUtils.Convolve(
- in this.sampler,
- point,
- sourceBuffer,
+ Span rowSpan = this.destination.GetPixelRowSpan(y);
+ PixelOperations.Instance.ToVector4(
+ this.configuration,
+ rowSpan,
+ span,
+ PixelConversionModifiers.Scale);
+
+ for (int x = 0; x < span.Length; x++)
+ {
+ var point = Vector2.Transform(new Vector2(x, y), matrix);
+ float pY = point.Y;
+ float pX = point.X;
+
+ int top = LinearTransformUtility.GetRangeStart(yRadius, pY, maxY);
+ int bottom = LinearTransformUtility.GetRangeEnd(yRadius, pY, maxY);
+ int left = LinearTransformUtility.GetRangeStart(xRadius, pX, maxX);
+ int right = LinearTransformUtility.GetRangeEnd(xRadius, pX, maxX);
+
+ if (bottom == top || right == left)
+ {
+ continue;
+ }
+
+ Vector4 sum = Vector4.Zero;
+ for (int yK = top; yK <= bottom; yK++)
+ {
+ float yWeight = sampler.GetValue(yK - pY);
+
+ for (int xK = left; xK <= right; xK++)
+ {
+ float xWeight = sampler.GetValue(xK - pX);
+
+ Vector4 current = sourceBuffer.GetElementUnsafe(xK, yK).ToScaledVector4();
+ Numerics.Premultiply(ref current);
+ sum += current * xWeight * yWeight;
+ }
+ }
+
+ span[x] = sum;
+ }
+
+ Numerics.UnPremultiply(span);
+ PixelOperations.Instance.FromVector4Destructive(
+ this.configuration,
span,
- x,
- ref yKernelSpanRef,
- ref xKernelSpanRef,
- this.radialExtents,
- this.maxSourceExtents);
+ rowSpan,
+ PixelConversionModifiers.Scale);
}
+ }
+
+ [ExcludeFromCodeCoverage]
+ [MethodImpl(InliningOptions.ShortMethod)]
+ private void InvokeMacOSX(in RowInterval rows, Span span)
+ {
+ Matrix3x2 matrix = this.matrix;
+ TResampler sampler = this.sampler;
+ float yRadius = this.yRadius;
+ float xRadius = this.xRadius;
+ int maxY = this.source.Height - 1;
+ int maxX = this.source.Width - 1;
- PixelOperations.Instance.FromVector4Destructive(
- this.configuration,
- span,
- this.destination.GetPixelRowSpan(y));
+ Buffer2D sourceBuffer = this.source.PixelBuffer;
+
+ for (int y = rows.Min; y < rows.Max; y++)
+ {
+ Span rowSpan = this.destination.GetPixelRowSpan(y);
+ PixelOperations.Instance.ToVector4(
+ this.configuration,
+ rowSpan,
+ span,
+ PixelConversionModifiers.Scale);
+
+ for (int x = 0; x < span.Length; x++)
+ {
+ var point = Vector2.Transform(new Vector2(x, y), matrix);
+ float pY = point.Y;
+ float pX = point.X;
+
+ int top = LinearTransformUtility.GetRangeStart(yRadius, pY, maxY);
+ int bottom = LinearTransformUtility.GetRangeEnd(yRadius, pY, maxY);
+ int left = LinearTransformUtility.GetRangeStart(xRadius, pX, maxX);
+ int right = LinearTransformUtility.GetRangeEnd(xRadius, pX, maxX);
+
+ if (bottom == top || right == left)
+ {
+ continue;
+ }
+
+ Vector4 sum = Vector4.Zero;
+ for (int yK = top; yK <= bottom; yK++)
+ {
+ float yWeight = sampler.GetValue(yK - pY);
+
+ for (int xK = left; xK <= right; xK++)
+ {
+ float xWeight = sampler.GetValue(xK - pX);
+
+ Vector4 current = sourceBuffer.GetElementUnsafe(xK, yK).ToScaledVector4();
+ Numerics.Premultiply(ref current);
+ sum += current * xWeight * yWeight;
+ }
+ }
+
+ Numerics.UnPremultiply(ref sum);
+ span[x] = sum;
+ }
+
+ PixelOperations.Instance.FromVector4Destructive(
+ this.configuration,
+ span,
+ rowSpan,
+ PixelConversionModifiers.Scale);
+ }
}
}
}
diff --git a/src/ImageSharp/Processing/Processors/Transforms/Linear/LinearTransformUtility.cs b/src/ImageSharp/Processing/Processors/Transforms/Linear/LinearTransformUtility.cs
new file mode 100644
index 0000000000..c6168b4619
--- /dev/null
+++ b/src/ImageSharp/Processing/Processors/Transforms/Linear/LinearTransformUtility.cs
@@ -0,0 +1,60 @@
+// Copyright (c) Six Labors.
+// Licensed under the Apache License, Version 2.0.
+
+using System;
+using System.Runtime.CompilerServices;
+
+namespace SixLabors.ImageSharp.Processing.Processors.Transforms
+{
+ ///
+ /// Utility methods for linear transforms.
+ ///
+ internal static class LinearTransformUtility
+ {
+ ///
+ /// Returns the sampling radius for the given sampler and dimensions.
+ ///
+ /// The type of resampler.
+ /// The resampler sampler.
+ /// The source size.
+ /// The destination size.
+ /// The .
+ [MethodImpl(InliningOptions.ShortMethod)]
+ public static float GetSamplingRadius(in TResampler sampler, int sourceSize, int destinationSize)
+ where TResampler : struct, IResampler
+ {
+ float scale = (float)sourceSize / destinationSize;
+
+ if (scale < 1F)
+ {
+ scale = 1F;
+ }
+
+ return MathF.Ceiling(sampler.Radius * scale);
+ }
+
+ ///
+ /// Gets the start position (inclusive) for a sampling range given
+ /// the radius, center position and max constraint.
+ ///
+ /// The radius.
+ /// The center position.
+ /// The max allowed amouunt.
+ /// The .
+ [MethodImpl(InliningOptions.ShortMethod)]
+ public static int GetRangeStart(float radius, float center, int max)
+ => Numerics.Clamp((int)MathF.Ceiling(center - radius), 0, max);
+
+ ///
+ /// Gets the end position (inclusive) for a sampling range given
+ /// the radius, center position and max constraint.
+ ///
+ /// The radius.
+ /// The center position.
+ /// The max allowed amouunt.
+ /// The .
+ [MethodImpl(InliningOptions.ShortMethod)]
+ public static int GetRangeEnd(float radius, float center, int max)
+ => Numerics.Clamp((int)MathF.Floor(center + radius), 0, max);
+ }
+}
diff --git a/src/ImageSharp/Processing/Processors/Transforms/Linear/LinearTransformUtils.cs b/src/ImageSharp/Processing/Processors/Transforms/Linear/LinearTransformUtils.cs
deleted file mode 100644
index e65b2cbe92..0000000000
--- a/src/ImageSharp/Processing/Processors/Transforms/Linear/LinearTransformUtils.cs
+++ /dev/null
@@ -1,104 +0,0 @@
-// Copyright (c) Six Labors.
-// Licensed under the Apache License, Version 2.0.
-
-using System;
-using System.Numerics;
-using System.Runtime.CompilerServices;
-using SixLabors.ImageSharp.Memory;
-using SixLabors.ImageSharp.PixelFormats;
-
-namespace SixLabors.ImageSharp.Processing.Processors.Transforms
-{
- ///
- /// Utility methods for affine and projective transforms.
- ///
- internal static class LinearTransformUtils
- {
- [MethodImpl(InliningOptions.ShortMethod)]
- internal static int GetSamplingRadius(in TResampler sampler, int sourceSize, int destinationSize)
- where TResampler : struct, IResampler
- {
- double scale = sourceSize / destinationSize;
- if (scale < 1)
- {
- scale = 1;
- }
-
- return (int)Math.Ceiling(scale * sampler.Radius);
- }
-
- [MethodImpl(InliningOptions.ShortMethod)]
- internal static void Convolve(
- in TResampler sampler,
- Vector2 transformedPoint,
- Buffer2D sourcePixels,
- Span targetRow,
- int column,
- ref float yKernelSpanRef,
- ref float xKernelSpanRef,
- Vector2 radialExtents,
- Vector4 maxSourceExtents)
- where TResampler : struct, IResampler
- where TPixel : unmanaged, IPixel
- {
- // Clamp sampling pixel radial extents to the source image edges
- Vector2 minXY = transformedPoint - radialExtents;
- Vector2 maxXY = transformedPoint + radialExtents;
-
- // left, top, right, bottom
- var sourceExtents = new Vector4(
- MathF.Ceiling(minXY.X),
- MathF.Ceiling(minXY.Y),
- MathF.Floor(maxXY.X),
- MathF.Floor(maxXY.Y));
-
- sourceExtents = Numerics.Clamp(sourceExtents, Vector4.Zero, maxSourceExtents);
-
- int left = (int)sourceExtents.X;
- int top = (int)sourceExtents.Y;
- int right = (int)sourceExtents.Z;
- int bottom = (int)sourceExtents.W;
-
- if (left == right || top == bottom)
- {
- return;
- }
-
- CalculateWeights(in sampler, top, bottom, transformedPoint.Y, ref yKernelSpanRef);
- CalculateWeights(in sampler, left, right, transformedPoint.X, ref xKernelSpanRef);
-
- Vector4 sum = Vector4.Zero;
- for (int kernelY = 0, y = top; y <= bottom; y++, kernelY++)
- {
- float yWeight = Unsafe.Add(ref yKernelSpanRef, kernelY);
-
- for (int kernelX = 0, x = left; x <= right; x++, kernelX++)
- {
- float xWeight = Unsafe.Add(ref xKernelSpanRef, kernelX);
-
- // Values are first premultiplied to prevent darkening of edge pixels.
- var current = sourcePixels[x, y].ToVector4();
- Numerics.Premultiply(ref current);
- sum += current * xWeight * yWeight;
- }
- }
-
- // Reverse the premultiplication
- Numerics.UnPremultiply(ref sum);
- targetRow[column] = sum;
- }
-
- [MethodImpl(InliningOptions.ShortMethod)]
- private static void CalculateWeights(in TResampler sampler, int min, int max, float point, ref float weightsRef)
- where TResampler : struct, IResampler
- {
- float sum = 0;
- for (int x = 0, i = min; i <= max; i++, x++)
- {
- float weight = sampler.GetValue(i - point);
- sum += weight;
- Unsafe.Add(ref weightsRef, x) = weight;
- }
- }
- }
-}
diff --git a/src/ImageSharp/Processing/Processors/Transforms/Linear/ProjectiveTransformProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Transforms/Linear/ProjectiveTransformProcessor{TPixel}.cs
index f16a495b14..9396a018d3 100644
--- a/src/ImageSharp/Processing/Processors/Transforms/Linear/ProjectiveTransformProcessor{TPixel}.cs
+++ b/src/ImageSharp/Processing/Processors/Transforms/Linear/ProjectiveTransformProcessor{TPixel}.cs
@@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0.
using System;
+using System.Diagnostics.CodeAnalysis;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
@@ -80,32 +81,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
return;
}
- int yRadius = LinearTransformUtils.GetSamplingRadius(in sampler, source.Height, destination.Height);
- int xRadius = LinearTransformUtils.GetSamplingRadius(in sampler, source.Width, destination.Width);
- var radialExtents = new Vector2(xRadius, yRadius);
- int yLength = (yRadius * 2) + 1;
- int xLength = (xRadius * 2) + 1;
-
- // We use 2D buffers so that we can access the weight spans per row in parallel.
- using Buffer2D yKernelBuffer = configuration.MemoryAllocator.Allocate2D(yLength, destination.Height);
- using Buffer2D xKernelBuffer = configuration.MemoryAllocator.Allocate2D(xLength, destination.Height);
-
- int maxX = source.Width - 1;
- int maxY = source.Height - 1;
- var maxSourceExtents = new Vector4(maxX, maxY, maxX, maxY);
-
var operation = new ProjectiveOperation(
configuration,
source,
destination,
- yKernelBuffer,
- xKernelBuffer,
in sampler,
- matrix,
- radialExtents,
- maxSourceExtents);
+ matrix);
- ParallelRowIterator.IterateRows, Vector4>(
+ ParallelRowIterator.IterateRowIntervals, Vector4>(
configuration,
destination.Bounds(),
in operation);
@@ -117,7 +100,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
private readonly ImageFrame destination;
private readonly Rectangle bounds;
private readonly Matrix4x4 matrix;
- private readonly int maxX;
[MethodImpl(InliningOptions.ShortMethod)]
public NNProjectiveOperation(
@@ -129,15 +111,15 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
this.destination = destination;
this.bounds = source.Bounds();
this.matrix = matrix;
- this.maxX = destination.Width;
}
[MethodImpl(InliningOptions.ShortMethod)]
public void Invoke(int y)
{
+ Buffer2D sourceBuffer = this.source.PixelBuffer;
Span destRow = this.destination.GetPixelRowSpan(y);
- for (int x = 0; x < this.maxX; x++)
+ for (int x = 0; x < destRow.Length; x++)
{
Vector2 point = TransformUtils.ProjectiveTransform2D(x, y, this.matrix);
int px = (int)MathF.Round(point.X);
@@ -145,84 +127,181 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
if (this.bounds.Contains(px, py))
{
- destRow[x] = this.source[px, py];
+ destRow[x] = sourceBuffer.GetElementUnsafe(px, py);
}
}
}
}
- private readonly struct ProjectiveOperation : IRowOperation
+ private readonly struct ProjectiveOperation : IRowIntervalOperation
where TResampler : struct, IResampler
{
private readonly Configuration configuration;
private readonly ImageFrame source;
private readonly ImageFrame destination;
- private readonly Buffer2D yKernelBuffer;
- private readonly Buffer2D xKernelBuffer;
private readonly TResampler sampler;
private readonly Matrix4x4 matrix;
- private readonly Vector2 radialExtents;
- private readonly Vector4 maxSourceExtents;
- private readonly int maxX;
+ private readonly float yRadius;
+ private readonly float xRadius;
[MethodImpl(InliningOptions.ShortMethod)]
public ProjectiveOperation(
Configuration configuration,
ImageFrame source,
ImageFrame destination,
- Buffer2D yKernelBuffer,
- Buffer2D xKernelBuffer,
in TResampler sampler,
- Matrix4x4 matrix,
- Vector2 radialExtents,
- Vector4 maxSourceExtents)
+ Matrix4x4 matrix)
{
this.configuration = configuration;
this.source = source;
this.destination = destination;
- this.yKernelBuffer = yKernelBuffer;
- this.xKernelBuffer = xKernelBuffer;
this.sampler = sampler;
this.matrix = matrix;
- this.radialExtents = radialExtents;
- this.maxSourceExtents = maxSourceExtents;
- this.maxX = destination.Width;
+
+ this.yRadius = LinearTransformUtility.GetSamplingRadius(in sampler, source.Height, destination.Height);
+ this.xRadius = LinearTransformUtility.GetSamplingRadius(in sampler, source.Width, destination.Width);
}
[MethodImpl(InliningOptions.ShortMethod)]
- public void Invoke(int y, Span span)
+ public void Invoke(in RowInterval rows, Span span)
{
- Buffer2D sourceBuffer = this.source.PixelBuffer;
+ if (RuntimeEnvironment.IsOSPlatform(OSPlatform.OSX)
+ && RuntimeEnvironment.IsNetCore)
+ {
+ // There's something wrong with the JIT in .NET Core 3.1 on certain
+ // MacOSX machines so we have to use different pipelines.
+ // It's:
+ // - Not reproducable locally
+ // - Doesn't seem to be triggered by the bulk Numerics.UnPremultiply method but by caller.
+ // https://github.com/SixLabors/ImageSharp/pull/1591
+ this.InvokeMacOSX(in rows, span);
+ return;
+ }
- PixelOperations.Instance.ToVector4(
- this.configuration,
- this.destination.GetPixelRowSpan(y),
- span);
+ Matrix4x4 matrix = this.matrix;
+ TResampler sampler = this.sampler;
+ float yRadius = this.yRadius;
+ float xRadius = this.xRadius;
+ int maxY = this.source.Height - 1;
+ int maxX = this.source.Width - 1;
- ref float yKernelSpanRef = ref MemoryMarshal.GetReference(this.yKernelBuffer.GetRowSpan(y));
- ref float xKernelSpanRef = ref MemoryMarshal.GetReference(this.xKernelBuffer.GetRowSpan(y));
+ Buffer2D sourceBuffer = this.source.PixelBuffer;
- for (int x = 0; x < this.maxX; x++)
+ for (int y = rows.Min; y < rows.Max; y++)
{
- // Use the single precision position to calculate correct bounding pixels
- // otherwise we get rogue pixels outside of the bounds.
- Vector2 point = TransformUtils.ProjectiveTransform2D(x, y, this.matrix);
- LinearTransformUtils.Convolve(
- in this.sampler,
- point,
- sourceBuffer,
+ Span rowSpan = this.destination.GetPixelRowSpan(y);
+ PixelOperations.Instance.ToVector4(
+ this.configuration,
+ rowSpan,
+ span,
+ PixelConversionModifiers.Scale);
+
+ for (int x = 0; x < span.Length; x++)
+ {
+ Vector2 point = TransformUtils.ProjectiveTransform2D(x, y, matrix);
+ float pY = point.Y;
+ float pX = point.X;
+
+ int top = LinearTransformUtility.GetRangeStart(yRadius, pY, maxY);
+ int bottom = LinearTransformUtility.GetRangeEnd(yRadius, pY, maxY);
+ int left = LinearTransformUtility.GetRangeStart(xRadius, pX, maxX);
+ int right = LinearTransformUtility.GetRangeEnd(xRadius, pX, maxX);
+
+ if (bottom <= top || right <= left)
+ {
+ continue;
+ }
+
+ Vector4 sum = Vector4.Zero;
+ for (int yK = top; yK <= bottom; yK++)
+ {
+ float yWeight = sampler.GetValue(yK - pY);
+
+ for (int xK = left; xK <= right; xK++)
+ {
+ float xWeight = sampler.GetValue(xK - pX);
+
+ Vector4 current = sourceBuffer.GetElementUnsafe(xK, yK).ToScaledVector4();
+ Numerics.Premultiply(ref current);
+ sum += current * xWeight * yWeight;
+ }
+ }
+
+ span[x] = sum;
+ }
+
+ Numerics.UnPremultiply(span);
+ PixelOperations.Instance.FromVector4Destructive(
+ this.configuration,
span,
- x,
- ref yKernelSpanRef,
- ref xKernelSpanRef,
- this.radialExtents,
- this.maxSourceExtents);
+ rowSpan,
+ PixelConversionModifiers.Scale);
}
+ }
+
+ [ExcludeFromCodeCoverage]
+ [MethodImpl(InliningOptions.ShortMethod)]
+ public void InvokeMacOSX(in RowInterval rows, Span span)
+ {
+ Matrix4x4 matrix = this.matrix;
+ TResampler sampler = this.sampler;
+ float yRadius = this.yRadius;
+ float xRadius = this.xRadius;
+ int maxY = this.source.Height - 1;
+ int maxX = this.source.Width - 1;
- PixelOperations.Instance.FromVector4Destructive(
- this.configuration,
- span,
- this.destination.GetPixelRowSpan(y));
+ Buffer2D sourceBuffer = this.source.PixelBuffer;
+
+ for (int y = rows.Min; y < rows.Max; y++)
+ {
+ Span rowSpan = this.destination.GetPixelRowSpan(y);
+ PixelOperations.Instance.ToVector4(
+ this.configuration,
+ rowSpan,
+ span,
+ PixelConversionModifiers.Scale);
+
+ for (int x = 0; x < span.Length; x++)
+ {
+ Vector2 point = TransformUtils.ProjectiveTransform2D(x, y, matrix);
+ float pY = point.Y;
+ float pX = point.X;
+
+ int top = LinearTransformUtility.GetRangeStart(yRadius, pY, maxY);
+ int bottom = LinearTransformUtility.GetRangeEnd(yRadius, pY, maxY);
+ int left = LinearTransformUtility.GetRangeStart(xRadius, pX, maxX);
+ int right = LinearTransformUtility.GetRangeEnd(xRadius, pX, maxX);
+
+ if (bottom <= top || right <= left)
+ {
+ continue;
+ }
+
+ Vector4 sum = Vector4.Zero;
+ for (int yK = top; yK <= bottom; yK++)
+ {
+ float yWeight = sampler.GetValue(yK - pY);
+
+ for (int xK = left; xK <= right; xK++)
+ {
+ float xWeight = sampler.GetValue(xK - pX);
+
+ Vector4 current = sourceBuffer.GetElementUnsafe(xK, yK).ToScaledVector4();
+ Numerics.Premultiply(ref current);
+ sum += current * xWeight * yWeight;
+ }
+ }
+
+ Numerics.UnPremultiply(ref sum);
+ span[x] = sum;
+ }
+
+ PixelOperations.Instance.FromVector4Destructive(
+ this.configuration,
+ span,
+ rowSpan,
+ PixelConversionModifiers.Scale);
+ }
}
}
}
diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernel.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernel.cs
index 66f885f23a..a67ed92a56 100644
--- a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernel.cs
+++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernel.cs
@@ -13,7 +13,7 @@ using System.Runtime.Intrinsics.X86;
namespace SixLabors.ImageSharp.Processing.Processors.Transforms
{
///
- /// Points to a collection of of weights allocated in .
+ /// Points to a collection of weights allocated in .
///
internal readonly unsafe struct ResizeKernel
{
@@ -40,7 +40,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
}
///
- /// Gets the the length of the kernel.
+ /// Gets the length of the kernel.
///
public int Length
{
diff --git a/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj b/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj
index d89cf79fc9..a146dc03ee 100644
--- a/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj
+++ b/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj
@@ -5,15 +5,28 @@
ImageSharp.Benchmarks
Exe
SixLabors.ImageSharp.Benchmarks
- net5.0;netcoreapp3.1;netcoreapp2.1;net472
false
false
+ Debug;Release;Release-InnerLoop;Debug-InnerLoop
+
+
+
+ netcoreapp3.1
+
+
+
+
+ net5.0;netcoreapp3.1;netcoreapp2.1;net472
+
+
+
+
diff --git a/tests/ImageSharp.Benchmarks/Processing/Rotate.cs b/tests/ImageSharp.Benchmarks/Processing/Rotate.cs
index 107c47f062..1b8aed0068 100644
--- a/tests/ImageSharp.Benchmarks/Processing/Rotate.cs
+++ b/tests/ImageSharp.Benchmarks/Processing/Rotate.cs
@@ -21,21 +21,19 @@ namespace SixLabors.ImageSharp.Benchmarks.Processing
}
}
-// #### 21th February 2020 ####
+// #### 2021-04-06 ####
//
-// BenchmarkDotNet=v0.12.0, OS=Windows 10.0.18363
-// Intel Core i7-8650U CPU 1.90GHz(Kaby Lake R), 1 CPU, 8 logical and 4 physical cores
-// .NET Core SDK = 3.1.101
+// BenchmarkDotNet=v0.12.1, OS=Windows 10.0.19042
+// Intel Core i7-8650U CPU 1.90GHz (Kaby Lake R), 1 CPU, 8 logical and 4 physical cores
+// .NET Core SDK=5.0.201
+// [Host] : .NET Core 5.0.4 (CoreCLR 5.0.421.11614, CoreFX 5.0.421.11614), X64 RyuJIT
+// Job-HQWHDJ : .NET Framework 4.8 (4.8.4341.0), X64 RyuJIT
+// Job-RPXLFC : .NET Core 2.1.26 (CoreCLR 4.6.29812.02, CoreFX 4.6.29812.01), X64 RyuJIT
+// Job-YMSKIM : .NET Core 3.1.13 (CoreCLR 4.700.21.11102, CoreFX 4.700.21.11602), X64 RyuJIT
//
-// [Host] : .NET Core 3.1.1 (CoreCLR 4.700.19.60701, CoreFX 4.700.19.60801), X64 RyuJIT
-// Job-HOGSNT : .NET Framework 4.8 (4.8.4121.0), X64 RyuJIT
-// Job-FKDHXC : .NET Core 2.1.15 (CoreCLR 4.6.28325.01, CoreFX 4.6.28327.02), X64 RyuJIT
-// Job-ODABAZ : .NET Core 3.1.1 (CoreCLR 4.700.19.60701, CoreFX 4.700.19.60801), X64 RyuJIT
//
-// IterationCount=3 LaunchCount=1 WarmupCount=3
-//
-// | Method | Runtime | Mean | Error | StdDev | Gen 0 | Gen 1 | Gen 2 | Allocated |
-// |--------- |-------------- |---------:|---------:|---------:|------:|------:|------:|----------:|
-// | DoRotate | .NET 4.7.2 | 28.77 ms | 3.304 ms | 0.181 ms | - | - | - | 6.5 KB |
-// | DoRotate | .NET Core 2.1 | 16.27 ms | 1.044 ms | 0.057 ms | - | - | - | 5.25 KB |
-// | DoRotate | .NET Core 3.1 | 17.12 ms | 4.352 ms | 0.239 ms | - | - | - | 6.57 KB |
+// | Method | Job | Runtime | Mean | Error | StdDev | Gen 0 | Gen 1 | Gen 2 | Allocated |
+// |--------- |----------- |-------------- |---------:|---------:|---------:|------:|------:|------:|----------:|
+// | DoRotate | Job-BAUEPW | .NET 4.7.2 | 30.73 ms | 0.397 ms | 0.331 ms | - | - | - | 6.75 KB |
+// | DoRotate | Job-SNWMCN | .NET Core 2.1 | 16.31 ms | 0.317 ms | 0.352 ms | - | - | - | 5.25 KB |
+// | DoRotate | Job-MRMBJZ | .NET Core 3.1 | 12.21 ms | 0.239 ms | 0.245 ms | - | - | - | 6.61 KB |
diff --git a/tests/ImageSharp.Benchmarks/Processing/Skew.cs b/tests/ImageSharp.Benchmarks/Processing/Skew.cs
index b77f0dcd6b..1c92b9f3c5 100644
--- a/tests/ImageSharp.Benchmarks/Processing/Skew.cs
+++ b/tests/ImageSharp.Benchmarks/Processing/Skew.cs
@@ -21,21 +21,19 @@ namespace SixLabors.ImageSharp.Benchmarks.Processing
}
}
-// #### 21th February 2020 ####
+// #### 2021-04-06 ####
//
-// BenchmarkDotNet=v0.12.0, OS=Windows 10.0.18363
-// Intel Core i7-8650U CPU 1.90GHz(Kaby Lake R), 1 CPU, 8 logical and 4 physical cores
-// .NET Core SDK = 3.1.101
+// BenchmarkDotNet=v0.12.1, OS=Windows 10.0.19042
+// Intel Core i7-8650U CPU 1.90GHz (Kaby Lake R), 1 CPU, 8 logical and 4 physical cores
+// .NET Core SDK=5.0.201
+// [Host] : .NET Core 5.0.4 (CoreCLR 5.0.421.11614, CoreFX 5.0.421.11614), X64 RyuJIT
+// Job-HQWHDJ : .NET Framework 4.8 (4.8.4341.0), X64 RyuJIT
+// Job-RPXLFC : .NET Core 2.1.26 (CoreCLR 4.6.29812.02, CoreFX 4.6.29812.01), X64 RyuJIT
+// Job-YMSKIM : .NET Core 3.1.13 (CoreCLR 4.700.21.11102, CoreFX 4.700.21.11602), X64 RyuJIT
//
-// [Host] : .NET Core 3.1.1 (CoreCLR 4.700.19.60701, CoreFX 4.700.19.60801), X64 RyuJIT
-// Job-VKKTMF : .NET Framework 4.8 (4.8.4121.0), X64 RyuJIT
-// Job-KTVRKR : .NET Core 2.1.15 (CoreCLR 4.6.28325.01, CoreFX 4.6.28327.02), X64 RyuJIT
-// Job-EONWDB : .NET Core 3.1.1 (CoreCLR 4.700.19.60701, CoreFX 4.700.19.60801), X64 RyuJIT
//
-// IterationCount=3 LaunchCount=1 WarmupCount=3
-//
-// | Method | Runtime | Mean | Error | StdDev | Gen 0 | Gen 1 | Gen 2 | Allocated |
-// |------- |-------------- |---------:|----------:|---------:|------:|------:|------:|----------:|
-// | DoSkew | .NET 4.7.2 | 24.60 ms | 33.971 ms | 1.862 ms | - | - | - | 6.5 KB |
-// | DoSkew | .NET Core 2.1 | 12.13 ms | 2.256 ms | 0.124 ms | - | - | - | 5.21 KB |
-// | DoSkew | .NET Core 3.1 | 12.83 ms | 1.442 ms | 0.079 ms | - | - | - | 6.57 KB |
+// | Method | Job | Runtime | Mean | Error | StdDev | Gen 0 | Gen 1 | Gen 2 | Allocated |
+// |------- |----------- |-------------- |----------:|----------:|----------:|------:|------:|------:|----------:|
+// | DoSkew | Job-YEGFRQ | .NET 4.7.2 | 23.563 ms | 0.0731 ms | 0.0570 ms | - | - | - | 6.75 KB |
+// | DoSkew | Job-HZHOGR | .NET Core 2.1 | 13.700 ms | 0.2727 ms | 0.5122 ms | - | - | - | 5.25 KB |
+// | DoSkew | Job-LTEUKY | .NET Core 3.1 | 9.971 ms | 0.0254 ms | 0.0225 ms | - | - | - | 6.61 KB |
diff --git a/tests/ImageSharp.Tests.ProfilingSandbox/ImageSharp.Tests.ProfilingSandbox.csproj b/tests/ImageSharp.Tests.ProfilingSandbox/ImageSharp.Tests.ProfilingSandbox.csproj
index 220780c58e..9159475326 100644
--- a/tests/ImageSharp.Tests.ProfilingSandbox/ImageSharp.Tests.ProfilingSandbox.csproj
+++ b/tests/ImageSharp.Tests.ProfilingSandbox/ImageSharp.Tests.ProfilingSandbox.csproj
@@ -8,13 +8,26 @@
false
SixLabors.ImageSharp.Tests.ProfilingSandbox
win7-x64
- net5.0;netcoreapp3.1;netcoreapp2.1;net472
SixLabors.ImageSharp.Tests.ProfilingSandbox.Program
false
false
+ Debug;Release;Release-InnerLoop;Debug-InnerLoop
+
+
+
+ netcoreapp3.1
+
+
+
+
+ net5.0;netcoreapp3.1;netcoreapp2.1;net472
+
+
+
+
diff --git a/tests/ImageSharp.Tests.ProfilingSandbox/app.config b/tests/ImageSharp.Tests.ProfilingSandbox/app.config
index 3328297a54..a74fa13156 100644
--- a/tests/ImageSharp.Tests.ProfilingSandbox/app.config
+++ b/tests/ImageSharp.Tests.ProfilingSandbox/app.config
@@ -1,4 +1,4 @@
-
+
@@ -12,8 +12,8 @@
-
+
-
\ No newline at end of file
+
diff --git a/tests/ImageSharp.Tests/Helpers/RuntimeEnvironmentTests.cs b/tests/ImageSharp.Tests/Helpers/RuntimeEnvironmentTests.cs
new file mode 100644
index 0000000000..8074b8b150
--- /dev/null
+++ b/tests/ImageSharp.Tests/Helpers/RuntimeEnvironmentTests.cs
@@ -0,0 +1,41 @@
+// Copyright (c) Six Labors.
+// Licensed under the Apache License, Version 2.0.
+
+using System.Runtime.InteropServices;
+using Xunit;
+
+#pragma warning disable IDE0022 // Use expression body for methods
+namespace SixLabors.ImageSharp.Tests.Helpers
+{
+ public class RuntimeEnvironmentTests
+ {
+ [Fact]
+ public void CanDetectNetCore()
+ {
+#if NET5_0_OR_GREATER
+ Assert.False(RuntimeEnvironment.IsNetCore);
+#elif NETCOREAPP
+ Assert.True(RuntimeEnvironment.IsNetCore);
+#else
+ Assert.False(RuntimeEnvironment.IsNetCore);
+#endif
+ }
+
+ [Fact]
+ public void CanDetectOSPlatform()
+ {
+ if (TestEnvironment.IsLinux)
+ {
+ Assert.True(RuntimeEnvironment.IsOSPlatform(OSPlatform.Linux));
+ }
+ else if (TestEnvironment.IsOSX)
+ {
+ Assert.True(RuntimeEnvironment.IsOSPlatform(OSPlatform.OSX));
+ }
+ else if (TestEnvironment.IsWindows)
+ {
+ Assert.True(RuntimeEnvironment.IsOSPlatform(OSPlatform.Windows));
+ }
+ }
+ }
+}
diff --git a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj
index ebbe2cbdfa..b6482455e0 100644
--- a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj
+++ b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj
@@ -2,13 +2,26 @@
- net5.0;netcoreapp3.1;netcoreapp2.1;net472
True
SixLabors.ImageSharp.Tests
AnyCPU;x64;x86
SixLabors.ImageSharp.Tests
+ Debug;Release;Release-InnerLoop;Debug-InnerLoop
+
+
+
+ netcoreapp3.1
+
+
+
+
+ net5.0;netcoreapp3.1;netcoreapp2.1;net472
+
+
+
+
diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/AffineTransformTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/AffineTransformTests.cs
index 379f74d094..49a443d927 100644
--- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/AffineTransformTests.cs
+++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/AffineTransformTests.cs
@@ -4,7 +4,6 @@
using System;
using System.Numerics;
using System.Reflection;
-using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing;
using SixLabors.ImageSharp.Processing.Processors.Transforms;
@@ -18,9 +17,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms
public class AffineTransformTests
{
private readonly ITestOutputHelper output;
-
- // 1 byte difference on one color component.
- private static readonly ImageComparer ValidatorComparer = ImageComparer.TolerantPercentage(0.0134F, 3);
+ private static readonly ImageComparer ValidatorComparer = ImageComparer.TolerantPercentage(0.033F, 3);
///
/// angleDeg, sx, sy, tx, ty
diff --git a/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs b/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs
index fcde6273f5..8a038a6912 100644
--- a/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs
+++ b/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs
@@ -174,7 +174,7 @@ namespace SixLabors.ImageSharp.Tests
appendPixelTypeToFileName,
appendSourceFileOrDescription);
- encoder = encoder ?? TestEnvironment.GetReferenceEncoder(path);
+ encoder ??= TestEnvironment.GetReferenceEncoder(path);
using (FileStream stream = File.OpenWrite(path))
{
diff --git a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/ImageSharpPngEncoderWithDefaultConfiguration.cs b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/ImageSharpPngEncoderWithDefaultConfiguration.cs
new file mode 100644
index 0000000000..f0a01e45e8
--- /dev/null
+++ b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/ImageSharpPngEncoderWithDefaultConfiguration.cs
@@ -0,0 +1,94 @@
+// Copyright (c) Six Labors.
+// Licensed under the Apache License, Version 2.0.
+
+using System.IO;
+using System.Threading;
+using System.Threading.Tasks;
+using SixLabors.ImageSharp.Formats;
+using SixLabors.ImageSharp.Formats.Png;
+using SixLabors.ImageSharp.Memory;
+using SixLabors.ImageSharp.PixelFormats;
+using SixLabors.ImageSharp.Processing.Processors.Quantization;
+
+namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs
+{
+ ///
+ /// A Png encoder that uses the ImageSharp core encoder but the default configuration.
+ /// This allows encoding under environments with restricted memory.
+ ///
+ public sealed class ImageSharpPngEncoderWithDefaultConfiguration : IImageEncoder, IPngEncoderOptions
+ {
+ ///
+ public PngBitDepth? BitDepth { get; set; }
+
+ ///
+ public PngColorType? ColorType { get; set; }
+
+ ///
+ public PngFilterMethod? FilterMethod { get; set; }
+
+ ///
+ public PngCompressionLevel CompressionLevel { get; set; } = PngCompressionLevel.DefaultCompression;
+
+ ///
+ public int TextCompressionThreshold { get; set; } = 1024;
+
+ ///
+ public float? Gamma { get; set; }
+
+ ///
+ public IQuantizer Quantizer { get; set; }
+
+ ///
+ public byte Threshold { get; set; } = byte.MaxValue;
+
+ ///
+ public PngInterlaceMode? InterlaceMethod { get; set; }
+
+ ///
+ public PngChunkFilter? ChunkFilter { get; set; }
+
+ ///
+ public bool IgnoreMetadata { get; set; }
+
+ ///
+ public PngTransparentColorMode TransparentColorMode { get; set; }
+
+ ///
+ /// Encodes the image to the specified stream from the .
+ ///
+ /// The pixel format.
+ /// The to encode from.
+ /// The to encode the image data to.
+ public void Encode(Image image, Stream stream)
+ where TPixel : unmanaged, IPixel
+ {
+ Configuration configuration = Configuration.Default;
+ MemoryAllocator allocator = configuration.MemoryAllocator;
+
+ using var encoder = new PngEncoderCore(allocator, configuration, new PngEncoderOptions(this));
+ encoder.Encode(image, stream);
+ }
+
+ ///
+ /// Encodes the image to the specified stream from the .
+ ///
+ /// The pixel format.
+ /// The to encode from.
+ /// The to encode the image data to.
+ /// The token to monitor for cancellation requests.
+ /// A representing the asynchronous operation.
+ public async Task EncodeAsync(Image image, Stream stream, CancellationToken cancellationToken)
+ where TPixel : unmanaged, IPixel
+ {
+ Configuration configuration = Configuration.Default;
+ MemoryAllocator allocator = configuration.MemoryAllocator;
+
+ // The introduction of a local variable that refers to an object the implements
+ // IDisposable means you must use async/await, where the compiler generates the
+ // state machine and a continuation.
+ using var encoder = new PngEncoderCore(allocator, configuration, new PngEncoderOptions(this));
+ await encoder.EncodeAsync(image, stream, cancellationToken).ConfigureAwait(false);
+ }
+ }
+}
diff --git a/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.Formats.cs b/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.Formats.cs
index f6b5b4ca52..3b63505e91 100644
--- a/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.Formats.cs
+++ b/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.Formats.cs
@@ -59,10 +59,10 @@ namespace SixLabors.ImageSharp.Tests
new TgaConfigurationModule(),
new WebpConfigurationModule());
- // Magick codecs should work on all platforms
- IImageEncoder pngEncoder = IsWindows ? (IImageEncoder)SystemDrawingReferenceEncoder.Png : new PngEncoder();
+ IImageEncoder pngEncoder = IsWindows ? (IImageEncoder)SystemDrawingReferenceEncoder.Png : new ImageSharpPngEncoderWithDefaultConfiguration();
IImageEncoder bmpEncoder = IsWindows ? (IImageEncoder)SystemDrawingReferenceEncoder.Bmp : new BmpEncoder();
+ // Magick codecs should work on all platforms
cfg.ConfigureCodecs(
PngFormat.Instance,
MagickReferenceDecoder.Instance,
diff --git a/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.cs b/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.cs
index cb8a0df42f..b14c2bf782 100644
--- a/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.cs
+++ b/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.cs
@@ -24,8 +24,6 @@ namespace SixLabors.ImageSharp.Tests
private static readonly Lazy SolutionDirectoryFullPathLazy = new Lazy(GetSolutionDirectoryFullPathImpl);
- private static readonly Lazy RunsOnCiLazy = new Lazy(() => bool.TryParse(Environment.GetEnvironmentVariable("CI"), out bool isCi) && isCi);
-
private static readonly Lazy NetCoreVersionLazy = new Lazy(GetNetCoreVersion);
static TestEnvironment() => PrepareRemoteExecutor();
@@ -40,7 +38,20 @@ namespace SixLabors.ImageSharp.Tests
///
/// Gets a value indicating whether test execution runs on CI.
///
- internal static bool RunsOnCI => RunsOnCiLazy.Value;
+#if ENV_CI
+ internal static bool RunsOnCI => true;
+#else
+ internal static bool RunsOnCI => false;
+#endif
+
+ ///
+ /// Gets a value indicating whether test execution is running with code coverage testing enabled.
+ ///
+#if ENV_CODECOV
+ internal static bool RunsWithCodeCoverage => true;
+#else
+ internal static bool RunsWithCodeCoverage => false;
+#endif
internal static string SolutionDirectoryFullPath => SolutionDirectoryFullPathLazy.Value;
@@ -59,14 +70,14 @@ namespace SixLabors.ImageSharp.Tests
}
catch (Exception ex)
{
- throw new Exception(
+ throw new DirectoryNotFoundException(
$"Unable to find ImageSharp solution directory from {TestAssemblyFile} because of {ex.GetType().Name}!",
ex);
}
if (directory == null)
{
- throw new Exception($"Unable to find ImageSharp solution directory from {TestAssemblyFile}!");
+ throw new DirectoryNotFoundException($"Unable to find ImageSharp solution directory from {TestAssemblyFile}!");
}
}
diff --git a/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs b/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs
index 073db1efed..1c5aedd9b7 100644
--- a/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs
+++ b/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs
@@ -34,18 +34,16 @@ namespace SixLabors.ImageSharp.Tests
bool appendPixelTypeToFileName = true,
bool appendSourceFileOrDescription = true,
IImageEncoder encoder = null)
- {
- image.DebugSave(
+ => image.DebugSave(
provider,
(object)testOutputDetails,
extension,
appendPixelTypeToFileName,
appendSourceFileOrDescription,
encoder);
- }
///
- /// Saves the image only when not running in the CI server.
+ /// Saves the image for debugging purpose.
///
/// The image.
/// The image provider.
@@ -64,12 +62,11 @@ namespace SixLabors.ImageSharp.Tests
bool appendSourceFileOrDescription = true,
IImageEncoder encoder = null)
{
- if (TestEnvironment.RunsOnCI)
+ if (TestEnvironment.RunsWithCodeCoverage)
{
return image;
}
- // We are running locally then we want to save it out
provider.Utility.SaveTestOutputFile(
image,
extension,
@@ -86,12 +83,10 @@ namespace SixLabors.ImageSharp.Tests
IImageEncoder encoder,
FormattableString testOutputDetails,
bool appendPixelTypeToFileName = true)
- {
- image.DebugSave(provider, encoder, (object)testOutputDetails, appendPixelTypeToFileName);
- }
+ => image.DebugSave(provider, encoder, (object)testOutputDetails, appendPixelTypeToFileName);
///
- /// Saves the image only when not running in the CI server.
+ /// Saves the image for debugging purpose.
///
/// The image
/// The image provider
@@ -104,19 +99,11 @@ namespace SixLabors.ImageSharp.Tests
IImageEncoder encoder,
object testOutputDetails = null,
bool appendPixelTypeToFileName = true)
- {
- if (TestEnvironment.RunsOnCI)
- {
- return;
- }
-
- // We are running locally then we want to save it out
- provider.Utility.SaveTestOutputFile(
+ => provider.Utility.SaveTestOutputFile(
image,
encoder: encoder,
testOutputDetails: testOutputDetails,
appendPixelTypeToFileName: appendPixelTypeToFileName);
- }
public static Image DebugSaveMultiFrame(
this Image image,
@@ -126,17 +113,17 @@ namespace SixLabors.ImageSharp.Tests
bool appendPixelTypeToFileName = true)
where TPixel : unmanaged, IPixel
{
- if (TestEnvironment.RunsOnCI)
+ if (TestEnvironment.RunsWithCodeCoverage)
{
return image;
}
- // We are running locally then we want to save it out
provider.Utility.SaveTestOutputFileMultiFrame(
image,
extension,
testOutputDetails: testOutputDetails,
appendPixelTypeToFileName: appendPixelTypeToFileName);
+
return image;
}
@@ -149,15 +136,13 @@ namespace SixLabors.ImageSharp.Tests
bool appendPixelTypeToFileName = true,
bool appendSourceFileOrDescription = true)
where TPixel : unmanaged, IPixel
- {
- return image.CompareToReferenceOutput(
+ => image.CompareToReferenceOutput(
provider,
(object)testOutputDetails,
extension,
grayscale,
appendPixelTypeToFileName,
appendSourceFileOrDescription);
- }
///
/// Compares the image against the expected Reference output, throws an exception if the images are not similar enough.
@@ -181,8 +166,7 @@ namespace SixLabors.ImageSharp.Tests
bool appendPixelTypeToFileName = true,
bool appendSourceFileOrDescription = true)
where TPixel : unmanaged, IPixel
- {
- return CompareToReferenceOutput(
+ => CompareToReferenceOutput(
image,
ImageComparer.Tolerant(),
provider,
@@ -191,7 +175,6 @@ namespace SixLabors.ImageSharp.Tests
grayscale,
appendPixelTypeToFileName,
appendSourceFileOrDescription);
- }
public static Image CompareToReferenceOutput(
this Image image,
@@ -202,15 +185,13 @@ namespace SixLabors.ImageSharp.Tests
bool grayscale = false,
bool appendPixelTypeToFileName = true)
where TPixel : unmanaged, IPixel
- {
- return image.CompareToReferenceOutput(
+ => image.CompareToReferenceOutput(
comparer,
provider,
(object)testOutputDetails,
extension,
grayscale,
appendPixelTypeToFileName);
- }
///
/// Compares the image against the expected Reference output, throws an exception if the images are not similar enough.
@@ -263,8 +244,7 @@ namespace SixLabors.ImageSharp.Tests
bool appendPixelTypeToFileName = true,
bool appendSourceFileOrDescription = true)
where TPixel : unmanaged, IPixel
- {
- return image.CompareFirstFrameToReferenceOutput(
+ => image.CompareFirstFrameToReferenceOutput(
comparer,
provider,
(object)testOutputDetails,
@@ -272,7 +252,6 @@ namespace SixLabors.ImageSharp.Tests
grayscale,
appendPixelTypeToFileName,
appendSourceFileOrDescription);
- }
public static Image CompareFirstFrameToReferenceOutput(
this Image image,
@@ -508,9 +487,7 @@ namespace SixLabors.ImageSharp.Tests
ITestImageProvider provider,
IImageDecoder referenceDecoder = null)
where TPixel : unmanaged, IPixel
- {
- return CompareToOriginal(image, provider, ImageComparer.Tolerant(), referenceDecoder);
- }
+ => CompareToOriginal(image, provider, ImageComparer.Tolerant(), referenceDecoder);
public static Image CompareToOriginal(
this Image image,
@@ -584,14 +561,12 @@ namespace SixLabors.ImageSharp.Tests
bool appendPixelTypeToFileName = true,
bool appendSourceFileOrDescription = true)
where TPixel : unmanaged, IPixel
- {
- provider.VerifyOperation(
+ => provider.VerifyOperation(
ImageComparer.Tolerant(),
operation,
testOutputDetails,
appendPixelTypeToFileName,
appendSourceFileOrDescription);
- }
///
/// Utility method for doing the following in one step:
@@ -606,14 +581,12 @@ namespace SixLabors.ImageSharp.Tests
bool appendPixelTypeToFileName = true,
bool appendSourceFileOrDescription = true)
where TPixel : unmanaged, IPixel
- {
- provider.VerifyOperation(
+ => provider.VerifyOperation(
comparer,
operation,
$"",
appendPixelTypeToFileName,
appendSourceFileOrDescription);
- }
///
/// Utility method for doing the following in one step:
@@ -627,9 +600,7 @@ namespace SixLabors.ImageSharp.Tests
bool appendPixelTypeToFileName = true,
bool appendSourceFileOrDescription = true)
where TPixel : unmanaged, IPixel
- {
- provider.VerifyOperation(operation, $"", appendPixelTypeToFileName, appendSourceFileOrDescription);
- }
+ => provider.VerifyOperation(operation, $"", appendPixelTypeToFileName, appendSourceFileOrDescription);
///
/// Loads the expected image with a reference decoder + compares it to .
diff --git a/tests/ImageSharp.Tests/TestUtilities/Tests/TestEnvironmentTests.cs b/tests/ImageSharp.Tests/TestUtilities/Tests/TestEnvironmentTests.cs
index 487f5b7a5d..da2ed63750 100644
--- a/tests/ImageSharp.Tests/TestUtilities/Tests/TestEnvironmentTests.cs
+++ b/tests/ImageSharp.Tests/TestUtilities/Tests/TestEnvironmentTests.cs
@@ -8,7 +8,6 @@ using SixLabors.ImageSharp.Formats.Bmp;
using SixLabors.ImageSharp.Formats.Experimental.Webp;
using SixLabors.ImageSharp.Formats.Gif;
using SixLabors.ImageSharp.Formats.Jpeg;
-using SixLabors.ImageSharp.Formats.Png;
using SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs;
using Xunit;
using Xunit.Abstractions;
@@ -86,7 +85,7 @@ namespace SixLabors.ImageSharp.Tests
}
[Theory]
- [InlineData("lol/foo.png", typeof(PngEncoder))]
+ [InlineData("lol/foo.png", typeof(ImageSharpPngEncoderWithDefaultConfiguration))]
[InlineData("lol/Rofl.bmp", typeof(BmpEncoder))]
[InlineData("lol/Baz.JPG", typeof(JpegEncoder))]
[InlineData("lol/Baz.gif", typeof(GifEncoder))]
diff --git a/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_RotateScaleTranslate_Rgba32_TestPattern100x50_R(50)_S(1,1)_T(-20,-10).png b/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_RotateScaleTranslate_Rgba32_TestPattern100x50_R(50)_S(1,1)_T(-20,-10).png
index ec3bfb5d11..49c7795fe5 100644
--- a/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_RotateScaleTranslate_Rgba32_TestPattern100x50_R(50)_S(1,1)_T(-20,-10).png
+++ b/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_RotateScaleTranslate_Rgba32_TestPattern100x50_R(50)_S(1,1)_T(-20,-10).png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:57376aa4446fc2d034d2a0cb627163ac416d1b6768b063b2c11ccf8517443bda
-size 10135
+oid sha256:2ef489dc0837b382ad7c7ead6b7c7042dfbfba39902d4cc81b5f3805d5b03967
+size 9175
diff --git a/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_RotateScaleTranslate_Rgba32_TestPattern100x50__original.png b/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_RotateScaleTranslate_Rgba32_TestPattern100x50__original.png
index bdad18d1dc..a6ff73cf83 100644
--- a/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_RotateScaleTranslate_Rgba32_TestPattern100x50__original.png
+++ b/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_RotateScaleTranslate_Rgba32_TestPattern100x50__original.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:9c83b59471a50df9e1d7b8f0e35c50aa417cd3be1730d6369f47f5cc99b87cef
-size 6405
+oid sha256:99d6c1d6b092a2feba2aebe2e09c521c3cc9682f3d748927cdc3cbaa38448b28
+size 710
diff --git a/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_Bicubic.png b/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_Bicubic.png
index 526096e7c0..a909194b0b 100644
--- a/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_Bicubic.png
+++ b/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_Bicubic.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:f9f149093c5d9d487f3e16cb59e6807ea6ce581b5c307e57aeb4edaf921de9ca
-size 15138
+oid sha256:04a3b84c668758b586f4d998f080ef96b09f726b0298b28f5dd3d739b0e90744
+size 13138
diff --git a/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_CatmullRom.png b/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_CatmullRom.png
index 526096e7c0..a909194b0b 100644
--- a/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_CatmullRom.png
+++ b/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_CatmullRom.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:f9f149093c5d9d487f3e16cb59e6807ea6ce581b5c307e57aeb4edaf921de9ca
-size 15138
+oid sha256:04a3b84c668758b586f4d998f080ef96b09f726b0298b28f5dd3d739b0e90744
+size 13138
diff --git a/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_Lanczos2.png b/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_Lanczos2.png
index b3439a5c88..e248b6d918 100644
--- a/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_Lanczos2.png
+++ b/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_Lanczos2.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:0c7467702a784807a3a5813a75d5f643655ed5ad427e978d6ee079da67b05961
-size 15363
+oid sha256:6ea7ca66c31474c0bb9673a0d85c1c7465e387ebabf4e2d1e8f9daebfc7c8f34
+size 13956
diff --git a/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_Lanczos3.png b/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_Lanczos3.png
index 4622adab47..5c81a5f5da 100644
--- a/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_Lanczos3.png
+++ b/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_Lanczos3.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:a836c63c0912f69683bc9c8f59687b11e6b84f257816a01ff979ad0b6f4ab656
-size 19059
+oid sha256:6dd98ac441f3c20ea999f058c7b21601d5981d46e9b77709c25f2930a64edb93
+size 17148
diff --git a/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_Lanczos5.png b/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_Lanczos5.png
index 753764631b..1647aae60d 100644
--- a/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_Lanczos5.png
+++ b/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_Lanczos5.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:05de30dc282a0b8a096a476f689a1d2b6bb298098692a2f665c59c3d14902aa6
-size 20426
+oid sha256:d5c4772d9b9dc57c4b5d47450ec9d02d96e40656cf2015f171b5425945f8a598
+size 18726
diff --git a/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_Lanczos8.png b/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_Lanczos8.png
index c0840e5f76..3949197248 100644
--- a/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_Lanczos8.png
+++ b/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_Lanczos8.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:8892179d8edf96583900048bdd895eff24e57be0105e91efafe1de971414db0e
-size 22457
+oid sha256:bb025c4470cec1b0d6544924e46b84cbdb90d75da5d0f879f2c7d7ec9875dee2
+size 20574
diff --git a/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_MitchellNetravali.png b/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_MitchellNetravali.png
index 094777eec3..da8413be52 100644
--- a/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_MitchellNetravali.png
+++ b/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_MitchellNetravali.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:2f351ec6ae6df56537e383494984c2fbcf35a66c44a6ce53d6fd8d6d74a330f3
-size 15342
+oid sha256:c4abaa06827cb779026f8fbb655692bdd8adab37ae5b00c3ae18ebea456eb8d9
+size 13459
diff --git a/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_Robidoux.png b/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_Robidoux.png
index c580f0cffd..5bdf261405 100644
--- a/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_Robidoux.png
+++ b/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_Robidoux.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:b0fb38dbdded32a1518d62ac79f4aa88133aaddad947f23c1066dc33d6938e0b
-size 15372
+oid sha256:3435ade8f7988779280820342e16881b049f717735d2218ac5a971a1bd807db1
+size 13448
diff --git a/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_RobidouxSharp.png b/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_RobidouxSharp.png
index 4c0bb37bc3..0e2dbf2565 100644
--- a/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_RobidouxSharp.png
+++ b/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_RobidouxSharp.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:0be42a5fd4ff10680af74a99ed1e0561ae38181f4efe4641bd63891222dcdf3c
-size 15283
+oid sha256:f0098aa45e820544dd16a58396fa70860886b7d79900916ed97376a8328a5ff2
+size 13367
diff --git a/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_Spline.png b/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_Spline.png
index 7527157d50..27ed945dc8 100644
--- a/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_Spline.png
+++ b/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_Spline.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:1eabaf35e0dda3eccd5e8866ddd65e0c45557c8d5cc29423a99e2f377ee1bfa9
-size 16271
+oid sha256:7729495277b80a42e24dd8f40cdd8a280443575710fb4e199e4871c28b558271
+size 14253
diff --git a/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_Triangle.png b/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_Triangle.png
index 1ee2a15ff6..90c47e96d7 100644
--- a/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_Triangle.png
+++ b/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_Triangle.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:5ab9bea8f45e7d29d7a8c5e3d0182c0f3f3aa7014aa358883dee53db6dfeb3f7
-size 14076
+oid sha256:a2304c234b93bdabaa018263dec70e62090ad1bbb7005ef62643b88600a863fb
+size 12157
diff --git a/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_Welch.png b/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_Welch.png
index d3b8938091..581b229500 100644
--- a/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_Welch.png
+++ b/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_Welch.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:ea452bc46c508f6990870a34d908224a58aa350c4ccebabd4fa6ba138e8034a0
-size 18383
+oid sha256:54b0da9646b7f4cf83df784d69dfbec48e0bdc1788d70a9872817543f72f57c1
+size 16829
diff --git a/tests/Images/External/ReferenceOutput/Drawing/DrawImageTests/DrawTransformed.png b/tests/Images/External/ReferenceOutput/Drawing/DrawImageTests/DrawTransformed.png
index bfb9ab5edf..c04521ebc7 100644
--- a/tests/Images/External/ReferenceOutput/Drawing/DrawImageTests/DrawTransformed.png
+++ b/tests/Images/External/ReferenceOutput/Drawing/DrawImageTests/DrawTransformed.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:2c83df7a2f70aec8f150799055ce42db09568b47b95216c91a79233ce69381d5
-size 191563
+oid sha256:233d8c6c9e101dddf5d210d47c7a20807f8f956738289068ea03b774258ef8c6
+size 182754