diff --git a/.editorconfig b/.editorconfig
index 83670fa83..33fd0577a 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.category-style.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 416dd0d06..70ced6903 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 4be351165..8709e1318 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/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml
index 4828f4f21..5189f0435 100644
--- a/.github/workflows/build-and-test.yml
+++ b/.github/workflows/build-and-test.yml
@@ -1,19 +1,37 @@
name: Build
on:
- push:
- branches:
- - master
- tags:
- - "v*"
- pull_request:
- branches:
- - master
+ push:
+ branches:
+ - master
+ tags:
+ - "v*"
+ pull_request:
+ branches:
+ - master
jobs:
Build:
strategy:
matrix:
options:
+ - os: ubuntu-latest
+ framework: net6.0
+ sdk: 6.0.x
+ sdk-preview: true
+ runtime: -x64
+ codecov: false
+ - os: macos-latest
+ framework: net6.0
+ sdk: 6.0.x
+ sdk-preview: true
+ runtime: -x64
+ codecov: false
+ - os: windows-latest
+ framework: net6.0
+ sdk: 6.0.x
+ sdk-preview: true
+ runtime: -x64
+ codecov: false
- os: ubuntu-latest
framework: net5.0
runtime: -x64
@@ -52,37 +70,38 @@ jobs:
codecov: false
runs-on: ${{matrix.options.os}}
- if: "!contains(github.event.head_commit.message, '[skip ci]')"
steps:
- - uses: actions/checkout@v2
+ - name: Git Config
+ shell: bash
+ run: |
+ git config --global core.autocrlf false
+ git config --global core.longpaths true
+
+ - name: Git Checkout
+ uses: actions/checkout@v2
+ with:
+ fetch-depth: 0
+ submodules: recursive
# See https://github.com/actions/checkout/issues/165#issuecomment-657673315
- - name: Create LFS file list
+ - name: Git Create LFS FileList
run: git lfs ls-files -l | cut -d' ' -f1 | sort > .lfs-assets-id
- - name: Restore LFS cache
+ - name: Git Setup LFS Cache
uses: actions/cache@v2
id: lfs-cache
with:
path: .git/lfs
key: ${{ runner.os }}-lfs-${{ hashFiles('.lfs-assets-id') }}-v1
- - name: Git LFS Pull
+ - name: Git Pull LFS
run: git lfs pull
- - name: Install NuGet
+ - name: NuGet Install
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: Setup NuGet Cache
+ - name: NuGet Setup Cache
uses: actions/cache@v2
id: nuget-cache
with:
@@ -90,60 +109,94 @@ jobs:
key: ${{ runner.os }}-nuget-${{ hashFiles('**/*.csproj', '**/*.props', '**/*.targets') }}
restore-keys: ${{ runner.os }}-nuget-
- - name: Build
+ - name: DotNet Setup Preview
+ if: ${{ matrix.options.sdk-preview == true }}
+ uses: actions/setup-dotnet@v1
+ with:
+ dotnet-version: ${{ matrix.options.sdk }}
+ include-prerelease: true
+
+ - name: DotNet Build
+ if: ${{ matrix.options.sdk-preview != true }}
shell: pwsh
run: ./ci-build.ps1 "${{matrix.options.framework}}"
env:
SIXLABORS_TESTING: True
- - name: Test
+ - name: DotNet Build Preview
+ if: ${{ matrix.options.sdk-preview == true }}
+ shell: pwsh
+ run: ./ci-build.ps1 "${{matrix.options.framework}}"
+ env:
+ SIXLABORS_TESTING_PREVIEW: True
+
+ - name: DotNet Test
+ if: ${{ matrix.options.sdk-preview != true }}
shell: pwsh
run: ./ci-test.ps1 "${{matrix.options.os}}" "${{matrix.options.framework}}" "${{matrix.options.runtime}}" "${{matrix.options.codecov}}"
env:
- SIXLABORS_TESTING: True
- XUNIT_PATH: .\tests\ImageSharp.Tests # Required for xunit
+ SIXLABORS_TESTING: True
+ XUNIT_PATH: .\tests\ImageSharp.Tests # Required for xunit
+
+ - name: DotNet Test Preview
+ if: ${{ matrix.options.sdk-preview == true }}
+ shell: pwsh
+ run: ./ci-test.ps1 "${{matrix.options.os}}" "${{matrix.options.framework}}" "${{matrix.options.runtime}}" "${{matrix.options.codecov}}"
+ env:
+ SIXLABORS_TESTING_PREVIEW: True
+ XUNIT_PATH: .\tests\ImageSharp.Tests # Required for xunit
- name: Export Failed Output
uses: actions/upload-artifact@v2
if: failure()
with:
- name: actual_output_${{ runner.os }}_${{ matrix.options.framework }}${{ matrix.options.runtime }}.zip
- path: tests/Images/ActualOutput/
+ name: actual_output_${{ runner.os }}_${{ matrix.options.framework }}${{ matrix.options.runtime }}.zip
+ path: tests/Images/ActualOutput/
- - name: Update Codecov
+ - name: Codecov Update
uses: codecov/codecov-action@v1
if: matrix.options.codecov == true && startsWith(github.repository, 'SixLabors')
with:
- flags: unittests
+ flags: unittests
Publish:
needs: [Build]
- runs-on: windows-latest
+ runs-on: ubuntu-latest
if: (github.event_name == 'push')
steps:
- - uses: actions/checkout@v2
-
- - name: Install NuGet
- uses: NuGet/setup-nuget@v1
-
- - name: Setup Git
+ - name: Git Config
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: Pack
+ - name: Git Checkout
+ uses: actions/checkout@v2
+ with:
+ fetch-depth: 0
+ submodules: recursive
+
+ - name: NuGet Install
+ uses: NuGet/setup-nuget@v1
+
+ - name: NuGet Setup Cache
+ uses: actions/cache@v2
+ id: nuget-cache
+ with:
+ path: ~/.nuget
+ key: ${{ runner.os }}-nuget-${{ hashFiles('**/*.csproj', '**/*.props', '**/*.targets') }}
+ restore-keys: ${{ runner.os }}-nuget-
+
+ - name: DotNet Pack
shell: pwsh
run: ./ci-pack.ps1
- - name: Publish to MyGet
+ - name: MyGet Publish
shell: pwsh
run: |
- nuget.exe push .\artifacts\*.nupkg ${{secrets.MYGET_TOKEN}} -Source https://www.myget.org/F/sixlabors/api/v2/package
- nuget.exe push .\artifacts\*.snupkg ${{secrets.MYGET_TOKEN}} -Source https://www.myget.org/F/sixlabors/api/v3/index.json
+ dotnet nuget push .\artifacts\*.nupkg -k ${{secrets.MYGET_TOKEN}} -s https://www.myget.org/F/sixlabors/api/v2/package
+ dotnet nuget push .\artifacts\*.snupkg -k ${{secrets.MYGET_TOKEN}} -s https://www.myget.org/F/sixlabors/api/v3/index.json
# TODO: If github.ref starts with 'refs/tags' then it was tag push and we can optionally push out package to nuget.org
diff --git a/.gitignore b/.gitignore
index 475d6e76b..fadf36964 100644
--- a/.gitignore
+++ b/.gitignore
@@ -221,4 +221,9 @@ artifacts/
# Tests
**/Images/ActualOutput
**/Images/ReferenceOutput
+**/Images/Input/MemoryStress
.DS_Store
+
+#lfs
+hooks/**
+lfs/**
diff --git a/Directory.Build.props b/Directory.Build.props
index 3a133efe7..3899ce939 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -18,4 +18,17 @@
+
+
+ preview
+
+
+
+
+ true
+
+
diff --git a/ImageSharp.sln b/ImageSharp.sln
index 8dfab6033..f16f98ac5 100644
--- a/ImageSharp.sln
+++ b/ImageSharp.sln
@@ -1,7 +1,7 @@
Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio Version 16
-VisualStudioVersion = 16.0.28902.138
+# Visual Studio Version 17
+VisualStudioVersion = 17.0.31903.59
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "_root", "_root", "{C317F1B1-D75E-4C6D-83EB-80367343E0D7}"
ProjectSection(SolutionItems) = preProject
@@ -13,6 +13,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "_root", "_root", "{C317F1B1
ci-build.ps1 = ci-build.ps1
ci-pack.ps1 = ci-pack.ps1
ci-test.ps1 = ci-test.ps1
+ codecov.yml = codecov.yml
Directory.Build.props = Directory.Build.props
Directory.Build.targets = Directory.Build.targets
LICENSE = LICENSE
@@ -379,6 +380,170 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Png", "Png", "{E1C42A6F-913
tests\Images\Input\Png\zlib-ztxt-bad-header.png = tests\Images\Input\Png\zlib-ztxt-bad-header.png
EndProjectSection
EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Webp", "Webp", "{983A31E2-5E26-4058-BD6E-03B4922D4BBF}"
+ ProjectSection(SolutionItems) = preProject
+ tests\Images\Input\Webp\1602311202.webp = tests\Images\Input\Webp\1602311202.webp
+ tests\Images\Input\Webp\alpha_color_cache.webp = tests\Images\Input\Webp\alpha_color_cache.webp
+ tests\Images\Input\Webp\alpha_filter_0_method_0.webp = tests\Images\Input\Webp\alpha_filter_0_method_0.webp
+ tests\Images\Input\Webp\alpha_filter_0_method_1.webp = tests\Images\Input\Webp\alpha_filter_0_method_1.webp
+ tests\Images\Input\Webp\alpha_filter_1.webp = tests\Images\Input\Webp\alpha_filter_1.webp
+ tests\Images\Input\Webp\alpha_filter_1_method_0.webp = tests\Images\Input\Webp\alpha_filter_1_method_0.webp
+ tests\Images\Input\Webp\alpha_filter_1_method_1.webp = tests\Images\Input\Webp\alpha_filter_1_method_1.webp
+ tests\Images\Input\Webp\alpha_filter_2.webp = tests\Images\Input\Webp\alpha_filter_2.webp
+ tests\Images\Input\Webp\alpha_filter_2_method_0.webp = tests\Images\Input\Webp\alpha_filter_2_method_0.webp
+ tests\Images\Input\Webp\alpha_filter_2_method_1.webp = tests\Images\Input\Webp\alpha_filter_2_method_1.webp
+ tests\Images\Input\Webp\alpha_filter_3.webp = tests\Images\Input\Webp\alpha_filter_3.webp
+ tests\Images\Input\Webp\alpha_filter_3_method_0.webp = tests\Images\Input\Webp\alpha_filter_3_method_0.webp
+ tests\Images\Input\Webp\alpha_filter_3_method_1.webp = tests\Images\Input\Webp\alpha_filter_3_method_1.webp
+ tests\Images\Input\Webp\alpha_no_compression.webp = tests\Images\Input\Webp\alpha_no_compression.webp
+ tests\Images\Input\Webp\animated-webp.webp = tests\Images\Input\Webp\animated-webp.webp
+ tests\Images\Input\Webp\animated2.webp = tests\Images\Input\Webp\animated2.webp
+ tests\Images\Input\Webp\animated3.webp = tests\Images\Input\Webp\animated3.webp
+ tests\Images\Input\Webp\animated_lossy.webp = tests\Images\Input\Webp\animated_lossy.webp
+ tests\Images\Input\Webp\bad_palette_index.webp = tests\Images\Input\Webp\bad_palette_index.webp
+ tests\Images\Input\Webp\big_endian_bug_393.webp = tests\Images\Input\Webp\big_endian_bug_393.webp
+ tests\Images\Input\Webp\bike_lossless.webp = tests\Images\Input\Webp\bike_lossless.webp
+ tests\Images\Input\Webp\bike_lossless_small.webp = tests\Images\Input\Webp\bike_lossless_small.webp
+ tests\Images\Input\Webp\bike_lossy.webp = tests\Images\Input\Webp\bike_lossy.webp
+ tests\Images\Input\Webp\bike_lossy_complex_filter.webp = tests\Images\Input\Webp\bike_lossy_complex_filter.webp
+ tests\Images\Input\Webp\bryce.webp = tests\Images\Input\Webp\bryce.webp
+ tests\Images\Input\Webp\bug3.webp = tests\Images\Input\Webp\bug3.webp
+ tests\Images\Input\Webp\color_cache_bits_11.webp = tests\Images\Input\Webp\color_cache_bits_11.webp
+ tests\Images\Input\Webp\earth_lossless.webp = tests\Images\Input\Webp\earth_lossless.webp
+ tests\Images\Input\Webp\earth_lossy.webp = tests\Images\Input\Webp\earth_lossy.webp
+ tests\Images\Input\Webp\exif_lossless.webp = tests\Images\Input\Webp\exif_lossless.webp
+ tests\Images\Input\Webp\exif_lossy.webp = tests\Images\Input\Webp\exif_lossy.webp
+ tests\Images\Input\Webp\flag_of_germany.png = tests\Images\Input\Webp\flag_of_germany.png
+ tests\Images\Input\Webp\lossless1.webp = tests\Images\Input\Webp\lossless1.webp
+ tests\Images\Input\Webp\lossless2.webp = tests\Images\Input\Webp\lossless2.webp
+ tests\Images\Input\Webp\lossless3.webp = tests\Images\Input\Webp\lossless3.webp
+ tests\Images\Input\Webp\lossless4.webp = tests\Images\Input\Webp\lossless4.webp
+ tests\Images\Input\Webp\lossless_alpha_small.webp = tests\Images\Input\Webp\lossless_alpha_small.webp
+ tests\Images\Input\Webp\lossless_big_random_alpha.webp = tests\Images\Input\Webp\lossless_big_random_alpha.webp
+ tests\Images\Input\Webp\lossless_color_transform.bmp = tests\Images\Input\Webp\lossless_color_transform.bmp
+ tests\Images\Input\Webp\lossless_color_transform.pam = tests\Images\Input\Webp\lossless_color_transform.pam
+ tests\Images\Input\Webp\lossless_color_transform.pgm = tests\Images\Input\Webp\lossless_color_transform.pgm
+ tests\Images\Input\Webp\lossless_color_transform.ppm = tests\Images\Input\Webp\lossless_color_transform.ppm
+ tests\Images\Input\Webp\lossless_color_transform.tiff = tests\Images\Input\Webp\lossless_color_transform.tiff
+ tests\Images\Input\Webp\lossless_color_transform.webp = tests\Images\Input\Webp\lossless_color_transform.webp
+ tests\Images\Input\Webp\lossless_vec_1_0.webp = tests\Images\Input\Webp\lossless_vec_1_0.webp
+ tests\Images\Input\Webp\lossless_vec_1_1.webp = tests\Images\Input\Webp\lossless_vec_1_1.webp
+ tests\Images\Input\Webp\lossless_vec_1_10.webp = tests\Images\Input\Webp\lossless_vec_1_10.webp
+ tests\Images\Input\Webp\lossless_vec_1_11.webp = tests\Images\Input\Webp\lossless_vec_1_11.webp
+ tests\Images\Input\Webp\lossless_vec_1_12.webp = tests\Images\Input\Webp\lossless_vec_1_12.webp
+ tests\Images\Input\Webp\lossless_vec_1_13.webp = tests\Images\Input\Webp\lossless_vec_1_13.webp
+ tests\Images\Input\Webp\lossless_vec_1_14.webp = tests\Images\Input\Webp\lossless_vec_1_14.webp
+ tests\Images\Input\Webp\lossless_vec_1_15.webp = tests\Images\Input\Webp\lossless_vec_1_15.webp
+ tests\Images\Input\Webp\lossless_vec_1_2.webp = tests\Images\Input\Webp\lossless_vec_1_2.webp
+ tests\Images\Input\Webp\lossless_vec_1_3.webp = tests\Images\Input\Webp\lossless_vec_1_3.webp
+ tests\Images\Input\Webp\lossless_vec_1_4.webp = tests\Images\Input\Webp\lossless_vec_1_4.webp
+ tests\Images\Input\Webp\lossless_vec_1_5.webp = tests\Images\Input\Webp\lossless_vec_1_5.webp
+ tests\Images\Input\Webp\lossless_vec_1_6.webp = tests\Images\Input\Webp\lossless_vec_1_6.webp
+ tests\Images\Input\Webp\lossless_vec_1_7.webp = tests\Images\Input\Webp\lossless_vec_1_7.webp
+ tests\Images\Input\Webp\lossless_vec_1_8.webp = tests\Images\Input\Webp\lossless_vec_1_8.webp
+ tests\Images\Input\Webp\lossless_vec_1_9.webp = tests\Images\Input\Webp\lossless_vec_1_9.webp
+ tests\Images\Input\Webp\lossless_vec_2_0.webp = tests\Images\Input\Webp\lossless_vec_2_0.webp
+ tests\Images\Input\Webp\lossless_vec_2_1.webp = tests\Images\Input\Webp\lossless_vec_2_1.webp
+ tests\Images\Input\Webp\lossless_vec_2_10.webp = tests\Images\Input\Webp\lossless_vec_2_10.webp
+ tests\Images\Input\Webp\lossless_vec_2_11.webp = tests\Images\Input\Webp\lossless_vec_2_11.webp
+ tests\Images\Input\Webp\lossless_vec_2_12.webp = tests\Images\Input\Webp\lossless_vec_2_12.webp
+ tests\Images\Input\Webp\lossless_vec_2_13.webp = tests\Images\Input\Webp\lossless_vec_2_13.webp
+ tests\Images\Input\Webp\lossless_vec_2_14.webp = tests\Images\Input\Webp\lossless_vec_2_14.webp
+ tests\Images\Input\Webp\lossless_vec_2_15.webp = tests\Images\Input\Webp\lossless_vec_2_15.webp
+ tests\Images\Input\Webp\lossless_vec_2_2.webp = tests\Images\Input\Webp\lossless_vec_2_2.webp
+ tests\Images\Input\Webp\lossless_vec_2_3.webp = tests\Images\Input\Webp\lossless_vec_2_3.webp
+ tests\Images\Input\Webp\lossless_vec_2_4.webp = tests\Images\Input\Webp\lossless_vec_2_4.webp
+ tests\Images\Input\Webp\lossless_vec_2_5.webp = tests\Images\Input\Webp\lossless_vec_2_5.webp
+ tests\Images\Input\Webp\lossless_vec_2_6.webp = tests\Images\Input\Webp\lossless_vec_2_6.webp
+ tests\Images\Input\Webp\lossless_vec_2_7.webp = tests\Images\Input\Webp\lossless_vec_2_7.webp
+ tests\Images\Input\Webp\lossless_vec_2_8.webp = tests\Images\Input\Webp\lossless_vec_2_8.webp
+ tests\Images\Input\Webp\lossless_vec_2_9.webp = tests\Images\Input\Webp\lossless_vec_2_9.webp
+ tests\Images\Input\Webp\lossless_vec_list.txt = tests\Images\Input\Webp\lossless_vec_list.txt
+ tests\Images\Input\Webp\lossless_with_iccp.webp = tests\Images\Input\Webp\lossless_with_iccp.webp
+ tests\Images\Input\Webp\lossy_alpha1.webp = tests\Images\Input\Webp\lossy_alpha1.webp
+ tests\Images\Input\Webp\lossy_alpha2.webp = tests\Images\Input\Webp\lossy_alpha2.webp
+ tests\Images\Input\Webp\lossy_alpha3.webp = tests\Images\Input\Webp\lossy_alpha3.webp
+ tests\Images\Input\Webp\lossy_alpha4.webp = tests\Images\Input\Webp\lossy_alpha4.webp
+ tests\Images\Input\Webp\lossy_extreme_probabilities.webp = tests\Images\Input\Webp\lossy_extreme_probabilities.webp
+ tests\Images\Input\Webp\lossy_q0_f100.webp = tests\Images\Input\Webp\lossy_q0_f100.webp
+ tests\Images\Input\Webp\lossy_with_iccp.webp = tests\Images\Input\Webp\lossy_with_iccp.webp
+ tests\Images\Input\Webp\near_lossless_75.webp = tests\Images\Input\Webp\near_lossless_75.webp
+ tests\Images\Input\Webp\peak.png = tests\Images\Input\Webp\peak.png
+ tests\Images\Input\Webp\rgb_pattern_100x100.png = tests\Images\Input\Webp\rgb_pattern_100x100.png
+ tests\Images\Input\Webp\rgb_pattern_63x63.png = tests\Images\Input\Webp\rgb_pattern_63x63.png
+ tests\Images\Input\Webp\rgb_pattern_80x80.png = tests\Images\Input\Webp\rgb_pattern_80x80.png
+ tests\Images\Input\Webp\segment01.webp = tests\Images\Input\Webp\segment01.webp
+ tests\Images\Input\Webp\segment02.webp = tests\Images\Input\Webp\segment02.webp
+ tests\Images\Input\Webp\segment03.webp = tests\Images\Input\Webp\segment03.webp
+ tests\Images\Input\Webp\small_13x1.webp = tests\Images\Input\Webp\small_13x1.webp
+ tests\Images\Input\Webp\small_1x1.webp = tests\Images\Input\Webp\small_1x1.webp
+ tests\Images\Input\Webp\small_1x13.webp = tests\Images\Input\Webp\small_1x13.webp
+ tests\Images\Input\Webp\small_31x13.webp = tests\Images\Input\Webp\small_31x13.webp
+ tests\Images\Input\Webp\sticker.webp = tests\Images\Input\Webp\sticker.webp
+ tests\Images\Input\Webp\test-nostrong.webp = tests\Images\Input\Webp\test-nostrong.webp
+ tests\Images\Input\Webp\test.webp = tests\Images\Input\Webp\test.webp
+ tests\Images\Input\Webp\testpattern_opaque.png = tests\Images\Input\Webp\testpattern_opaque.png
+ tests\Images\Input\Webp\testpattern_opaque_small.png = tests\Images\Input\Webp\testpattern_opaque_small.png
+ tests\Images\Input\Webp\very_short.webp = tests\Images\Input\Webp\very_short.webp
+ tests\Images\Input\Webp\vp80-00-comprehensive-001.webp = tests\Images\Input\Webp\vp80-00-comprehensive-001.webp
+ tests\Images\Input\Webp\vp80-00-comprehensive-002.webp = tests\Images\Input\Webp\vp80-00-comprehensive-002.webp
+ tests\Images\Input\Webp\vp80-00-comprehensive-003.webp = tests\Images\Input\Webp\vp80-00-comprehensive-003.webp
+ tests\Images\Input\Webp\vp80-00-comprehensive-004.webp = tests\Images\Input\Webp\vp80-00-comprehensive-004.webp
+ tests\Images\Input\Webp\vp80-00-comprehensive-005.webp = tests\Images\Input\Webp\vp80-00-comprehensive-005.webp
+ tests\Images\Input\Webp\vp80-00-comprehensive-006.webp = tests\Images\Input\Webp\vp80-00-comprehensive-006.webp
+ tests\Images\Input\Webp\vp80-00-comprehensive-007.webp = tests\Images\Input\Webp\vp80-00-comprehensive-007.webp
+ tests\Images\Input\Webp\vp80-00-comprehensive-008.webp = tests\Images\Input\Webp\vp80-00-comprehensive-008.webp
+ tests\Images\Input\Webp\vp80-00-comprehensive-009.webp = tests\Images\Input\Webp\vp80-00-comprehensive-009.webp
+ tests\Images\Input\Webp\vp80-00-comprehensive-010.webp = tests\Images\Input\Webp\vp80-00-comprehensive-010.webp
+ tests\Images\Input\Webp\vp80-00-comprehensive-011.webp = tests\Images\Input\Webp\vp80-00-comprehensive-011.webp
+ tests\Images\Input\Webp\vp80-00-comprehensive-012.webp = tests\Images\Input\Webp\vp80-00-comprehensive-012.webp
+ tests\Images\Input\Webp\vp80-00-comprehensive-013.webp = tests\Images\Input\Webp\vp80-00-comprehensive-013.webp
+ tests\Images\Input\Webp\vp80-00-comprehensive-014.webp = tests\Images\Input\Webp\vp80-00-comprehensive-014.webp
+ tests\Images\Input\Webp\vp80-00-comprehensive-015.webp = tests\Images\Input\Webp\vp80-00-comprehensive-015.webp
+ tests\Images\Input\Webp\vp80-00-comprehensive-016.webp = tests\Images\Input\Webp\vp80-00-comprehensive-016.webp
+ tests\Images\Input\Webp\vp80-00-comprehensive-017.webp = tests\Images\Input\Webp\vp80-00-comprehensive-017.webp
+ tests\Images\Input\Webp\vp80-01-intra-1400.webp = tests\Images\Input\Webp\vp80-01-intra-1400.webp
+ tests\Images\Input\Webp\vp80-01-intra-1411.webp = tests\Images\Input\Webp\vp80-01-intra-1411.webp
+ tests\Images\Input\Webp\vp80-01-intra-1416.webp = tests\Images\Input\Webp\vp80-01-intra-1416.webp
+ tests\Images\Input\Webp\vp80-01-intra-1417.webp = tests\Images\Input\Webp\vp80-01-intra-1417.webp
+ tests\Images\Input\Webp\vp80-02-inter-1402.webp = tests\Images\Input\Webp\vp80-02-inter-1402.webp
+ tests\Images\Input\Webp\vp80-02-inter-1412.webp = tests\Images\Input\Webp\vp80-02-inter-1412.webp
+ tests\Images\Input\Webp\vp80-02-inter-1418.webp = tests\Images\Input\Webp\vp80-02-inter-1418.webp
+ tests\Images\Input\Webp\vp80-02-inter-1424.webp = tests\Images\Input\Webp\vp80-02-inter-1424.webp
+ tests\Images\Input\Webp\vp80-03-segmentation-1401.webp = tests\Images\Input\Webp\vp80-03-segmentation-1401.webp
+ tests\Images\Input\Webp\vp80-03-segmentation-1403.webp = tests\Images\Input\Webp\vp80-03-segmentation-1403.webp
+ tests\Images\Input\Webp\vp80-03-segmentation-1407.webp = tests\Images\Input\Webp\vp80-03-segmentation-1407.webp
+ tests\Images\Input\Webp\vp80-03-segmentation-1408.webp = tests\Images\Input\Webp\vp80-03-segmentation-1408.webp
+ tests\Images\Input\Webp\vp80-03-segmentation-1409.webp = tests\Images\Input\Webp\vp80-03-segmentation-1409.webp
+ tests\Images\Input\Webp\vp80-03-segmentation-1410.webp = tests\Images\Input\Webp\vp80-03-segmentation-1410.webp
+ tests\Images\Input\Webp\vp80-03-segmentation-1413.webp = tests\Images\Input\Webp\vp80-03-segmentation-1413.webp
+ tests\Images\Input\Webp\vp80-03-segmentation-1414.webp = tests\Images\Input\Webp\vp80-03-segmentation-1414.webp
+ tests\Images\Input\Webp\vp80-03-segmentation-1415.webp = tests\Images\Input\Webp\vp80-03-segmentation-1415.webp
+ tests\Images\Input\Webp\vp80-03-segmentation-1425.webp = tests\Images\Input\Webp\vp80-03-segmentation-1425.webp
+ tests\Images\Input\Webp\vp80-03-segmentation-1426.webp = tests\Images\Input\Webp\vp80-03-segmentation-1426.webp
+ tests\Images\Input\Webp\vp80-03-segmentation-1427.webp = tests\Images\Input\Webp\vp80-03-segmentation-1427.webp
+ tests\Images\Input\Webp\vp80-03-segmentation-1432.webp = tests\Images\Input\Webp\vp80-03-segmentation-1432.webp
+ tests\Images\Input\Webp\vp80-03-segmentation-1435.webp = tests\Images\Input\Webp\vp80-03-segmentation-1435.webp
+ tests\Images\Input\Webp\vp80-03-segmentation-1436.webp = tests\Images\Input\Webp\vp80-03-segmentation-1436.webp
+ tests\Images\Input\Webp\vp80-03-segmentation-1437.webp = tests\Images\Input\Webp\vp80-03-segmentation-1437.webp
+ tests\Images\Input\Webp\vp80-03-segmentation-1441.webp = tests\Images\Input\Webp\vp80-03-segmentation-1441.webp
+ tests\Images\Input\Webp\vp80-03-segmentation-1442.webp = tests\Images\Input\Webp\vp80-03-segmentation-1442.webp
+ tests\Images\Input\Webp\vp80-04-partitions-1404.webp = tests\Images\Input\Webp\vp80-04-partitions-1404.webp
+ tests\Images\Input\Webp\vp80-04-partitions-1405.webp = tests\Images\Input\Webp\vp80-04-partitions-1405.webp
+ tests\Images\Input\Webp\vp80-04-partitions-1406.webp = tests\Images\Input\Webp\vp80-04-partitions-1406.webp
+ tests\Images\Input\Webp\vp80-05-sharpness-1428.webp = tests\Images\Input\Webp\vp80-05-sharpness-1428.webp
+ tests\Images\Input\Webp\vp80-05-sharpness-1429.webp = tests\Images\Input\Webp\vp80-05-sharpness-1429.webp
+ tests\Images\Input\Webp\vp80-05-sharpness-1430.webp = tests\Images\Input\Webp\vp80-05-sharpness-1430.webp
+ tests\Images\Input\Webp\vp80-05-sharpness-1431.webp = tests\Images\Input\Webp\vp80-05-sharpness-1431.webp
+ tests\Images\Input\Webp\vp80-05-sharpness-1433.webp = tests\Images\Input\Webp\vp80-05-sharpness-1433.webp
+ tests\Images\Input\Webp\vp80-05-sharpness-1434.webp = tests\Images\Input\Webp\vp80-05-sharpness-1434.webp
+ tests\Images\Input\Webp\vp80-05-sharpness-1438.webp = tests\Images\Input\Webp\vp80-05-sharpness-1438.webp
+ tests\Images\Input\Webp\vp80-05-sharpness-1439.webp = tests\Images\Input\Webp\vp80-05-sharpness-1439.webp
+ tests\Images\Input\Webp\vp80-05-sharpness-1440.webp = tests\Images\Input\Webp\vp80-05-sharpness-1440.webp
+ tests\Images\Input\Webp\vp80-05-sharpness-1443.webp = tests\Images\Input\Webp\vp80-05-sharpness-1443.webp
+ tests\Images\Input\Webp\yuv_test.png = tests\Images\Input\Webp\yuv_test.png
+ EndProjectSection
+EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ImageSharp.Tests", "tests\ImageSharp.Tests\ImageSharp.Tests.csproj", "{EA3000E9-2A91-4EC4-8A68-E566DEBDC4F6}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ImageSharp.Benchmarks", "tests\ImageSharp.Benchmarks\ImageSharp.Benchmarks.csproj", "{2BF743D8-2A06-412D-96D7-F448F00C5EA5}"
@@ -404,6 +569,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "issues", "issues", "{670DD4
tests\Images\Input\Png\issues\Issue_1127.png = tests\Images\Input\Png\issues\Issue_1127.png
tests\Images\Input\Png\issues\Issue_1177_1.png = tests\Images\Input\Png\issues\Issue_1177_1.png
tests\Images\Input\Png\issues\Issue_1177_2.png = tests\Images\Input\Png\issues\Issue_1177_2.png
+ tests\Images\Input\Png\issues\Issue_1765_Net6DeflateStreamRead.png = tests\Images\Input\Png\issues\Issue_1765_Net6DeflateStreamRead.png
tests\Images\Input\Png\issues\Issue_410.png = tests\Images\Input\Png\issues\Issue_410.png
tests\Images\Input\Png\issues\Issue_935.png = tests\Images\Input\Png\issues\Issue_935.png
EndProjectSection
@@ -480,61 +646,43 @@ Global
EndGlobalSection
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
- Debug|x64 = Debug|x64
- Debug|x86 = Debug|x86
+ Debug-InnerLoop|Any CPU = Debug-InnerLoop|Any CPU
Release|Any CPU = Release|Any CPU
- Release|x64 = Release|x64
- Release|x86 = Release|x86
+ Release-InnerLoop|Any CPU = Release-InnerLoop|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{2AA31A1F-142C-43F4-8687-09ABCA4B3A26}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2AA31A1F-142C-43F4-8687-09ABCA4B3A26}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {2AA31A1F-142C-43F4-8687-09ABCA4B3A26}.Debug|x64.ActiveCfg = Debug|Any CPU
- {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}.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
{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}.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
{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}.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
{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}.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
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -557,6 +705,7 @@ Global
{6458AFCB-A159-47D5-8F2B-50C95C0915E0} = {DB21FED7-E8CB-4B00-9EB2-9144D32A590A}
{39F5197B-CF6C-41A5-9739-7F97E78BB104} = {6458AFCB-A159-47D5-8F2B-50C95C0915E0}
{E1C42A6F-913B-4A7B-B1A8-2BB62843B254} = {9DA226A1-8656-49A8-A58A-A8B5C081AD66}
+ {983A31E2-5E26-4058-BD6E-03B4922D4BBF} = {9DA226A1-8656-49A8-A58A-A8B5C081AD66}
{EA3000E9-2A91-4EC4-8A68-E566DEBDC4F6} = {56801022-D71A-4FBE-BC5B-CBA08E2284EC}
{2BF743D8-2A06-412D-96D7-F448F00C5EA5} = {56801022-D71A-4FBE-BC5B-CBA08E2284EC}
{C0D7754B-5277-438E-ABEB-2BA34401B5A7} = {1799C43E-5C54-4A8F-8D64-B1475241DB0D}
diff --git a/README.md b/README.md
index 6cc8e5304..ab16bbb76 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-
+
@@ -26,9 +26,16 @@ Built against [.NET Standard 1.3](https://docs.microsoft.com/en-us/dotnet/standa
## License
- ImageSharp is licensed under the [Apache License, Version 2.0](https://opensource.org/licenses/Apache-2.0)
-- An alternative Commercial License can be purchased for projects and applications requiring support.
+- An alternative Commercial Support License can be purchased **for projects and applications requiring support**.
Please visit https://sixlabors.com/pricing for details.
+## Support Six Labors
+
+Support the efforts of the development of the Six Labors projects.
+ - [Purchase a Commercial Support License :heart:](https://sixlabors.com/pricing/)
+ - [Become a sponsor via GitHub Sponsors :heart:]( https://github.com/sponsors/SixLabors)
+ - [Become a sponsor via Open Collective :heart:](https://opencollective.com/sixlabors)
+
## Documentation
- [Detailed documentation](https://sixlabors.github.io/docs/) for the ImageSharp API is available. This includes additional conceptual documentation to help you get started.
@@ -57,7 +64,7 @@ If you prefer, you can compile ImageSharp yourself (please do and help!)
- Using [Visual Studio 2019](https://visualstudio.microsoft.com/vs/)
- Make sure you have the latest version installed
- - Make sure you have [the .NET Core 3.1 SDK](https://www.microsoft.com/net/core#windows) installed
+ - Make sure you have [the .NET 5 SDK](https://www.microsoft.com/net/core#windows) installed
Alternatively, you can work from command line and/or with a lightweight editor on **both Linux/Unix and Windows**:
@@ -96,40 +103,6 @@ Please... Spread the word, contribute algorithms, submit performance improvement
- [Scott Williams](https://github.com/tocsoft)
- [Brian Popow](https://github.com/brianpopow)
-## Sponsor Six Labors
-
-Support the efforts of the development of the Six Labors projects. [[Become a sponsor :heart:](https://opencollective.com/sixlabors#sponsor)]
-
-### Platinum Sponsors
-Become a platinum sponsor with a monthly donation of $2000 (providing 32 hours of maintenance and development) and get 2 hours of dedicated support (remote support available through chat or screen-sharing) per month.
-
-In addition you get your logo (large) on our README on GitHub and the home page (large) of sixlabors.com
-
-
-
-### Gold Sponsors
-Become a gold sponsor with a monthly donation of $1000 (providing 16 hours of maintenance and development) and get 1 hour of dedicated support (remote support available through chat or screen-sharing) per month.
-
-In addition you get your logo (large) on our README on GitHub and the home page (medium) of sixlabors.com
-
-









-
-### Silver Sponsors
-Become a silver sponsor with a monthly donation of $500 (providing 8 hours of maintenance and development) and get your logo (medium) on our README on GitHub and the product pages of sixlabors.com
-









-### Bronze Sponsors
-Become a bronze sponsor with a monthly donation of $100 and get your logo (small) on our README on GitHub.
-
-
-
-
-
-
-
-
-
-
-
diff --git a/codecov.yml b/codecov.yml
index 833fc0a51..310eefb8c 100644
--- a/codecov.yml
+++ b/codecov.yml
@@ -9,3 +9,14 @@ codecov:
# Avoid Report Expired
# https://docs.codecov.io/docs/codecov-yaml#section-expired-reports
max_report_age: off
+
+coverage:
+ # Use integer precision
+ # https://docs.codecov.com/docs/codecovyml-reference#coverageprecision
+ precision: 0
+
+ # Explicitly control coverage status checks
+ # https://docs.codecov.com/docs/commit-status#disabling-a-status
+ status:
+ project: on
+ patch: off
diff --git a/shared-infrastructure b/shared-infrastructure
index 06a733983..33cb12ca7 160000
--- a/shared-infrastructure
+++ b/shared-infrastructure
@@ -1 +1 @@
-Subproject commit 06a733983486638b9e38197c7c6eb197ecac43e6
+Subproject commit 33cb12ca77f919b44de56f344d2627cc2a108c3a
diff --git a/src/ImageSharp/Advanced/AotCompilerTools.cs b/src/ImageSharp/Advanced/AotCompilerTools.cs
index ea4cd1c8c..3961cc6c5 100644
--- a/src/ImageSharp/Advanced/AotCompilerTools.cs
+++ b/src/ImageSharp/Advanced/AotCompilerTools.cs
@@ -12,6 +12,8 @@ using SixLabors.ImageSharp.Formats.Jpeg;
using SixLabors.ImageSharp.Formats.Jpeg.Components;
using SixLabors.ImageSharp.Formats.Png;
using SixLabors.ImageSharp.Formats.Tga;
+using SixLabors.ImageSharp.Formats.Tiff;
+using SixLabors.ImageSharp.Formats.Webp;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing;
@@ -56,7 +58,7 @@ namespace SixLabors.ImageSharp.Advanced
/// necessary methods to complete the SaveAsGif call. That's it, otherwise you should NEVER need this method!!!
///
[Preserve]
- private static void SeedEverything()
+ private static void SeedPixelFormats()
{
try
{
@@ -194,11 +196,13 @@ namespace SixLabors.ImageSharp.Advanced
private static void AotCompileImageEncoderInternals()
where TPixel : unmanaged, IPixel
{
+ default(WebpEncoderCore).Encode(default, default, default);
default(BmpEncoderCore).Encode(default, default, default);
default(GifEncoderCore).Encode(default, default, default);
default(JpegEncoderCore).Encode(default, default, default);
default(PngEncoderCore).Encode(default, default, default);
default(TgaEncoderCore).Encode(default, default, default);
+ default(TiffEncoderCore).Encode(default, default, default);
}
///
@@ -209,11 +213,13 @@ namespace SixLabors.ImageSharp.Advanced
private static void AotCompileImageDecoderInternals()
where TPixel : unmanaged, IPixel
{
+ default(WebpDecoderCore).Decode(default, default, default);
default(BmpDecoderCore).Decode(default, default, default);
default(GifDecoderCore).Decode(default, default, default);
default(JpegDecoderCore).Decode(default, default, default);
default(PngDecoderCore).Decode(default, default, default);
default(TgaDecoderCore).Decode(default, default, default);
+ default(TiffDecoderCore).Decode(default, default, default);
}
///
@@ -224,11 +230,13 @@ namespace SixLabors.ImageSharp.Advanced
private static void AotCompileImageEncoders()
where TPixel : unmanaged, IPixel
{
+ AotCompileImageEncoder();
AotCompileImageEncoder();
AotCompileImageEncoder();
AotCompileImageEncoder();
AotCompileImageEncoder();
AotCompileImageEncoder();
+ AotCompileImageEncoder();
}
///
@@ -239,11 +247,13 @@ namespace SixLabors.ImageSharp.Advanced
private static void AotCompileImageDecoders()
where TPixel : unmanaged, IPixel
{
+ AotCompileImageDecoder();
AotCompileImageDecoder();
AotCompileImageDecoder();
AotCompileImageDecoder();
AotCompileImageDecoder();
AotCompileImageDecoder();
+ AotCompileImageDecoder();
}
///
diff --git a/src/ImageSharp/Advanced/ParallelExecutionSettings.cs b/src/ImageSharp/Advanced/ParallelExecutionSettings.cs
index 5415249d2..e1f36d9d6 100644
--- a/src/ImageSharp/Advanced/ParallelExecutionSettings.cs
+++ b/src/ImageSharp/Advanced/ParallelExecutionSettings.cs
@@ -3,7 +3,6 @@
using System;
using System.Threading.Tasks;
-
using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp.Advanced
diff --git a/src/ImageSharp/Color/Color.Conversions.cs b/src/ImageSharp/Color/Color.Conversions.cs
index cd3fc8fd9..bf7869e53 100644
--- a/src/ImageSharp/Color/Color.Conversions.cs
+++ b/src/ImageSharp/Color/Color.Conversions.cs
@@ -3,7 +3,6 @@
using System.Numerics;
using System.Runtime.CompilerServices;
-
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp
@@ -18,56 +17,118 @@ namespace SixLabors.ImageSharp
///
/// The containing the color information.
[MethodImpl(InliningOptions.ShortMethod)]
- public Color(Rgba64 pixel) => this.data = pixel;
+ public Color(Rgba64 pixel)
+ {
+ this.data = pixel;
+ this.boxedHighPrecisionPixel = null;
+ }
+
+ ///
+ /// Initializes a new instance of the struct.
+ ///
+ /// The containing the color information.
+ [MethodImpl(InliningOptions.ShortMethod)]
+ public Color(Rgb48 pixel)
+ {
+ this.data = new Rgba64(pixel.R, pixel.G, pixel.B, ushort.MaxValue);
+ this.boxedHighPrecisionPixel = null;
+ }
+
+ ///
+ /// Initializes a new instance of the struct.
+ ///
+ /// The containing the color information.
+ [MethodImpl(InliningOptions.ShortMethod)]
+ public Color(La32 pixel)
+ {
+ this.data = new Rgba64(pixel.L, pixel.L, pixel.L, pixel.A);
+ this.boxedHighPrecisionPixel = null;
+ }
+
+ ///
+ /// Initializes a new instance of the struct.
+ ///
+ /// The containing the color information.
+ [MethodImpl(InliningOptions.ShortMethod)]
+ public Color(L16 pixel)
+ {
+ this.data = new Rgba64(pixel.PackedValue, pixel.PackedValue, pixel.PackedValue, ushort.MaxValue);
+ this.boxedHighPrecisionPixel = null;
+ }
///
/// Initializes a new instance of the struct.
///
/// The containing the color information.
[MethodImpl(InliningOptions.ShortMethod)]
- public Color(Rgba32 pixel) => this.data = new Rgba64(pixel);
+ public Color(Rgba32 pixel)
+ {
+ this.data = new Rgba64(pixel);
+ this.boxedHighPrecisionPixel = null;
+ }
///
/// Initializes a new instance of the struct.
///
/// The containing the color information.
[MethodImpl(InliningOptions.ShortMethod)]
- public Color(Argb32 pixel) => this.data = new Rgba64(pixel);
+ public Color(Argb32 pixel)
+ {
+ this.data = new Rgba64(pixel);
+ this.boxedHighPrecisionPixel = null;
+ }
///
/// Initializes a new instance of the struct.
///
/// The containing the color information.
[MethodImpl(InliningOptions.ShortMethod)]
- public Color(Bgra32 pixel) => this.data = new Rgba64(pixel);
+ public Color(Bgra32 pixel)
+ {
+ this.data = new Rgba64(pixel);
+ this.boxedHighPrecisionPixel = null;
+ }
///
/// Initializes a new instance of the struct.
///
/// The containing the color information.
[MethodImpl(InliningOptions.ShortMethod)]
- public Color(Rgb24 pixel) => this.data = new Rgba64(pixel);
+ public Color(Rgb24 pixel)
+ {
+ this.data = new Rgba64(pixel);
+ this.boxedHighPrecisionPixel = null;
+ }
///
/// Initializes a new instance of the struct.
///
/// The containing the color information.
[MethodImpl(InliningOptions.ShortMethod)]
- public Color(Bgr24 pixel) => this.data = new Rgba64(pixel);
+ public Color(Bgr24 pixel)
+ {
+ this.data = new Rgba64(pixel);
+ this.boxedHighPrecisionPixel = null;
+ }
///
/// Initializes a new instance of the struct.
///
/// The containing the color information.
[MethodImpl(InliningOptions.ShortMethod)]
- public Color(Vector4 vector) => this.data = new Rgba64(vector);
+ public Color(Vector4 vector)
+ {
+ vector = Numerics.Clamp(vector, Vector4.Zero, Vector4.One);
+ this.boxedHighPrecisionPixel = new RgbaVector(vector.X, vector.Y, vector.Z, vector.W);
+ this.data = default;
+ }
///
/// Converts a to .
///
/// The .
/// The .
- public static explicit operator Vector4(Color color) => color.data.ToVector4();
+ public static explicit operator Vector4(Color color) => color.ToVector4();
///
/// Converts an to .
@@ -75,24 +136,82 @@ namespace SixLabors.ImageSharp
/// The .
/// The .
[MethodImpl(InliningOptions.ShortMethod)]
- public static explicit operator Color(Vector4 source) => new Color(source);
+ public static explicit operator Color(Vector4 source) => new(source);
[MethodImpl(InliningOptions.ShortMethod)]
- internal Rgba32 ToRgba32() => this.data.ToRgba32();
+ internal Rgba32 ToRgba32()
+ {
+ if (this.boxedHighPrecisionPixel is null)
+ {
+ return this.data.ToRgba32();
+ }
+
+ Rgba32 value = default;
+ this.boxedHighPrecisionPixel.ToRgba32(ref value);
+ return value;
+ }
[MethodImpl(InliningOptions.ShortMethod)]
- internal Bgra32 ToBgra32() => this.data.ToBgra32();
+ internal Bgra32 ToBgra32()
+ {
+ if (this.boxedHighPrecisionPixel is null)
+ {
+ return this.data.ToBgra32();
+ }
+
+ Bgra32 value = default;
+ value.FromScaledVector4(this.boxedHighPrecisionPixel.ToScaledVector4());
+ return value;
+ }
[MethodImpl(InliningOptions.ShortMethod)]
- internal Argb32 ToArgb32() => this.data.ToArgb32();
+ internal Argb32 ToArgb32()
+ {
+ if (this.boxedHighPrecisionPixel is null)
+ {
+ return this.data.ToArgb32();
+ }
+
+ Argb32 value = default;
+ value.FromScaledVector4(this.boxedHighPrecisionPixel.ToScaledVector4());
+ return value;
+ }
[MethodImpl(InliningOptions.ShortMethod)]
- internal Rgb24 ToRgb24() => this.data.ToRgb24();
+ internal Rgb24 ToRgb24()
+ {
+ if (this.boxedHighPrecisionPixel is null)
+ {
+ return this.data.ToRgb24();
+ }
+
+ Rgb24 value = default;
+ value.FromScaledVector4(this.boxedHighPrecisionPixel.ToScaledVector4());
+ return value;
+ }
[MethodImpl(InliningOptions.ShortMethod)]
- internal Bgr24 ToBgr24() => this.data.ToBgr24();
+ internal Bgr24 ToBgr24()
+ {
+ if (this.boxedHighPrecisionPixel is null)
+ {
+ return this.data.ToBgr24();
+ }
+
+ Bgr24 value = default;
+ value.FromScaledVector4(this.boxedHighPrecisionPixel.ToScaledVector4());
+ return value;
+ }
[MethodImpl(InliningOptions.ShortMethod)]
- internal Vector4 ToVector4() => this.data.ToVector4();
+ internal Vector4 ToVector4()
+ {
+ if (this.boxedHighPrecisionPixel is null)
+ {
+ return this.data.ToScaledVector4();
+ }
+
+ return this.boxedHighPrecisionPixel.ToScaledVector4();
+ }
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Color/Color.WebSafePalette.cs b/src/ImageSharp/Color/Color.WebSafePalette.cs
index cad6553c0..1cffb841c 100644
--- a/src/ImageSharp/Color/Color.WebSafePalette.cs
+++ b/src/ImageSharp/Color/Color.WebSafePalette.cs
@@ -163,4 +163,4 @@ namespace SixLabors.ImageSharp
YellowGreen
};
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Color/Color.cs b/src/ImageSharp/Color/Color.cs
index 72f16528a..7c21d62dd 100644
--- a/src/ImageSharp/Color/Color.cs
+++ b/src/ImageSharp/Color/Color.cs
@@ -4,8 +4,6 @@
using System;
using System.Numerics;
using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp
@@ -22,6 +20,7 @@ namespace SixLabors.ImageSharp
public readonly partial struct Color : IEquatable
{
private readonly Rgba64 data;
+ private readonly IPixel boxedHighPrecisionPixel;
[MethodImpl(InliningOptions.ShortMethod)]
private Color(byte r, byte g, byte b, byte a)
@@ -31,6 +30,8 @@ namespace SixLabors.ImageSharp
ColorNumerics.UpscaleFrom8BitTo16Bit(g),
ColorNumerics.UpscaleFrom8BitTo16Bit(b),
ColorNumerics.UpscaleFrom8BitTo16Bit(a));
+
+ this.boxedHighPrecisionPixel = null;
}
[MethodImpl(InliningOptions.ShortMethod)]
@@ -41,6 +42,15 @@ namespace SixLabors.ImageSharp
ColorNumerics.UpscaleFrom8BitTo16Bit(g),
ColorNumerics.UpscaleFrom8BitTo16Bit(b),
ushort.MaxValue);
+
+ this.boxedHighPrecisionPixel = null;
+ }
+
+ [MethodImpl(InliningOptions.ShortMethod)]
+ private Color(IPixel pixel)
+ {
+ this.boxedHighPrecisionPixel = pixel;
+ this.data = default;
}
///
@@ -53,13 +63,10 @@ namespace SixLabors.ImageSharp
/// otherwise, false.
///
[MethodImpl(InliningOptions.ShortMethod)]
- public static bool operator ==(Color left, Color right)
- {
- return left.Equals(right);
- }
+ public static bool operator ==(Color left, Color right) => left.Equals(right);
///
- /// Checks whether two structures are equal.
+ /// Checks whether two structures are not equal.
///
/// The left hand operand.
/// The right hand operand.
@@ -68,10 +75,7 @@ namespace SixLabors.ImageSharp
/// otherwise, false.
///
[MethodImpl(InliningOptions.ShortMethod)]
- public static bool operator !=(Color left, Color right)
- {
- return !left.Equals(right);
- }
+ public static bool operator !=(Color left, Color right) => !left.Equals(right);
///
/// Creates a from RGBA bytes.
@@ -82,7 +86,7 @@ namespace SixLabors.ImageSharp
/// The alpha component (0-255).
/// The .
[MethodImpl(InliningOptions.ShortMethod)]
- public static Color FromRgba(byte r, byte g, byte b, byte a) => new Color(r, g, b, a);
+ public static Color FromRgba(byte r, byte g, byte b, byte a) => new(r, g, b, a);
///
/// Creates a from RGB bytes.
@@ -92,7 +96,46 @@ namespace SixLabors.ImageSharp
/// The blue component (0-255).
/// The .
[MethodImpl(InliningOptions.ShortMethod)]
- public static Color FromRgb(byte r, byte g, byte b) => new Color(r, g, b);
+ public static Color FromRgb(byte r, byte g, byte b) => new(r, g, b);
+
+ ///
+ /// Creates a from the given .
+ ///
+ /// The pixel to convert from.
+ /// The pixel format.
+ /// The .
+ [MethodImpl(InliningOptions.ShortMethod)]
+ public static Color FromPixel(TPixel pixel)
+ where TPixel : unmanaged, IPixel
+ {
+ // Avoid boxing in case we can convert to Rgba64 safely and efficently
+ if (typeof(TPixel) == typeof(Rgba64))
+ {
+ return new((Rgba64)(object)pixel);
+ }
+ else if (typeof(TPixel) == typeof(Rgb48))
+ {
+ return new((Rgb48)(object)pixel);
+ }
+ else if (typeof(TPixel) == typeof(La32))
+ {
+ return new((La32)(object)pixel);
+ }
+ else if (typeof(TPixel) == typeof(L16))
+ {
+ return new((L16)(object)pixel);
+ }
+ else if (Unsafe.SizeOf() <= Unsafe.SizeOf())
+ {
+ Rgba32 p = default;
+ pixel.ToRgba32(ref p);
+ return new(p);
+ }
+ else
+ {
+ return new(pixel);
+ }
+ }
///
/// Creates a new instance of the struct
@@ -214,7 +257,7 @@ namespace SixLabors.ImageSharp
public override string ToString() => this.ToHex();
///
- /// Converts the color instance to a specified type.
+ /// Converts the color instance to a specified type.
///
/// The pixel type to convert to.
/// The pixel value.
@@ -222,13 +265,18 @@ namespace SixLabors.ImageSharp
public TPixel ToPixel()
where TPixel : unmanaged, IPixel
{
- TPixel pixel = default;
+ if (this.boxedHighPrecisionPixel is TPixel pixel)
+ {
+ return pixel;
+ }
+
+ pixel = default;
pixel.FromRgba64(this.data);
return pixel;
}
///
- /// Bulk converts a span of to a span of a specified type.
+ /// Bulk converts a span of to a span of a specified type.
///
/// The pixel type to convert to.
/// The configuration.
@@ -241,28 +289,38 @@ namespace SixLabors.ImageSharp
Span destination)
where TPixel : unmanaged, IPixel
{
- ReadOnlySpan rgba64Span = MemoryMarshal.Cast(source);
- PixelOperations.Instance.FromRgba64(configuration, rgba64Span, destination);
+ Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
+ for (int i = 0; i < source.Length; i++)
+ {
+ destination[i] = source[i].ToPixel();
+ }
}
///
[MethodImpl(InliningOptions.ShortMethod)]
public bool Equals(Color other)
{
- return this.data.PackedValue == other.data.PackedValue;
+ if (this.boxedHighPrecisionPixel is null && other.boxedHighPrecisionPixel is null)
+ {
+ return this.data.PackedValue == other.data.PackedValue;
+ }
+
+ return this.boxedHighPrecisionPixel?.Equals(other.boxedHighPrecisionPixel) == true;
}
///
- public override bool Equals(object obj)
- {
- return obj is Color other && this.Equals(other);
- }
+ public override bool Equals(object obj) => obj is Color other && this.Equals(other);
///
[MethodImpl(InliningOptions.ShortMethod)]
public override int GetHashCode()
{
- return this.data.PackedValue.GetHashCode();
+ if (this.boxedHighPrecisionPixel is null)
+ {
+ return this.data.PackedValue.GetHashCode();
+ }
+
+ return this.boxedHighPrecisionPixel.GetHashCode();
}
}
}
diff --git a/src/ImageSharp/ColorSpaces/CieLab.cs b/src/ImageSharp/ColorSpaces/CieLab.cs
index 4d25836ec..c1b9aab37 100644
--- a/src/ImageSharp/ColorSpaces/CieLab.cs
+++ b/src/ImageSharp/ColorSpaces/CieLab.cs
@@ -136,4 +136,4 @@ namespace SixLabors.ImageSharp.ColorSpaces
&& this.WhitePoint.Equals(other.WhitePoint);
}
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/ColorSpaces/CieLch.cs b/src/ImageSharp/ColorSpaces/CieLch.cs
index 3e94790bb..7722b705e 100644
--- a/src/ImageSharp/ColorSpaces/CieLch.cs
+++ b/src/ImageSharp/ColorSpaces/CieLch.cs
@@ -162,4 +162,4 @@ namespace SixLabors.ImageSharp.ColorSpaces
return result;
}
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/ColorSpaces/CieLchuv.cs b/src/ImageSharp/ColorSpaces/CieLchuv.cs
index 272c53556..ed8e72fc9 100644
--- a/src/ImageSharp/ColorSpaces/CieLchuv.cs
+++ b/src/ImageSharp/ColorSpaces/CieLchuv.cs
@@ -157,4 +157,4 @@ namespace SixLabors.ImageSharp.ColorSpaces
return result;
}
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/ColorSpaces/CieLuv.cs b/src/ImageSharp/ColorSpaces/CieLuv.cs
index b11447fa7..6b69b9088 100644
--- a/src/ImageSharp/ColorSpaces/CieLuv.cs
+++ b/src/ImageSharp/ColorSpaces/CieLuv.cs
@@ -137,4 +137,4 @@ namespace SixLabors.ImageSharp.ColorSpaces
&& this.WhitePoint.Equals(other.WhitePoint);
}
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/ColorSpaces/CieXyy.cs b/src/ImageSharp/ColorSpaces/CieXyy.cs
index 526c03831..5e3b444ac 100644
--- a/src/ImageSharp/ColorSpaces/CieXyy.cs
+++ b/src/ImageSharp/ColorSpaces/CieXyy.cs
@@ -100,4 +100,4 @@ namespace SixLabors.ImageSharp.ColorSpaces
&& this.Yl.Equals(other.Yl);
}
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/ColorSpaces/CieXyz.cs b/src/ImageSharp/ColorSpaces/CieXyz.cs
index aaf48c0b9..ceffd727d 100644
--- a/src/ImageSharp/ColorSpaces/CieXyz.cs
+++ b/src/ImageSharp/ColorSpaces/CieXyz.cs
@@ -103,4 +103,4 @@ namespace SixLabors.ImageSharp.ColorSpaces
&& this.Z.Equals(other.Z);
}
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/ColorSpaces/Cmyk.cs b/src/ImageSharp/ColorSpaces/Cmyk.cs
index 675f1f814..fb8efad63 100644
--- a/src/ImageSharp/ColorSpaces/Cmyk.cs
+++ b/src/ImageSharp/ColorSpaces/Cmyk.cs
@@ -108,4 +108,4 @@ namespace SixLabors.ImageSharp.ColorSpaces
&& this.K.Equals(other.K);
}
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/ColorSpaces/Companding/GammaCompanding.cs b/src/ImageSharp/ColorSpaces/Companding/GammaCompanding.cs
index b72332ebe..440aa4185 100644
--- a/src/ImageSharp/ColorSpaces/Companding/GammaCompanding.cs
+++ b/src/ImageSharp/ColorSpaces/Companding/GammaCompanding.cs
@@ -33,4 +33,4 @@ namespace SixLabors.ImageSharp.ColorSpaces.Companding
[MethodImpl(InliningOptions.ShortMethod)]
public static float Compress(float channel, float gamma) => MathF.Pow(channel, 1 / gamma);
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/ColorSpaces/Companding/Rec2020Companding.cs b/src/ImageSharp/ColorSpaces/Companding/Rec2020Companding.cs
index 2eb2537fc..957c07687 100644
--- a/src/ImageSharp/ColorSpaces/Companding/Rec2020Companding.cs
+++ b/src/ImageSharp/ColorSpaces/Companding/Rec2020Companding.cs
@@ -38,4 +38,4 @@ namespace SixLabors.ImageSharp.ColorSpaces.Companding
public static float Compress(float channel)
=> channel < Beta ? 4.5F * channel : (Alpha * MathF.Pow(channel, 0.45F)) - AlphaMinusOne;
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/ColorSpaces/Companding/Rec709Companding.cs b/src/ImageSharp/ColorSpaces/Companding/Rec709Companding.cs
index cf6f97e44..8b511aa1c 100644
--- a/src/ImageSharp/ColorSpaces/Companding/Rec709Companding.cs
+++ b/src/ImageSharp/ColorSpaces/Companding/Rec709Companding.cs
@@ -34,4 +34,4 @@ namespace SixLabors.ImageSharp.ColorSpaces.Companding
public static float Compress(float channel)
=> channel < 0.018F ? 4.5F * channel : (1.099F * MathF.Pow(channel, 0.45F)) - 0.099F;
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/ColorSpaces/Conversion/CieConstants.cs b/src/ImageSharp/ColorSpaces/Conversion/CieConstants.cs
index a81845f21..0d3568a2a 100644
--- a/src/ImageSharp/ColorSpaces/Conversion/CieConstants.cs
+++ b/src/ImageSharp/ColorSpaces/Conversion/CieConstants.cs
@@ -19,4 +19,4 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
///
public const float Kappa = 903.2963F;
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.HunterLab.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.HunterLab.cs
index 17cbcbbd5..147ffba70 100644
--- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.HunterLab.cs
+++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.HunterLab.cs
@@ -1,4 +1,4 @@
-// Copyright (c) Six Labors.
+// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
using System;
@@ -429,4 +429,4 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
return this.ToHunterLab(xyzColor);
}
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Lms.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Lms.cs
index cb5907424..7f44a3e4b 100644
--- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Lms.cs
+++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Lms.cs
@@ -424,4 +424,4 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
return this.ToLms(xyzColor);
}
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CIeLchToCieLabConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CIeLchToCieLabConverter.cs
index 2b60b2861..0b6ca4071 100644
--- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CIeLchToCieLabConverter.cs
+++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CIeLchToCieLabConverter.cs
@@ -30,4 +30,4 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
return new CieLab(l, a, b, input.WhitePoint);
}
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzAndCieXyyConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzAndCieXyyConverter.cs
index 2e048031b..ea021d73c 100644
--- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzAndCieXyyConverter.cs
+++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzAndCieXyyConverter.cs
@@ -51,4 +51,4 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
return new CieXyz(x, y, z);
}
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzAndHunterLabConverterBase.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzAndHunterLabConverterBase.cs
index 761558676..7ed2d78d8 100644
--- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzAndHunterLabConverterBase.cs
+++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzAndHunterLabConverterBase.cs
@@ -42,4 +42,4 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
return 100F * (70F / 218.11F) * (whitePoint.Y + whitePoint.Z);
}
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzAndLmsConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzAndLmsConverter.cs
index 0a6ba15fe..22f081ccd 100644
--- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzAndLmsConverter.cs
+++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzAndLmsConverter.cs
@@ -67,4 +67,4 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
return new CieXyz(vector);
}
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToCieLabConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToCieLabConverter.cs
index 7a9016261..5f16a82a4 100644
--- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToCieLabConverter.cs
+++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToCieLabConverter.cs
@@ -54,4 +54,4 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
return new CieLab(l, a, b, this.LabWhitePoint);
}
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToCieLuvConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToCieLuvConverter.cs
index 45e7589ce..031d96e71 100644
--- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToCieLuvConverter.cs
+++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToCieLuvConverter.cs
@@ -85,4 +85,4 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
private static float ComputeVp(in CieXyz input)
=> (9 * input.Y) / (input.X + (15 * input.Y) + (3 * input.Z));
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToHunterLabConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToHunterLabConverter.cs
index 2bf1bb720..0b70f8c85 100644
--- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToHunterLabConverter.cs
+++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToHunterLabConverter.cs
@@ -64,4 +64,4 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
return new HunterLab(l, a, b, this.HunterLabWhitePoint);
}
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToLinearRgbConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToLinearRgbConverter.cs
index b14705a2d..f6ee2b0d8 100644
--- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToLinearRgbConverter.cs
+++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToLinearRgbConverter.cs
@@ -53,4 +53,4 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
return new LinearRgb(vector, this.TargetWorkingSpace);
}
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CmykAndRgbConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CmykAndRgbConverter.cs
index 38c03ca18..72f543442 100644
--- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CmykAndRgbConverter.cs
+++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CmykAndRgbConverter.cs
@@ -48,4 +48,4 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
return new Cmyk(cmy.X, cmy.Y, cmy.Z, k.X);
}
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/YCbCrAndRgbConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/YCbCrAndRgbConverter.cs
index 0ae244848..3f90e8d71 100644
--- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/YCbCrAndRgbConverter.cs
+++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/YCbCrAndRgbConverter.cs
@@ -54,4 +54,4 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
return new YCbCr(y, cb, cr);
}
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/IChromaticAdaptation.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/IChromaticAdaptation.cs
index 62833475d..b787c48b3 100644
--- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/IChromaticAdaptation.cs
+++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/IChromaticAdaptation.cs
@@ -36,4 +36,4 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
CieXyz sourceWhitePoint,
in CieXyz destinationWhitePoint);
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/ColorSpaces/Hsl.cs b/src/ImageSharp/ColorSpaces/Hsl.cs
index 9df5b4656..740752e6d 100644
--- a/src/ImageSharp/ColorSpaces/Hsl.cs
+++ b/src/ImageSharp/ColorSpaces/Hsl.cs
@@ -101,4 +101,4 @@ namespace SixLabors.ImageSharp.ColorSpaces
&& this.L.Equals(other.L);
}
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/ColorSpaces/Hsv.cs b/src/ImageSharp/ColorSpaces/Hsv.cs
index 40474621a..d29e4b5b7 100644
--- a/src/ImageSharp/ColorSpaces/Hsv.cs
+++ b/src/ImageSharp/ColorSpaces/Hsv.cs
@@ -99,4 +99,4 @@ namespace SixLabors.ImageSharp.ColorSpaces
&& this.V.Equals(other.V);
}
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/ColorSpaces/HunterLab.cs b/src/ImageSharp/ColorSpaces/HunterLab.cs
index 4a0acadf4..a36ad4b9e 100644
--- a/src/ImageSharp/ColorSpaces/HunterLab.cs
+++ b/src/ImageSharp/ColorSpaces/HunterLab.cs
@@ -135,4 +135,4 @@ namespace SixLabors.ImageSharp.ColorSpaces
&& this.WhitePoint.Equals(other.WhitePoint);
}
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/ColorSpaces/Illuminants.cs b/src/ImageSharp/ColorSpaces/Illuminants.cs
index 11b66d43b..f22ab9cd0 100644
--- a/src/ImageSharp/ColorSpaces/Illuminants.cs
+++ b/src/ImageSharp/ColorSpaces/Illuminants.cs
@@ -69,4 +69,4 @@ namespace SixLabors.ImageSharp.ColorSpaces
///
public static readonly CieXyz F11 = new CieXyz(1.00962F, 1F, 0.64350F);
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/ColorSpaces/Lms.cs b/src/ImageSharp/ColorSpaces/Lms.cs
index fa6800343..e0068c92f 100644
--- a/src/ImageSharp/ColorSpaces/Lms.cs
+++ b/src/ImageSharp/ColorSpaces/Lms.cs
@@ -104,4 +104,4 @@ namespace SixLabors.ImageSharp.ColorSpaces
&& this.S.Equals(other.S);
}
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Common/ByteOrder.cs b/src/ImageSharp/Common/ByteOrder.cs
new file mode 100644
index 000000000..cc38f1cde
--- /dev/null
+++ b/src/ImageSharp/Common/ByteOrder.cs
@@ -0,0 +1,23 @@
+// Copyright (c) Six Labors.
+// Licensed under the Apache License, Version 2.0.
+
+namespace SixLabors.ImageSharp
+{
+ ///
+ /// The byte order of the data stream.
+ ///
+ public enum ByteOrder
+ {
+ ///
+ /// The big-endian byte order (Motorola).
+ /// Most-significant byte comes first, and ends with the least-significant byte.
+ ///
+ BigEndian,
+
+ ///
+ /// The little-endian byte order (Intel).
+ /// Least-significant byte comes first and ends with the most-significant byte.
+ ///
+ LittleEndian
+ }
+}
diff --git a/src/ImageSharp/Common/Constants.cs b/src/ImageSharp/Common/Constants.cs
index fd2636100..90f33fdf7 100644
--- a/src/ImageSharp/Common/Constants.cs
+++ b/src/ImageSharp/Common/Constants.cs
@@ -18,4 +18,4 @@ namespace SixLabors.ImageSharp
///
public static readonly float EpsilonSquared = Epsilon * Epsilon;
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Common/Extensions/StreamExtensions.cs b/src/ImageSharp/Common/Extensions/StreamExtensions.cs
index f2367d488..1193eccee 100644
--- a/src/ImageSharp/Common/Extensions/StreamExtensions.cs
+++ b/src/ImageSharp/Common/Extensions/StreamExtensions.cs
@@ -4,7 +4,6 @@
using System;
using System.Buffers;
using System.IO;
-using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp
{
@@ -72,12 +71,6 @@ namespace SixLabors.ImageSharp
}
}
- public static void Read(this Stream stream, IManagedByteBuffer buffer)
- => stream.Read(buffer.Array, 0, buffer.Length());
-
- public static void Write(this Stream stream, IManagedByteBuffer buffer)
- => stream.Write(buffer.Array, 0, buffer.Length());
-
#if !SUPPORTS_SPAN_STREAM
// This is a port of the CoreFX implementation and is MIT Licensed:
// https://github.com/dotnet/corefx/blob/17300169760c61a90cab8d913636c1058a30a8c1/src/Common/src/CoreLib/System/IO/Stream.cs#L742
diff --git a/src/ImageSharp/Common/Helpers/DebugGuard.cs b/src/ImageSharp/Common/Helpers/DebugGuard.cs
index 9ef7c01c6..f56cb37a8 100644
--- a/src/ImageSharp/Common/Helpers/DebugGuard.cs
+++ b/src/ImageSharp/Common/Helpers/DebugGuard.cs
@@ -37,7 +37,7 @@ namespace SixLabors
/// has a different size than
///
[Conditional("DEBUG")]
- public static void MustBeSameSized(Span target, Span other, string parameterName)
+ public static void MustBeSameSized(ReadOnlySpan target, ReadOnlySpan other, string parameterName)
where T : struct
{
if (target.Length != other.Length)
@@ -57,7 +57,7 @@ namespace SixLabors
/// has less items than
///
[Conditional("DEBUG")]
- public static void MustBeSizedAtLeast(Span target, Span minSpan, string parameterName)
+ public static void MustBeSizedAtLeast(ReadOnlySpan target, ReadOnlySpan minSpan, string parameterName)
where T : struct
{
if (target.Length < minSpan.Length)
diff --git a/src/ImageSharp/Common/Helpers/ExifResolutionValues.cs b/src/ImageSharp/Common/Helpers/ExifResolutionValues.cs
new file mode 100644
index 000000000..b6a628608
--- /dev/null
+++ b/src/ImageSharp/Common/Helpers/ExifResolutionValues.cs
@@ -0,0 +1,21 @@
+// Copyright (c) Six Labors.
+// Licensed under the Apache License, Version 2.0.
+
+namespace SixLabors.ImageSharp.Common.Helpers
+{
+ internal readonly struct ExifResolutionValues
+ {
+ public ExifResolutionValues(ushort resolutionUnit, double? horizontalResolution, double? verticalResolution)
+ {
+ this.ResolutionUnit = resolutionUnit;
+ this.HorizontalResolution = horizontalResolution;
+ this.VerticalResolution = verticalResolution;
+ }
+
+ public ushort ResolutionUnit { get; }
+
+ public double? HorizontalResolution { get; }
+
+ public double? VerticalResolution { get; }
+ }
+}
diff --git a/src/ImageSharp/Common/Helpers/InliningOptions.cs b/src/ImageSharp/Common/Helpers/InliningOptions.cs
index 4bc8ef3c8..1ae880787 100644
--- a/src/ImageSharp/Common/Helpers/InliningOptions.cs
+++ b/src/ImageSharp/Common/Helpers/InliningOptions.cs
@@ -12,6 +12,10 @@ namespace SixLabors.ImageSharp
///
internal static class InliningOptions
{
+ ///
+ /// regardless of the build conditions.
+ ///
+ public const MethodImplOptions AlwaysInline = MethodImplOptions.AggressiveInlining;
#if PROFILING
public const MethodImplOptions HotPath = MethodImplOptions.NoInlining;
public const MethodImplOptions ShortMethod = MethodImplOptions.NoInlining;
diff --git a/src/ImageSharp/Common/Helpers/Numerics.cs b/src/ImageSharp/Common/Helpers/Numerics.cs
index 610542237..ba5c588ca 100644
--- a/src/ImageSharp/Common/Helpers/Numerics.cs
+++ b/src/ImageSharp/Common/Helpers/Numerics.cs
@@ -23,6 +23,16 @@ namespace SixLabors.ImageSharp
private const int ShuffleAlphaControl = 0b_11_11_11_11;
#endif
+#if !SUPPORTS_BITOPERATIONS
+ private static ReadOnlySpan Log2DeBruijn => new byte[32]
+ {
+ 00, 09, 01, 10, 13, 21, 02, 29,
+ 11, 14, 16, 18, 22, 25, 03, 30,
+ 08, 12, 20, 28, 15, 17, 24, 07,
+ 19, 27, 23, 06, 26, 05, 04, 31
+ };
+#endif
+
///
/// Determine the Greatest CommonDivisor (GCD) of two numbers.
///
@@ -748,5 +758,134 @@ namespace SixLabors.ImageSharp
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float Lerp(float value1, float value2, float amount)
=> ((value2 - value1) * amount) + value1;
+
+#if SUPPORTS_RUNTIME_INTRINSICS
+
+ ///
+ /// Accumulates 8-bit integers into by
+ /// widening them to 32-bit integers and performing four additions.
+ ///
+ ///
+ /// byte(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16)
+ /// is widened and added onto as such:
+ ///
+ /// accumulator += i32(1, 2, 3, 4);
+ /// accumulator += i32(5, 6, 7, 8);
+ /// accumulator += i32(9, 10, 11, 12);
+ /// accumulator += i32(13, 14, 15, 16);
+ ///
+ ///
+ /// The accumulator destination.
+ /// The values to accumulate.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void Accumulate(ref Vector accumulator, Vector values)
+ {
+ Vector.Widen(values, out Vector shortLow, out Vector shortHigh);
+
+ Vector.Widen(shortLow, out Vector intLow, out Vector intHigh);
+ accumulator += intLow;
+ accumulator += intHigh;
+
+ Vector.Widen(shortHigh, out intLow, out intHigh);
+ accumulator += intLow;
+ accumulator += intHigh;
+ }
+
+ ///
+ /// Reduces elements of the vector into one sum.
+ ///
+ /// The accumulator to reduce.
+ /// The sum of all elements.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static int ReduceSum(Vector128 accumulator)
+ {
+ if (Ssse3.IsSupported)
+ {
+ Vector128 hadd = Ssse3.HorizontalAdd(accumulator, accumulator);
+ Vector128 swapped = Sse2.Shuffle(hadd, 0x1);
+ Vector128 tmp = Sse2.Add(hadd, swapped);
+
+ // Vector128.ToScalar() isn't optimized pre-net5.0 https://github.com/dotnet/runtime/pull/37882
+ return Sse2.ConvertToInt32(tmp);
+ }
+ else
+ {
+ int sum = 0;
+ for (int i = 0; i < Vector128.Count; i++)
+ {
+ sum += accumulator.GetElement(i);
+ }
+
+ return sum;
+ }
+ }
+
+ ///
+ /// Reduces even elements of the vector into one sum.
+ ///
+ /// The accumulator to reduce.
+ /// The sum of even elements.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static int EvenReduceSum(Vector256 accumulator)
+ {
+ Vector128 vsum = Sse2.Add(accumulator.GetLower(), accumulator.GetUpper()); // add upper lane to lower lane
+ vsum = Sse2.Add(vsum, Sse2.Shuffle(vsum, 0b_11_10_11_10)); // add high to low
+
+ // Vector128.ToScalar() isn't optimized pre-net5.0 https://github.com/dotnet/runtime/pull/37882
+ return Sse2.ConvertToInt32(vsum);
+ }
+#endif
+
+ ///
+ /// Calculates floored log of the specified value, base 2.
+ /// Note that by convention, input value 0 returns 0 since Log(0) is undefined.
+ ///
+ /// The value.
+ public static int Log2(uint value)
+ {
+#if SUPPORTS_BITOPERATIONS
+ return BitOperations.Log2(value);
+#else
+ return Log2SoftwareFallback(value);
+#endif
+ }
+
+#if !SUPPORTS_BITOPERATIONS
+ ///
+ /// Calculates floored log of the specified value, base 2.
+ /// Note that by convention, input value 0 returns 0 since Log(0) is undefined.
+ /// Bit hacking with deBruijn sequence, extremely fast yet does not use any intrinsics so will work on every platform/runtime.
+ ///
+ ///
+ /// Description of this bit hacking can be found here:
+ /// https://cstheory.stackexchange.com/questions/19524/using-the-de-bruijn-sequence-to-find-the-lceil-log-2-v-rceil-of-an-integer
+ ///
+ /// The value.
+ private static int Log2SoftwareFallback(uint value)
+ {
+ // No AggressiveInlining due to large method size
+ // Has conventional contract 0->0 (Log(0) is undefined) by default, no need for if checking
+
+ // Fill trailing zeros with ones, eg 00010010 becomes 00011111
+ value |= value >> 01;
+ value |= value >> 02;
+ value |= value >> 04;
+ value |= value >> 08;
+ value |= value >> 16;
+
+ // uint.MaxValue >> 27 is always in range [0 - 31] so we use Unsafe.AddByteOffset to avoid bounds check
+ return Unsafe.AddByteOffset(
+ ref MemoryMarshal.GetReference(Log2DeBruijn),
+ (IntPtr)(int)((value * 0x07C4ACDDu) >> 27)); // uint|long -> IntPtr cast on 32-bit platforms does expensive overflow checks not needed here
+ }
+#endif
+
+ ///
+ /// Fast division with ceiling for numbers.
+ ///
+ /// Divident value.
+ /// Divisor value.
+ /// Ceiled division result.
+ public static uint DivideCeil(uint value, uint divisor) => (value + divisor - 1) / divisor;
}
}
diff --git a/src/ImageSharp/Common/Helpers/RuntimeEnvironment.cs b/src/ImageSharp/Common/Helpers/RuntimeEnvironment.cs
new file mode 100644
index 000000000..5525d3de5
--- /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/Common/Helpers/SimdUtils.HwIntrinsics.cs b/src/ImageSharp/Common/Helpers/SimdUtils.HwIntrinsics.cs
index 4faf577fd..cd96b51e9 100644
--- a/src/ImageSharp/Common/Helpers/SimdUtils.HwIntrinsics.cs
+++ b/src/ImageSharp/Common/Helpers/SimdUtils.HwIntrinsics.cs
@@ -532,11 +532,12 @@ namespace SixLabors.ImageSharp
///
/// Performs a multiplication and an addition of the .
///
+ /// ret = (vm0 * vm1) + va
/// The vector to add to the intermediate result.
/// The first vector to multiply.
/// The second vector to multiply.
/// The .
- [MethodImpl(InliningOptions.ShortMethod)]
+ [MethodImpl(InliningOptions.AlwaysInline)]
public static Vector256 MultiplyAdd(
in Vector256 va,
in Vector256 vm0,
@@ -552,6 +553,30 @@ namespace SixLabors.ImageSharp
}
}
+ ///
+ /// Performs a multiplication and a substraction of the .
+ ///
+ /// ret = (vm0 * vm1) - vs
+ /// The vector to substract from the intermediate result.
+ /// The first vector to multiply.
+ /// The second vector to multiply.
+ /// The .
+ [MethodImpl(InliningOptions.ShortMethod)]
+ public static Vector256 MultiplySubstract(
+ in Vector256 vs,
+ in Vector256 vm0,
+ in Vector256 vm1)
+ {
+ if (Fma.IsSupported)
+ {
+ return Fma.MultiplySubtract(vm1, vm0, vs);
+ }
+ else
+ {
+ return Avx.Subtract(Avx.Multiply(vm0, vm1), vs);
+ }
+ }
+
///
/// as many elements as possible, slicing them down (keeping the remainder).
///
@@ -597,90 +622,89 @@ namespace SixLabors.ImageSharp
ReadOnlySpan source,
Span dest)
{
- if (Avx2.IsSupported)
+ fixed (byte* sourceBase = source)
{
- VerifySpanInput(source, dest, Vector256.Count);
+ if (Avx2.IsSupported)
+ {
+ VerifySpanInput(source, dest, Vector256.Count);
- int n = dest.Length / Vector256.Count;
+ int n = dest.Length / Vector256.Count;
- byte* sourceBase = (byte*)Unsafe.AsPointer(ref MemoryMarshal.GetReference(source));
+ ref Vector256 destBase =
+ ref Unsafe.As>(ref MemoryMarshal.GetReference(dest));
- ref Vector256 destBase =
- ref Unsafe.As>(ref MemoryMarshal.GetReference(dest));
+ var scale = Vector256.Create(1 / (float)byte.MaxValue);
- var scale = Vector256.Create(1 / (float)byte.MaxValue);
-
- for (int i = 0; i < n; i++)
- {
- int si = Vector256.Count * i;
- Vector256 i0 = Avx2.ConvertToVector256Int32(sourceBase + si);
- Vector256 i1 = Avx2.ConvertToVector256Int32(sourceBase + si + Vector256.Count);
- Vector256 i2 = Avx2.ConvertToVector256Int32(sourceBase + si + (Vector256.Count * 2));
- Vector256 i3 = Avx2.ConvertToVector256Int32(sourceBase + si + (Vector256.Count * 3));
-
- Vector256 f0 = Avx.Multiply(scale, Avx.ConvertToVector256Single(i0));
- Vector256 f1 = Avx.Multiply(scale, Avx.ConvertToVector256Single(i1));
- Vector256 f2 = Avx.Multiply(scale, Avx.ConvertToVector256Single(i2));
- Vector256 f3 = Avx.Multiply(scale, Avx.ConvertToVector256Single(i3));
-
- ref Vector256 d = ref Unsafe.Add(ref destBase, i * 4);
-
- d = f0;
- Unsafe.Add(ref d, 1) = f1;
- Unsafe.Add(ref d, 2) = f2;
- Unsafe.Add(ref d, 3) = f3;
+ for (int i = 0; i < n; i++)
+ {
+ int si = Vector256.Count * i;
+ Vector256 i0 = Avx2.ConvertToVector256Int32(sourceBase + si);
+ Vector256 i1 = Avx2.ConvertToVector256Int32(sourceBase + si + Vector256.Count);
+ Vector256 i2 = Avx2.ConvertToVector256Int32(sourceBase + si + (Vector256.Count * 2));
+ Vector256 i3 = Avx2.ConvertToVector256Int32(sourceBase + si + (Vector256.Count * 3));
+
+ Vector256 f0 = Avx.Multiply(scale, Avx.ConvertToVector256Single(i0));
+ Vector256 f1 = Avx.Multiply(scale, Avx.ConvertToVector256Single(i1));
+ Vector256 f2 = Avx.Multiply(scale, Avx.ConvertToVector256Single(i2));
+ Vector256 f3 = Avx.Multiply(scale, Avx.ConvertToVector256Single(i3));
+
+ ref Vector256 d = ref Unsafe.Add(ref destBase, i * 4);
+
+ d = f0;
+ Unsafe.Add(ref d, 1) = f1;
+ Unsafe.Add(ref d, 2) = f2;
+ Unsafe.Add(ref d, 3) = f3;
+ }
}
- }
- else
- {
- // Sse
- VerifySpanInput(source, dest, Vector128.Count);
-
- int n = dest.Length / Vector128.Count;
-
- byte* sourceBase = (byte*)Unsafe.AsPointer(ref MemoryMarshal.GetReference(source));
+ else
+ {
+ // Sse
+ VerifySpanInput(source, dest, Vector128.Count);
- ref Vector128 destBase =
- ref Unsafe.As>(ref MemoryMarshal.GetReference(dest));
+ int n = dest.Length / Vector128.Count;
- var scale = Vector128.Create(1 / (float)byte.MaxValue);
- Vector128 zero = Vector128.Zero;
+ ref Vector128 destBase =
+ ref Unsafe.As>(ref MemoryMarshal.GetReference(dest));
- for (int i = 0; i < n; i++)
- {
- int si = Vector128.Count * i;
+ var scale = Vector128.Create(1 / (float)byte.MaxValue);
+ Vector128 zero = Vector128.Zero;
- Vector128 i0, i1, i2, i3;
- if (Sse41.IsSupported)
- {
- i0 = Sse41.ConvertToVector128Int32(sourceBase + si);
- i1 = Sse41.ConvertToVector128Int32(sourceBase + si + Vector128.Count);
- i2 = Sse41.ConvertToVector128Int32(sourceBase + si + (Vector128.Count * 2));
- i3 = Sse41.ConvertToVector128Int32(sourceBase + si + (Vector128.Count * 3));
- }
- else
+ for (int i = 0; i < n; i++)
{
- Vector128 b = Sse2.LoadVector128(sourceBase + si);
- Vector128 s0 = Sse2.UnpackLow(b, zero).AsInt16();
- Vector128 s1 = Sse2.UnpackHigh(b, zero).AsInt16();
-
- i0 = Sse2.UnpackLow(s0, zero.AsInt16()).AsInt32();
- i1 = Sse2.UnpackHigh(s0, zero.AsInt16()).AsInt32();
- i2 = Sse2.UnpackLow(s1, zero.AsInt16()).AsInt32();
- i3 = Sse2.UnpackHigh(s1, zero.AsInt16()).AsInt32();
+ int si = Vector128.Count * i;
+
+ Vector128 i0, i1, i2, i3;
+ if (Sse41.IsSupported)
+ {
+ i0 = Sse41.ConvertToVector128Int32(sourceBase + si);
+ i1 = Sse41.ConvertToVector128Int32(sourceBase + si + Vector128.Count);
+ i2 = Sse41.ConvertToVector128Int32(sourceBase + si + (Vector128.Count * 2));
+ i3 = Sse41.ConvertToVector128Int32(sourceBase + si + (Vector128.Count * 3));
+ }
+ else
+ {
+ Vector128 b = Sse2.LoadVector128(sourceBase + si);
+ Vector128 s0 = Sse2.UnpackLow(b, zero).AsInt16();
+ Vector128 s1 = Sse2.UnpackHigh(b, zero).AsInt16();
+
+ i0 = Sse2.UnpackLow(s0, zero.AsInt16()).AsInt32();
+ i1 = Sse2.UnpackHigh(s0, zero.AsInt16()).AsInt32();
+ i2 = Sse2.UnpackLow(s1, zero.AsInt16()).AsInt32();
+ i3 = Sse2.UnpackHigh(s1, zero.AsInt16()).AsInt32();
+ }
+
+ Vector128 f0 = Sse.Multiply(scale, Sse2.ConvertToVector128Single(i0));
+ Vector128 f1 = Sse.Multiply(scale, Sse2.ConvertToVector128Single(i1));
+ Vector128 f2 = Sse.Multiply(scale, Sse2.ConvertToVector128Single(i2));
+ Vector128 f3 = Sse.Multiply(scale, Sse2.ConvertToVector128Single(i3));
+
+ ref Vector128 d = ref Unsafe.Add(ref destBase, i * 4);
+
+ d = f0;
+ Unsafe.Add(ref d, 1) = f1;
+ Unsafe.Add(ref d, 2) = f2;
+ Unsafe.Add(ref d, 3) = f3;
}
-
- Vector128 f0 = Sse.Multiply(scale, Sse2.ConvertToVector128Single(i0));
- Vector128 f1 = Sse.Multiply(scale, Sse2.ConvertToVector128Single(i1));
- Vector128 f2 = Sse.Multiply(scale, Sse2.ConvertToVector128Single(i2));
- Vector128 f3 = Sse.Multiply(scale, Sse2.ConvertToVector128Single(i3));
-
- ref Vector128 d = ref Unsafe.Add(ref destBase, i * 4);
-
- d = f0;
- Unsafe.Add(ref d, 1) = f1;
- Unsafe.Add(ref d, 2) = f2;
- Unsafe.Add(ref d, 3) = f3;
}
}
}
diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.Pack.cs b/src/ImageSharp/Common/Helpers/SimdUtils.Pack.cs
index fe02bd007..1ccf5ab1a 100644
--- a/src/ImageSharp/Common/Helpers/SimdUtils.Pack.cs
+++ b/src/ImageSharp/Common/Helpers/SimdUtils.Pack.cs
@@ -5,9 +5,7 @@ using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.PixelFormats;
-
#if SUPPORTS_RUNTIME_INTRINSICS
-using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.X86;
#endif
@@ -203,4 +201,4 @@ namespace SixLabors.ImageSharp
}
}
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Common/Helpers/UnitConverter.cs b/src/ImageSharp/Common/Helpers/UnitConverter.cs
index 4a6e6abcb..7ea64aa62 100644
--- a/src/ImageSharp/Common/Helpers/UnitConverter.cs
+++ b/src/ImageSharp/Common/Helpers/UnitConverter.cs
@@ -30,6 +30,11 @@ namespace SixLabors.ImageSharp.Common.Helpers
///
private const double InchesInMeter = 1 / 0.0254D;
+ ///
+ /// The default resolution unit value.
+ ///
+ private const PixelResolutionUnit DefaultResolutionUnit = PixelResolutionUnit.PixelsPerInch;
+
///
/// Scales the value from centimeters to meters.
///
@@ -89,7 +94,45 @@ namespace SixLabors.ImageSharp.Common.Helpers
IExifValue resolution = profile.GetValue(ExifTag.ResolutionUnit);
// EXIF is 1, 2, 3 so we minus "1" off the result.
- return resolution is null ? default : (PixelResolutionUnit)(byte)(resolution.Value - 1);
+ return resolution is null ? DefaultResolutionUnit : (PixelResolutionUnit)(byte)(resolution.Value - 1);
+ }
+
+ ///
+ /// Gets the exif profile resolution values.
+ ///
+ /// The resolution unit.
+ /// The horizontal resolution value.
+ /// The vertical resolution value.
+ ///
+ [MethodImpl(InliningOptions.ShortMethod)]
+ public static ExifResolutionValues GetExifResolutionValues(PixelResolutionUnit unit, double horizontal, double vertical)
+ {
+ switch (unit)
+ {
+ case PixelResolutionUnit.AspectRatio:
+ case PixelResolutionUnit.PixelsPerInch:
+ case PixelResolutionUnit.PixelsPerCentimeter:
+ break;
+ case PixelResolutionUnit.PixelsPerMeter:
+ {
+ unit = PixelResolutionUnit.PixelsPerCentimeter;
+ horizontal = MeterToCm(horizontal);
+ vertical = MeterToCm(vertical);
+ }
+
+ break;
+ default:
+ unit = PixelResolutionUnit.PixelsPerInch;
+ break;
+ }
+
+ ushort exifUnit = (ushort)(unit + 1);
+ if (unit == PixelResolutionUnit.AspectRatio)
+ {
+ return new ExifResolutionValues(exifUnit, null, null);
+ }
+
+ return new ExifResolutionValues(exifUnit, horizontal, vertical);
}
}
}
diff --git a/src/ImageSharp/Formats/Png/Zlib/Adler32.cs b/src/ImageSharp/Compression/Zlib/Adler32.cs
similarity index 53%
rename from src/ImageSharp/Formats/Png/Zlib/Adler32.cs
rename to src/ImageSharp/Compression/Zlib/Adler32.cs
index 534aba8f5..7eb3f4516 100644
--- a/src/ImageSharp/Formats/Png/Zlib/Adler32.cs
+++ b/src/ImageSharp/Compression/Zlib/Adler32.cs
@@ -9,7 +9,7 @@ using System.Runtime.Intrinsics.X86;
#endif
#pragma warning disable IDE0007 // Use implicit type
-namespace SixLabors.ImageSharp.Formats.Png.Zlib
+namespace SixLabors.ImageSharp.Compression.Zlib
{
///
/// Calculates the 32 bit Adler checksum of a given buffer according to
@@ -91,115 +91,117 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
int index = 0;
fixed (byte* bufferPtr = buffer)
- fixed (byte* tapPtr = Tap1Tap2)
{
- index += (int)blocks * BLOCK_SIZE;
- var localBufferPtr = bufferPtr;
-
- // _mm_setr_epi8 on x86
- Vector128 tap1 = Sse2.LoadVector128((sbyte*)tapPtr);
- Vector128 tap2 = Sse2.LoadVector128((sbyte*)(tapPtr + 0x10));
- Vector128 zero = Vector128.Zero;
- var ones = Vector128.Create((short)1);
-
- while (blocks > 0)
+ fixed (byte* tapPtr = Tap1Tap2)
{
- uint n = NMAX / BLOCK_SIZE; /* The NMAX constraint. */
- if (n > blocks)
- {
- n = blocks;
- }
+ index += (int)blocks * BLOCK_SIZE;
+ var localBufferPtr = bufferPtr;
- blocks -= n;
+ // _mm_setr_epi8 on x86
+ Vector128 tap1 = Sse2.LoadVector128((sbyte*)tapPtr);
+ Vector128 tap2 = Sse2.LoadVector128((sbyte*)(tapPtr + 0x10));
+ Vector128 zero = Vector128.Zero;
+ var ones = Vector128.Create((short)1);
- // Process n blocks of data. At most NMAX data bytes can be
- // processed before s2 must be reduced modulo BASE.
- Vector128 v_ps = Vector128.CreateScalar(s1 * n);
- Vector128 v_s2 = Vector128.CreateScalar(s2);
- Vector128 v_s1 = Vector128.Zero;
-
- do
+ while (blocks > 0)
{
- // Load 32 input bytes.
- Vector128 bytes1 = Sse3.LoadDquVector128(localBufferPtr);
- Vector128 bytes2 = Sse3.LoadDquVector128(localBufferPtr + 0x10);
+ uint n = NMAX / BLOCK_SIZE; /* The NMAX constraint. */
+ if (n > blocks)
+ {
+ n = blocks;
+ }
- // Add previous block byte sum to v_ps.
- v_ps = Sse2.Add(v_ps, v_s1);
+ blocks -= n;
- // Horizontally add the bytes for s1, multiply-adds the
- // bytes by [ 32, 31, 30, ... ] for s2.
- v_s1 = Sse2.Add(v_s1, Sse2.SumAbsoluteDifferences(bytes1, zero).AsUInt32());
- Vector128 mad1 = Ssse3.MultiplyAddAdjacent(bytes1, tap1);
- v_s2 = Sse2.Add(v_s2, Sse2.MultiplyAddAdjacent(mad1, ones).AsUInt32());
+ // Process n blocks of data. At most NMAX data bytes can be
+ // processed before s2 must be reduced modulo BASE.
+ Vector128 v_ps = Vector128.CreateScalar(s1 * n);
+ Vector128 v_s2 = Vector128.CreateScalar(s2);
+ Vector128 v_s1 = Vector128.Zero;
- v_s1 = Sse2.Add(v_s1, Sse2.SumAbsoluteDifferences(bytes2, zero).AsUInt32());
- Vector128 mad2 = Ssse3.MultiplyAddAdjacent(bytes2, tap2);
- v_s2 = Sse2.Add(v_s2, Sse2.MultiplyAddAdjacent(mad2, ones).AsUInt32());
+ do
+ {
+ // Load 32 input bytes.
+ Vector128 bytes1 = Sse3.LoadDquVector128(localBufferPtr);
+ Vector128 bytes2 = Sse3.LoadDquVector128(localBufferPtr + 0x10);
- localBufferPtr += BLOCK_SIZE;
- }
- while (--n > 0);
+ // Add previous block byte sum to v_ps.
+ v_ps = Sse2.Add(v_ps, v_s1);
- v_s2 = Sse2.Add(v_s2, Sse2.ShiftLeftLogical(v_ps, 5));
+ // Horizontally add the bytes for s1, multiply-adds the
+ // bytes by [ 32, 31, 30, ... ] for s2.
+ v_s1 = Sse2.Add(v_s1, Sse2.SumAbsoluteDifferences(bytes1, zero).AsUInt32());
+ Vector128 mad1 = Ssse3.MultiplyAddAdjacent(bytes1, tap1);
+ v_s2 = Sse2.Add(v_s2, Sse2.MultiplyAddAdjacent(mad1, ones).AsUInt32());
- // Sum epi32 ints v_s1(s2) and accumulate in s1(s2).
- const byte S2301 = 0b1011_0001; // A B C D -> B A D C
- const byte S1032 = 0b0100_1110; // A B C D -> C D A B
+ v_s1 = Sse2.Add(v_s1, Sse2.SumAbsoluteDifferences(bytes2, zero).AsUInt32());
+ Vector128 mad2 = Ssse3.MultiplyAddAdjacent(bytes2, tap2);
+ v_s2 = Sse2.Add(v_s2, Sse2.MultiplyAddAdjacent(mad2, ones).AsUInt32());
- v_s1 = Sse2.Add(v_s1, Sse2.Shuffle(v_s1, S1032));
+ localBufferPtr += BLOCK_SIZE;
+ }
+ while (--n > 0);
- s1 += v_s1.ToScalar();
+ v_s2 = Sse2.Add(v_s2, Sse2.ShiftLeftLogical(v_ps, 5));
- v_s2 = Sse2.Add(v_s2, Sse2.Shuffle(v_s2, S2301));
- v_s2 = Sse2.Add(v_s2, Sse2.Shuffle(v_s2, S1032));
+ // Sum epi32 ints v_s1(s2) and accumulate in s1(s2).
+ const byte S2301 = 0b1011_0001; // A B C D -> B A D C
+ const byte S1032 = 0b0100_1110; // A B C D -> C D A B
- s2 = v_s2.ToScalar();
+ v_s1 = Sse2.Add(v_s1, Sse2.Shuffle(v_s1, S1032));
- // Reduce.
- s1 %= BASE;
- s2 %= BASE;
- }
+ s1 += v_s1.ToScalar();
- if (length > 0)
- {
- if (length >= 16)
- {
- s2 += s1 += localBufferPtr[0];
- s2 += s1 += localBufferPtr[1];
- s2 += s1 += localBufferPtr[2];
- s2 += s1 += localBufferPtr[3];
- s2 += s1 += localBufferPtr[4];
- s2 += s1 += localBufferPtr[5];
- s2 += s1 += localBufferPtr[6];
- s2 += s1 += localBufferPtr[7];
- s2 += s1 += localBufferPtr[8];
- s2 += s1 += localBufferPtr[9];
- s2 += s1 += localBufferPtr[10];
- s2 += s1 += localBufferPtr[11];
- s2 += s1 += localBufferPtr[12];
- s2 += s1 += localBufferPtr[13];
- s2 += s1 += localBufferPtr[14];
- s2 += s1 += localBufferPtr[15];
+ v_s2 = Sse2.Add(v_s2, Sse2.Shuffle(v_s2, S2301));
+ v_s2 = Sse2.Add(v_s2, Sse2.Shuffle(v_s2, S1032));
- localBufferPtr += 16;
- length -= 16;
- }
+ s2 = v_s2.ToScalar();
- while (length-- > 0)
- {
- s2 += s1 += *localBufferPtr++;
+ // Reduce.
+ s1 %= BASE;
+ s2 %= BASE;
}
- if (s1 >= BASE)
+ if (length > 0)
{
- s1 -= BASE;
+ if (length >= 16)
+ {
+ s2 += s1 += localBufferPtr[0];
+ s2 += s1 += localBufferPtr[1];
+ s2 += s1 += localBufferPtr[2];
+ s2 += s1 += localBufferPtr[3];
+ s2 += s1 += localBufferPtr[4];
+ s2 += s1 += localBufferPtr[5];
+ s2 += s1 += localBufferPtr[6];
+ s2 += s1 += localBufferPtr[7];
+ s2 += s1 += localBufferPtr[8];
+ s2 += s1 += localBufferPtr[9];
+ s2 += s1 += localBufferPtr[10];
+ s2 += s1 += localBufferPtr[11];
+ s2 += s1 += localBufferPtr[12];
+ s2 += s1 += localBufferPtr[13];
+ s2 += s1 += localBufferPtr[14];
+ s2 += s1 += localBufferPtr[15];
+
+ localBufferPtr += 16;
+ length -= 16;
+ }
+
+ while (length-- > 0)
+ {
+ s2 += s1 += *localBufferPtr++;
+ }
+
+ if (s1 >= BASE)
+ {
+ s1 -= BASE;
+ }
+
+ s2 %= BASE;
}
- s2 %= BASE;
+ return s1 | (s2 << 16);
}
-
- return s1 | (s2 << 16);
}
}
#endif
diff --git a/src/ImageSharp/Formats/Png/Zlib/Crc32.Lut.cs b/src/ImageSharp/Compression/Zlib/Crc32.Lut.cs
similarity index 98%
rename from src/ImageSharp/Formats/Png/Zlib/Crc32.Lut.cs
rename to src/ImageSharp/Compression/Zlib/Crc32.Lut.cs
index 500783353..059bd9f31 100644
--- a/src/ImageSharp/Formats/Png/Zlib/Crc32.Lut.cs
+++ b/src/ImageSharp/Compression/Zlib/Crc32.Lut.cs
@@ -1,7 +1,7 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
-namespace SixLabors.ImageSharp.Formats.Png.Zlib
+namespace SixLabors.ImageSharp.Compression.Zlib
{
///
/// Contains precalulated tables for scalar calculations.
diff --git a/src/ImageSharp/Compression/Zlib/Crc32.cs b/src/ImageSharp/Compression/Zlib/Crc32.cs
new file mode 100644
index 000000000..075d6112a
--- /dev/null
+++ b/src/ImageSharp/Compression/Zlib/Crc32.cs
@@ -0,0 +1,217 @@
+// Copyright (c) Six Labors.
+// Licensed under the Apache License, Version 2.0.
+
+using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+#if SUPPORTS_RUNTIME_INTRINSICS
+using System.Runtime.Intrinsics;
+using System.Runtime.Intrinsics.X86;
+#endif
+
+namespace SixLabors.ImageSharp.Compression.Zlib
+{
+ ///
+ /// Calculates the 32 bit Cyclic Redundancy Check (CRC) checksum of a given buffer
+ /// according to the IEEE 802.3 specification.
+ ///
+ internal static partial class Crc32
+ {
+ ///
+ /// The default initial seed value of a Crc32 checksum calculation.
+ ///
+ public const uint SeedValue = 0U;
+
+#if SUPPORTS_RUNTIME_INTRINSICS
+ private const int MinBufferSize = 64;
+ private const int ChunksizeMask = 15;
+
+ // Definitions of the bit-reflected domain constants k1, k2, k3, etc and
+ // the CRC32+Barrett polynomials given at the end of the paper.
+ private static readonly ulong[] K05Poly =
+ {
+ 0x0154442bd4, 0x01c6e41596, // k1, k2
+ 0x01751997d0, 0x00ccaa009e, // k3, k4
+ 0x0163cd6124, 0x0000000000, // k5, k0
+ 0x01db710641, 0x01f7011641 // polynomial
+ };
+#endif
+
+ ///
+ /// Calculates the CRC checksum with the bytes taken from the span.
+ ///
+ /// The readonly span of bytes.
+ /// The .
+ [MethodImpl(InliningOptions.ShortMethod)]
+ public static uint Calculate(ReadOnlySpan buffer)
+ => Calculate(SeedValue, buffer);
+
+ ///
+ /// Calculates the CRC checksum with the bytes taken from the span and seed.
+ ///
+ /// The input CRC value.
+ /// The readonly span of bytes.
+ /// The .
+ [MethodImpl(InliningOptions.ShortMethod)]
+ public static uint Calculate(uint crc, ReadOnlySpan buffer)
+ {
+ if (buffer.IsEmpty)
+ {
+ return crc;
+ }
+
+#if SUPPORTS_RUNTIME_INTRINSICS
+ if (Sse41.IsSupported && Pclmulqdq.IsSupported && buffer.Length >= MinBufferSize)
+ {
+ return ~CalculateSse(~crc, buffer);
+ }
+ else
+ {
+ return ~CalculateScalar(~crc, buffer);
+ }
+#else
+ return ~CalculateScalar(~crc, buffer);
+#endif
+ }
+
+#if SUPPORTS_RUNTIME_INTRINSICS
+ // Based on https://github.com/chromium/chromium/blob/master/third_party/zlib/crc32_simd.c
+ [MethodImpl(InliningOptions.HotPath | InliningOptions.ShortMethod)]
+ private static unsafe uint CalculateSse(uint crc, ReadOnlySpan buffer)
+ {
+ int chunksize = buffer.Length & ~ChunksizeMask;
+ int length = chunksize;
+
+ fixed (byte* bufferPtr = buffer)
+ {
+ fixed (ulong* k05PolyPtr = K05Poly)
+ {
+ byte* localBufferPtr = bufferPtr;
+ ulong* localK05PolyPtr = k05PolyPtr;
+
+ // There's at least one block of 64.
+ Vector128 x1 = Sse2.LoadVector128((ulong*)(localBufferPtr + 0x00));
+ Vector128 x2 = Sse2.LoadVector128((ulong*)(localBufferPtr + 0x10));
+ Vector128 x3 = Sse2.LoadVector128((ulong*)(localBufferPtr + 0x20));
+ Vector128 x4 = Sse2.LoadVector128((ulong*)(localBufferPtr + 0x30));
+ Vector128 x5;
+
+ x1 = Sse2.Xor(x1, Sse2.ConvertScalarToVector128UInt32(crc).AsUInt64());
+
+ // k1, k2
+ Vector128 x0 = Sse2.LoadVector128(localK05PolyPtr + 0x0);
+
+ localBufferPtr += 64;
+ length -= 64;
+
+ // Parallel fold blocks of 64, if any.
+ while (length >= 64)
+ {
+ x5 = Pclmulqdq.CarrylessMultiply(x1, x0, 0x00);
+ Vector128 x6 = Pclmulqdq.CarrylessMultiply(x2, x0, 0x00);
+ Vector128 x7 = Pclmulqdq.CarrylessMultiply(x3, x0, 0x00);
+ Vector128 x8 = Pclmulqdq.CarrylessMultiply(x4, x0, 0x00);
+
+ x1 = Pclmulqdq.CarrylessMultiply(x1, x0, 0x11);
+ x2 = Pclmulqdq.CarrylessMultiply(x2, x0, 0x11);
+ x3 = Pclmulqdq.CarrylessMultiply(x3, x0, 0x11);
+ x4 = Pclmulqdq.CarrylessMultiply(x4, x0, 0x11);
+
+ Vector128 y5 = Sse2.LoadVector128((ulong*)(localBufferPtr + 0x00));
+ Vector128 y6 = Sse2.LoadVector128((ulong*)(localBufferPtr + 0x10));
+ Vector128 y7 = Sse2.LoadVector128((ulong*)(localBufferPtr + 0x20));
+ Vector128 y8 = Sse2.LoadVector128((ulong*)(localBufferPtr + 0x30));
+
+ x1 = Sse2.Xor(x1, x5);
+ x2 = Sse2.Xor(x2, x6);
+ x3 = Sse2.Xor(x3, x7);
+ x4 = Sse2.Xor(x4, x8);
+
+ x1 = Sse2.Xor(x1, y5);
+ x2 = Sse2.Xor(x2, y6);
+ x3 = Sse2.Xor(x3, y7);
+ x4 = Sse2.Xor(x4, y8);
+
+ localBufferPtr += 64;
+ length -= 64;
+ }
+
+ // Fold into 128-bits.
+ // k3, k4
+ x0 = Sse2.LoadVector128(k05PolyPtr + 0x2);
+
+ x5 = Pclmulqdq.CarrylessMultiply(x1, x0, 0x00);
+ x1 = Pclmulqdq.CarrylessMultiply(x1, x0, 0x11);
+ x1 = Sse2.Xor(x1, x2);
+ x1 = Sse2.Xor(x1, x5);
+
+ x5 = Pclmulqdq.CarrylessMultiply(x1, x0, 0x00);
+ x1 = Pclmulqdq.CarrylessMultiply(x1, x0, 0x11);
+ x1 = Sse2.Xor(x1, x3);
+ x1 = Sse2.Xor(x1, x5);
+
+ x5 = Pclmulqdq.CarrylessMultiply(x1, x0, 0x00);
+ x1 = Pclmulqdq.CarrylessMultiply(x1, x0, 0x11);
+ x1 = Sse2.Xor(x1, x4);
+ x1 = Sse2.Xor(x1, x5);
+
+ // Single fold blocks of 16, if any.
+ while (length >= 16)
+ {
+ x2 = Sse2.LoadVector128((ulong*)localBufferPtr);
+
+ x5 = Pclmulqdq.CarrylessMultiply(x1, x0, 0x00);
+ x1 = Pclmulqdq.CarrylessMultiply(x1, x0, 0x11);
+ x1 = Sse2.Xor(x1, x2);
+ x1 = Sse2.Xor(x1, x5);
+
+ localBufferPtr += 16;
+ length -= 16;
+ }
+
+ // Fold 128 - bits to 64 - bits.
+ x2 = Pclmulqdq.CarrylessMultiply(x1, x0, 0x10);
+ x3 = Vector128.Create(~0, 0, ~0, 0).AsUInt64(); // _mm_setr_epi32 on x86
+ x1 = Sse2.ShiftRightLogical128BitLane(x1, 8);
+ x1 = Sse2.Xor(x1, x2);
+
+ // k5, k0
+ x0 = Sse2.LoadScalarVector128(localK05PolyPtr + 0x4);
+
+ x2 = Sse2.ShiftRightLogical128BitLane(x1, 4);
+ x1 = Sse2.And(x1, x3);
+ x1 = Pclmulqdq.CarrylessMultiply(x1, x0, 0x00);
+ x1 = Sse2.Xor(x1, x2);
+
+ // Barret reduce to 32-bits.
+ // polynomial
+ x0 = Sse2.LoadVector128(localK05PolyPtr + 0x6);
+
+ x2 = Sse2.And(x1, x3);
+ x2 = Pclmulqdq.CarrylessMultiply(x2, x0, 0x10);
+ x2 = Sse2.And(x2, x3);
+ x2 = Pclmulqdq.CarrylessMultiply(x2, x0, 0x00);
+ x1 = Sse2.Xor(x1, x2);
+
+ crc = (uint)Sse41.Extract(x1.AsInt32(), 1);
+ return buffer.Length - chunksize == 0 ? crc : CalculateScalar(crc, buffer.Slice(chunksize));
+ }
+ }
+ }
+#endif
+
+ [MethodImpl(InliningOptions.HotPath | InliningOptions.ShortMethod)]
+ private static uint CalculateScalar(uint crc, ReadOnlySpan buffer)
+ {
+ ref uint crcTableRef = ref MemoryMarshal.GetReference(CrcTable.AsSpan());
+ ref byte bufferRef = ref MemoryMarshal.GetReference(buffer);
+
+ for (int i = 0; i < buffer.Length; i++)
+ {
+ crc = Unsafe.Add(ref crcTableRef, (int)((crc ^ Unsafe.Add(ref bufferRef, i)) & 0xFF)) ^ (crc >> 8);
+ }
+
+ return crc;
+ }
+ }
+}
diff --git a/src/ImageSharp/Compression/Zlib/DeflateCompressionLevel.cs b/src/ImageSharp/Compression/Zlib/DeflateCompressionLevel.cs
new file mode 100644
index 000000000..2edf76e7d
--- /dev/null
+++ b/src/ImageSharp/Compression/Zlib/DeflateCompressionLevel.cs
@@ -0,0 +1,81 @@
+// Copyright (c) Six Labors.
+// Licensed under the Apache License, Version 2.0.
+
+namespace SixLabors.ImageSharp.Compression.Zlib
+{
+ ///
+ /// Provides enumeration of available deflate compression levels.
+ ///
+ public enum DeflateCompressionLevel
+ {
+ ///
+ /// Level 0. Equivalent to .
+ ///
+ Level0 = 0,
+
+ ///
+ /// No compression. Equivalent to .
+ ///
+ NoCompression = Level0,
+
+ ///
+ /// Level 1. Equivalent to .
+ ///
+ Level1 = 1,
+
+ ///
+ /// Best speed compression level.
+ ///
+ BestSpeed = Level1,
+
+ ///
+ /// Level 2.
+ ///
+ Level2 = 2,
+
+ ///
+ /// Level 3.
+ ///
+ Level3 = 3,
+
+ ///
+ /// Level 4.
+ ///
+ Level4 = 4,
+
+ ///
+ /// Level 5.
+ ///
+ Level5 = 5,
+
+ ///
+ /// Level 6. Equivalent to .
+ ///
+ Level6 = 6,
+
+ ///
+ /// The default compression level. Equivalent to .
+ ///
+ DefaultCompression = Level6,
+
+ ///
+ /// Level 7.
+ ///
+ Level7 = 7,
+
+ ///
+ /// Level 8.
+ ///
+ Level8 = 8,
+
+ ///
+ /// Level 9. Equivalent to .
+ ///
+ Level9 = 9,
+
+ ///
+ /// Best compression level. Equivalent to .
+ ///
+ BestCompression = Level9,
+ }
+}
diff --git a/src/ImageSharp/Formats/Png/Zlib/DeflateThrowHelper.cs b/src/ImageSharp/Compression/Zlib/DeflateThrowHelper.cs
similarity index 96%
rename from src/ImageSharp/Formats/Png/Zlib/DeflateThrowHelper.cs
rename to src/ImageSharp/Compression/Zlib/DeflateThrowHelper.cs
index a5d129c92..02590ca25 100644
--- a/src/ImageSharp/Formats/Png/Zlib/DeflateThrowHelper.cs
+++ b/src/ImageSharp/Compression/Zlib/DeflateThrowHelper.cs
@@ -4,7 +4,7 @@
using System;
using System.Runtime.CompilerServices;
-namespace SixLabors.ImageSharp.Formats.Png.Zlib
+namespace SixLabors.ImageSharp.Compression.Zlib
{
internal static class DeflateThrowHelper
{
diff --git a/src/ImageSharp/Formats/Png/Zlib/Deflater.cs b/src/ImageSharp/Compression/Zlib/Deflater.cs
similarity index 98%
rename from src/ImageSharp/Formats/Png/Zlib/Deflater.cs
rename to src/ImageSharp/Compression/Zlib/Deflater.cs
index 838921581..7ff8342aa 100644
--- a/src/ImageSharp/Formats/Png/Zlib/Deflater.cs
+++ b/src/ImageSharp/Compression/Zlib/Deflater.cs
@@ -5,7 +5,7 @@ using System;
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Memory;
-namespace SixLabors.ImageSharp.Formats.Png.Zlib
+namespace SixLabors.ImageSharp.Compression.Zlib
{
///
/// This class compresses input with the deflate algorithm described in RFC 1951.
@@ -222,7 +222,7 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
/// The number of compressed bytes added to the output, or 0 if either
/// or returns true or length is zero.
///
- public int Deflate(byte[] output, int offset, int length)
+ public int Deflate(Span output, int offset, int length)
{
int origLength = length;
diff --git a/src/ImageSharp/Formats/Png/Zlib/DeflaterConstants.cs b/src/ImageSharp/Compression/Zlib/DeflaterConstants.cs
similarity index 98%
rename from src/ImageSharp/Formats/Png/Zlib/DeflaterConstants.cs
rename to src/ImageSharp/Compression/Zlib/DeflaterConstants.cs
index ec224d748..30bd75ffc 100644
--- a/src/ImageSharp/Formats/Png/Zlib/DeflaterConstants.cs
+++ b/src/ImageSharp/Compression/Zlib/DeflaterConstants.cs
@@ -4,7 +4,7 @@
//
using System;
-namespace SixLabors.ImageSharp.Formats.Png.Zlib
+namespace SixLabors.ImageSharp.Compression.Zlib
{
///
/// This class contains constants used for deflation.
diff --git a/src/ImageSharp/Formats/Png/Zlib/DeflaterEngine.cs b/src/ImageSharp/Compression/Zlib/DeflaterEngine.cs
similarity index 94%
rename from src/ImageSharp/Formats/Png/Zlib/DeflaterEngine.cs
rename to src/ImageSharp/Compression/Zlib/DeflaterEngine.cs
index 797f5d210..506b0f2c1 100644
--- a/src/ImageSharp/Formats/Png/Zlib/DeflaterEngine.cs
+++ b/src/ImageSharp/Compression/Zlib/DeflaterEngine.cs
@@ -6,7 +6,7 @@ using System.Buffers;
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Memory;
-namespace SixLabors.ImageSharp.Formats.Png.Zlib
+namespace SixLabors.ImageSharp.Compression.Zlib
{
///
/// Strategies for deflater
@@ -130,9 +130,9 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
/// This array contains the part of the uncompressed stream that
/// is of relevance. The current character is indexed by strstart.
///
- private IManagedByteBuffer windowMemoryOwner;
+ private IMemoryOwner windowMemoryOwner;
private MemoryHandle windowMemoryHandle;
- private readonly byte[] window;
+ private readonly Memory window;
private readonly byte* pinnedWindowPointer;
private int maxChain;
@@ -153,19 +153,19 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
// Create pinned pointers to the various buffers to allow indexing
// without bounds checks.
- this.windowMemoryOwner = memoryAllocator.AllocateManagedByteBuffer(2 * DeflaterConstants.WSIZE);
- this.window = this.windowMemoryOwner.Array;
- this.windowMemoryHandle = this.windowMemoryOwner.Memory.Pin();
+ this.windowMemoryOwner = memoryAllocator.Allocate(2 * DeflaterConstants.WSIZE);
+ this.window = this.windowMemoryOwner.Memory;
+ this.windowMemoryHandle = this.window.Pin();
this.pinnedWindowPointer = (byte*)this.windowMemoryHandle.Pointer;
this.headMemoryOwner = memoryAllocator.Allocate(DeflaterConstants.HASH_SIZE);
this.head = this.headMemoryOwner.Memory;
- this.headMemoryHandle = this.headMemoryOwner.Memory.Pin();
+ this.headMemoryHandle = this.head.Pin();
this.pinnedHeadPointer = (short*)this.headMemoryHandle.Pointer;
this.prevMemoryOwner = memoryAllocator.Allocate(DeflaterConstants.WSIZE);
this.prev = this.prevMemoryOwner.Memory;
- this.prevMemoryHandle = this.prevMemoryOwner.Memory.Pin();
+ this.prevMemoryHandle = this.prev.Pin();
this.pinnedPrevPointer = (short*)this.prevMemoryHandle.Pointer;
// We start at index 1, to avoid an implementation deficiency, that
@@ -303,7 +303,7 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
case DeflaterConstants.DEFLATE_STORED:
if (this.strstart > this.blockStart)
{
- this.huffman.FlushStoredBlock(this.window, this.blockStart, this.strstart - this.blockStart, false);
+ this.huffman.FlushStoredBlock(this.window.Span, this.blockStart, this.strstart - this.blockStart, false);
this.blockStart = this.strstart;
}
@@ -313,7 +313,7 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
case DeflaterConstants.DEFLATE_FAST:
if (this.strstart > this.blockStart)
{
- this.huffman.FlushBlock(this.window, this.blockStart, this.strstart - this.blockStart, false);
+ this.huffman.FlushBlock(this.window.Span, this.blockStart, this.strstart - this.blockStart, false);
this.blockStart = this.strstart;
}
@@ -327,7 +327,7 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
if (this.strstart > this.blockStart)
{
- this.huffman.FlushBlock(this.window, this.blockStart, this.strstart - this.blockStart, false);
+ this.huffman.FlushBlock(this.window.Span, this.blockStart, this.strstart - this.blockStart, false);
this.blockStart = this.strstart;
}
@@ -362,7 +362,10 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
more = this.inputEnd - this.inputOff;
}
- Buffer.BlockCopy(this.inputBuf, this.inputOff, this.window, this.strstart + this.lookahead, more);
+ Unsafe.CopyBlockUnaligned(
+ ref this.window.Span[this.strstart + this.lookahead],
+ ref this.inputBuf[this.inputOff],
+ unchecked((uint)more));
this.inputOff += more;
this.lookahead += more;
@@ -426,7 +429,11 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
private void SlideWindow()
{
- Unsafe.CopyBlockUnaligned(ref this.window[0], ref this.window[DeflaterConstants.WSIZE], DeflaterConstants.WSIZE);
+ Unsafe.CopyBlockUnaligned(
+ ref this.window.Span[0],
+ ref this.window.Span[DeflaterConstants.WSIZE],
+ DeflaterConstants.WSIZE);
+
this.matchStart -= DeflaterConstants.WSIZE;
this.strstart -= DeflaterConstants.WSIZE;
this.blockStart -= DeflaterConstants.WSIZE;
@@ -663,7 +670,7 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
lastBlock = false;
}
- this.huffman.FlushStoredBlock(this.window, this.blockStart, storedLength, lastBlock);
+ this.huffman.FlushStoredBlock(this.window.Span, this.blockStart, storedLength, lastBlock);
this.blockStart += storedLength;
return !(lastBlock || storedLength == 0);
}
@@ -683,7 +690,7 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
if (this.lookahead == 0)
{
// We are flushing everything
- this.huffman.FlushBlock(this.window, this.blockStart, this.strstart - this.blockStart, finish);
+ this.huffman.FlushBlock(this.window.Span, this.blockStart, this.strstart - this.blockStart, finish);
this.blockStart = this.strstart;
return false;
}
@@ -743,7 +750,7 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
if (this.huffman.IsFull())
{
bool lastBlock = finish && (this.lookahead == 0);
- this.huffman.FlushBlock(this.window, this.blockStart, this.strstart - this.blockStart, lastBlock);
+ this.huffman.FlushBlock(this.window.Span, this.blockStart, this.strstart - this.blockStart, lastBlock);
this.blockStart = this.strstart;
return !lastBlock;
}
@@ -771,7 +778,7 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
this.prevAvailable = false;
// We are flushing everything
- this.huffman.FlushBlock(this.window, this.blockStart, this.strstart - this.blockStart, finish);
+ this.huffman.FlushBlock(this.window.Span, this.blockStart, this.strstart - this.blockStart, finish);
this.blockStart = this.strstart;
return false;
}
@@ -846,7 +853,7 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
}
bool lastBlock = finish && (this.lookahead == 0) && !this.prevAvailable;
- this.huffman.FlushBlock(this.window, this.blockStart, len, lastBlock);
+ this.huffman.FlushBlock(this.window.Span, this.blockStart, len, lastBlock);
this.blockStart += len;
return !lastBlock;
}
diff --git a/src/ImageSharp/Formats/Png/Zlib/DeflaterHuffman.cs b/src/ImageSharp/Compression/Zlib/DeflaterHuffman.cs
similarity index 97%
rename from src/ImageSharp/Formats/Png/Zlib/DeflaterHuffman.cs
rename to src/ImageSharp/Compression/Zlib/DeflaterHuffman.cs
index 96b47fb24..27a8d5671 100644
--- a/src/ImageSharp/Formats/Png/Zlib/DeflaterHuffman.cs
+++ b/src/ImageSharp/Compression/Zlib/DeflaterHuffman.cs
@@ -7,7 +7,7 @@ using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Memory;
-namespace SixLabors.ImageSharp.Formats.Png.Zlib
+namespace SixLabors.ImageSharp.Compression.Zlib
{
///
/// Performs Deflate Huffman encoding.
@@ -41,11 +41,11 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
private Tree blTree;
// Buffer for distances
- private readonly IMemoryOwner distanceManagedBuffer;
+ private readonly IMemoryOwner distanceMemoryOwner;
private readonly short* pinnedDistanceBuffer;
private MemoryHandle distanceBufferHandle;
- private readonly IMemoryOwner literalManagedBuffer;
+ private readonly IMemoryOwner literalMemoryOwner;
private readonly short* pinnedLiteralBuffer;
private MemoryHandle literalBufferHandle;
@@ -65,12 +65,12 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
this.distTree = new Tree(memoryAllocator, DistanceNumber, 1, 15);
this.blTree = new Tree(memoryAllocator, BitLengthNumber, 4, 7);
- this.distanceManagedBuffer = memoryAllocator.Allocate(BufferSize);
- this.distanceBufferHandle = this.distanceManagedBuffer.Memory.Pin();
+ this.distanceMemoryOwner = memoryAllocator.Allocate(BufferSize);
+ this.distanceBufferHandle = this.distanceMemoryOwner.Memory.Pin();
this.pinnedDistanceBuffer = (short*)this.distanceBufferHandle.Pointer;
- this.literalManagedBuffer = memoryAllocator.Allocate(BufferSize);
- this.literalBufferHandle = this.literalManagedBuffer.Memory.Pin();
+ this.literalMemoryOwner = memoryAllocator.Allocate(BufferSize);
+ this.literalBufferHandle = this.literalMemoryOwner.Memory.Pin();
this.pinnedLiteralBuffer = (short*)this.literalBufferHandle.Pointer;
}
@@ -239,7 +239,7 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
/// Count of bytes to write
/// True if this is the last block
[MethodImpl(InliningOptions.ShortMethod)]
- public void FlushStoredBlock(byte[] stored, int storedOffset, int storedLength, bool lastBlock)
+ public void FlushStoredBlock(ReadOnlySpan stored, int storedOffset, int storedLength, bool lastBlock)
{
this.Pending.WriteBits((DeflaterConstants.STORED_BLOCK << 1) + (lastBlock ? 1 : 0), 3);
this.Pending.AlignToByte();
@@ -256,7 +256,7 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
/// Index of first byte to flush
/// Count of bytes to flush
/// True if this is the last block
- public void FlushBlock(byte[] stored, int storedOffset, int storedLength, bool lastBlock)
+ public void FlushBlock(ReadOnlySpan stored, int storedOffset, int storedLength, bool lastBlock)
{
this.literalTree.Frequencies[EofSymbol]++;
@@ -286,13 +286,13 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
+ this.extraBits;
int static_len = this.extraBits;
- ref byte staticLLengthRef = ref MemoryMarshal.GetReference(StaticLLength);
+ ref byte staticLLengthRef = ref MemoryMarshal.GetReference(StaticLLength);
for (int i = 0; i < LiteralNumber; i++)
{
static_len += this.literalTree.Frequencies[i] * Unsafe.Add(ref staticLLengthRef, i);
}
- ref byte staticDLengthRef = ref MemoryMarshal.GetReference(StaticDLength);
+ ref byte staticDLengthRef = ref MemoryMarshal.GetReference(StaticDLength);
for (int i = 0; i < DistanceNumber; i++)
{
static_len += this.distTree.Frequencies[i] * Unsafe.Add(ref staticDLengthRef, i);
@@ -419,9 +419,9 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
{
this.Pending.Dispose();
this.distanceBufferHandle.Dispose();
- this.distanceManagedBuffer.Dispose();
+ this.distanceMemoryOwner.Dispose();
this.literalBufferHandle.Dispose();
- this.literalManagedBuffer.Dispose();
+ this.literalMemoryOwner.Dispose();
this.literalTree.Dispose();
this.blTree.Dispose();
@@ -484,7 +484,7 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
private IMemoryOwner frequenciesMemoryOwner;
private MemoryHandle frequenciesMemoryHandle;
- private IManagedByteBuffer lengthsMemoryOwner;
+ private IMemoryOwner lengthsMemoryOwner;
private MemoryHandle lengthsMemoryHandle;
public Tree(MemoryAllocator memoryAllocator, int elements, int minCodes, int maxLength)
@@ -498,7 +498,7 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
this.frequenciesMemoryHandle = this.frequenciesMemoryOwner.Memory.Pin();
this.Frequencies = (short*)this.frequenciesMemoryHandle.Pointer;
- this.lengthsMemoryOwner = memoryAllocator.AllocateManagedByteBuffer(elements);
+ this.lengthsMemoryOwner = memoryAllocator.Allocate(elements);
this.lengthsMemoryHandle = this.lengthsMemoryOwner.Memory.Pin();
this.Length = (byte*)this.lengthsMemoryHandle.Pointer;
diff --git a/src/ImageSharp/Formats/Png/Zlib/DeflaterOutputStream.cs b/src/ImageSharp/Compression/Zlib/DeflaterOutputStream.cs
similarity index 85%
rename from src/ImageSharp/Formats/Png/Zlib/DeflaterOutputStream.cs
rename to src/ImageSharp/Compression/Zlib/DeflaterOutputStream.cs
index 5c5651996..d949ddf38 100644
--- a/src/ImageSharp/Formats/Png/Zlib/DeflaterOutputStream.cs
+++ b/src/ImageSharp/Compression/Zlib/DeflaterOutputStream.cs
@@ -2,10 +2,11 @@
// Licensed under the Apache License, Version 2.0.
using System;
+using System.Buffers;
using System.IO;
using SixLabors.ImageSharp.Memory;
-namespace SixLabors.ImageSharp.Formats.Png.Zlib
+namespace SixLabors.ImageSharp.Compression.Zlib
{
///
/// A special stream deflating or compressing the bytes that are
@@ -14,8 +15,8 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
internal sealed class DeflaterOutputStream : Stream
{
private const int BufferLength = 512;
- private IManagedByteBuffer memoryOwner;
- private readonly byte[] buffer;
+ private IMemoryOwner memoryOwner;
+ private readonly Memory buffer;
private Deflater deflater;
private readonly Stream rawStream;
private bool isDisposed;
@@ -29,8 +30,8 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
public DeflaterOutputStream(MemoryAllocator memoryAllocator, Stream rawStream, int compressionLevel)
{
this.rawStream = rawStream;
- this.memoryOwner = memoryAllocator.AllocateManagedByteBuffer(BufferLength);
- this.buffer = this.memoryOwner.Array;
+ this.memoryOwner = memoryAllocator.Allocate(BufferLength);
+ this.buffer = this.memoryOwner.Memory;
this.deflater = new Deflater(memoryAllocator, compressionLevel);
}
@@ -49,15 +50,9 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
///
public override long Position
{
- get
- {
- return this.rawStream.Position;
- }
+ get => this.rawStream.Position;
- set
- {
- throw new NotSupportedException();
- }
+ set => throw new NotSupportedException();
}
///
@@ -93,14 +88,14 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
{
while (flushing || !this.deflater.IsNeedingInput)
{
- int deflateCount = this.deflater.Deflate(this.buffer, 0, BufferLength);
+ int deflateCount = this.deflater.Deflate(this.buffer.Span, 0, BufferLength);
if (deflateCount <= 0)
{
break;
}
- this.rawStream.Write(this.buffer, 0, deflateCount);
+ this.rawStream.Write(this.buffer.Span.Slice(0, deflateCount));
}
if (!this.deflater.IsNeedingInput)
@@ -114,13 +109,13 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
this.deflater.Finish();
while (!this.deflater.IsFinished)
{
- int len = this.deflater.Deflate(this.buffer, 0, BufferLength);
+ int len = this.deflater.Deflate(this.buffer.Span, 0, BufferLength);
if (len <= 0)
{
break;
}
- this.rawStream.Write(this.buffer, 0, len);
+ this.rawStream.Write(this.buffer.Span.Slice(0, len));
}
if (!this.deflater.IsFinished)
diff --git a/src/ImageSharp/Formats/Png/Zlib/DeflaterPendingBuffer.cs b/src/ImageSharp/Compression/Zlib/DeflaterPendingBuffer.cs
similarity index 83%
rename from src/ImageSharp/Formats/Png/Zlib/DeflaterPendingBuffer.cs
rename to src/ImageSharp/Compression/Zlib/DeflaterPendingBuffer.cs
index f702a7ead..8f2c8d398 100644
--- a/src/ImageSharp/Formats/Png/Zlib/DeflaterPendingBuffer.cs
+++ b/src/ImageSharp/Compression/Zlib/DeflaterPendingBuffer.cs
@@ -4,18 +4,19 @@
using System;
using System.Buffers;
using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Memory;
-namespace SixLabors.ImageSharp.Formats.Png.Zlib
+namespace SixLabors.ImageSharp.Compression.Zlib
{
///
/// Stores pending data for writing data to the Deflater.
///
internal sealed unsafe class DeflaterPendingBuffer : IDisposable
{
- private readonly byte[] buffer;
+ private readonly Memory buffer;
private readonly byte* pinnedBuffer;
- private IManagedByteBuffer bufferMemoryOwner;
+ private IMemoryOwner bufferMemoryOwner;
private MemoryHandle bufferMemoryHandle;
private int start;
@@ -29,9 +30,9 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
/// The memory allocator to use for buffer allocations.
public DeflaterPendingBuffer(MemoryAllocator memoryAllocator)
{
- this.bufferMemoryOwner = memoryAllocator.AllocateManagedByteBuffer(DeflaterConstants.PENDING_BUF_SIZE);
- this.buffer = this.bufferMemoryOwner.Array;
- this.bufferMemoryHandle = this.bufferMemoryOwner.Memory.Pin();
+ this.bufferMemoryOwner = memoryAllocator.Allocate(DeflaterConstants.PENDING_BUF_SIZE);
+ this.buffer = this.bufferMemoryOwner.Memory;
+ this.bufferMemoryHandle = this.buffer.Pin();
this.pinnedBuffer = (byte*)this.bufferMemoryHandle.Pointer;
}
@@ -70,9 +71,13 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
/// The offset of first byte to write.
/// The number of bytes to write.
[MethodImpl(InliningOptions.ShortMethod)]
- public void WriteBlock(byte[] block, int offset, int length)
+ public void WriteBlock(ReadOnlySpan block, int offset, int length)
{
- Unsafe.CopyBlockUnaligned(ref this.buffer[this.end], ref block[offset], unchecked((uint)length));
+ Unsafe.CopyBlockUnaligned(
+ ref this.buffer.Span[this.end],
+ ref MemoryMarshal.GetReference(block.Slice(offset)),
+ unchecked((uint)length));
+
this.end += length;
}
@@ -136,7 +141,7 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
/// The offset into output array.
/// The maximum number of bytes to store.
/// The number of bytes flushed.
- public int Flush(byte[] output, int offset, int length)
+ public int Flush(Span output, int offset, int length)
{
if (this.BitCount >= 8)
{
@@ -149,13 +154,19 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
{
length = this.end - this.start;
- Unsafe.CopyBlockUnaligned(ref output[offset], ref this.buffer[this.start], unchecked((uint)length));
+ Unsafe.CopyBlockUnaligned(
+ ref output[offset],
+ ref this.buffer.Span[this.start],
+ unchecked((uint)length));
this.start = 0;
this.end = 0;
}
else
{
- Unsafe.CopyBlockUnaligned(ref output[offset], ref this.buffer[this.start], unchecked((uint)length));
+ Unsafe.CopyBlockUnaligned(
+ ref output[offset],
+ ref this.buffer.Span[this.start],
+ unchecked((uint)length));
this.start += length;
}
diff --git a/src/ImageSharp/Formats/Png/Zlib/README.md b/src/ImageSharp/Compression/Zlib/README.md
similarity index 100%
rename from src/ImageSharp/Formats/Png/Zlib/README.md
rename to src/ImageSharp/Compression/Zlib/README.md
diff --git a/src/ImageSharp/Formats/Png/Zlib/ZlibDeflateStream.cs b/src/ImageSharp/Compression/Zlib/ZlibDeflateStream.cs
similarity index 89%
rename from src/ImageSharp/Formats/Png/Zlib/ZlibDeflateStream.cs
rename to src/ImageSharp/Compression/Zlib/ZlibDeflateStream.cs
index 06c6e3dea..44883665a 100644
--- a/src/ImageSharp/Formats/Png/Zlib/ZlibDeflateStream.cs
+++ b/src/ImageSharp/Compression/Zlib/ZlibDeflateStream.cs
@@ -4,9 +4,10 @@
using System;
using System.IO;
using System.Runtime.CompilerServices;
+using SixLabors.ImageSharp.Formats.Png;
using SixLabors.ImageSharp.Memory;
-namespace SixLabors.ImageSharp.Formats.Png.Zlib
+namespace SixLabors.ImageSharp.Compression.Zlib
{
///
/// Provides methods and properties for compressing streams by using the Zlib Deflate algorithm.
@@ -39,9 +40,19 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
///
/// The stream responsible for compressing the input stream.
///
- // private DeflateStream deflateStream;
private DeflaterOutputStream deflateStream;
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The memory allocator to use for buffer allocations.
+ /// The stream to compress.
+ /// The compression level.
+ public ZlibDeflateStream(MemoryAllocator memoryAllocator, Stream stream, DeflateCompressionLevel level)
+ : this(memoryAllocator, stream, (PngCompressionLevel)level)
+ {
+ }
+
///
/// Initializes a new instance of the class.
///
diff --git a/src/ImageSharp/Formats/Png/Zlib/ZlibInflateStream.cs b/src/ImageSharp/Compression/Zlib/ZlibInflateStream.cs
similarity index 99%
rename from src/ImageSharp/Formats/Png/Zlib/ZlibInflateStream.cs
rename to src/ImageSharp/Compression/Zlib/ZlibInflateStream.cs
index 52ef0e85b..f4b0543b8 100644
--- a/src/ImageSharp/Formats/Png/Zlib/ZlibInflateStream.cs
+++ b/src/ImageSharp/Compression/Zlib/ZlibInflateStream.cs
@@ -6,7 +6,7 @@ using System.IO;
using System.IO.Compression;
using SixLabors.ImageSharp.IO;
-namespace SixLabors.ImageSharp.Formats.Png.Zlib
+namespace SixLabors.ImageSharp.Compression.Zlib
{
///
/// Provides methods and properties for deframing streams from PNGs.
diff --git a/src/ImageSharp/Formats/Png/Zlib/fast-crc-computation-generic-polynomials-pclmulqdq-paper.pdf b/src/ImageSharp/Compression/Zlib/fast-crc-computation-generic-polynomials-pclmulqdq-paper.pdf
similarity index 100%
rename from src/ImageSharp/Formats/Png/Zlib/fast-crc-computation-generic-polynomials-pclmulqdq-paper.pdf
rename to src/ImageSharp/Compression/Zlib/fast-crc-computation-generic-polynomials-pclmulqdq-paper.pdf
diff --git a/src/ImageSharp/Configuration.cs b/src/ImageSharp/Configuration.cs
index 062bcb229..ea9524827 100644
--- a/src/ImageSharp/Configuration.cs
+++ b/src/ImageSharp/Configuration.cs
@@ -10,6 +10,8 @@ using SixLabors.ImageSharp.Formats.Gif;
using SixLabors.ImageSharp.Formats.Jpeg;
using SixLabors.ImageSharp.Formats.Png;
using SixLabors.ImageSharp.Formats.Tga;
+using SixLabors.ImageSharp.Formats.Tiff;
+using SixLabors.ImageSharp.Formats.Webp;
using SixLabors.ImageSharp.IO;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Processing;
@@ -39,7 +41,7 @@ namespace SixLabors.ImageSharp
///
/// Initializes a new instance of the class.
///
- /// A collection of configuration modules to register
+ /// A collection of configuration modules to register.
public Configuration(params IConfigurationModule[] configurationModules)
{
if (configurationModules != null)
@@ -77,7 +79,7 @@ namespace SixLabors.ImageSharp
///
/// Gets or sets the size of the buffer to use when working with streams.
- /// Intitialized with by default.
+ /// Initialized with by default.
///
public int StreamProcessingBufferSize
{
@@ -94,9 +96,9 @@ namespace SixLabors.ImageSharp
}
///
- /// Gets a set of properties for the Congiguration.
+ /// Gets a set of properties for the Configuration.
///
- /// This can be used for storing global settings and defaults to be accessable to processors.
+ /// This can be used for storing global settings and defaults to be accessible to processors.
public IDictionary
public enum BmpBitsPerPixel : short
{
+ ///
+ /// 1 bit per pixel.
+ ///
+ Pixel1 = 1,
+
+ ///
+ /// 4 bits per pixel.
+ ///
+ Pixel4 = 4,
+
///
/// 8 bits per pixel. Each pixel consists of 1 byte.
///
@@ -28,4 +38,4 @@ namespace SixLabors.ImageSharp.Formats.Bmp
///
Pixel32 = 32
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Formats/Bmp/BmpConfigurationModule.cs b/src/ImageSharp/Formats/Bmp/BmpConfigurationModule.cs
index 5505cd5e6..0bec34ffb 100644
--- a/src/ImageSharp/Formats/Bmp/BmpConfigurationModule.cs
+++ b/src/ImageSharp/Formats/Bmp/BmpConfigurationModule.cs
@@ -16,4 +16,4 @@ namespace SixLabors.ImageSharp.Formats.Bmp
configuration.ImageFormatsManager.AddImageFormatDetector(new BmpImageFormatDetector());
}
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Formats/Bmp/BmpConstants.cs b/src/ImageSharp/Formats/Bmp/BmpConstants.cs
index d6c86e4db..0b9499eeb 100644
--- a/src/ImageSharp/Formats/Bmp/BmpConstants.cs
+++ b/src/ImageSharp/Formats/Bmp/BmpConstants.cs
@@ -56,4 +56,4 @@ namespace SixLabors.ImageSharp.Formats.Bmp
public const int Pointer = 0x5450;
}
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs
index 0be038572..8919befcb 100644
--- a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs
+++ b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs
@@ -817,31 +817,29 @@ namespace SixLabors.ImageSharp.Formats.Bmp
padding = 4 - padding;
}
- using (IManagedByteBuffer row = this.memoryAllocator.AllocateManagedByteBuffer(arrayWidth + padding, AllocationOptions.Clean))
+ using IMemoryOwner row = this.memoryAllocator.Allocate(arrayWidth + padding, AllocationOptions.Clean);
+ TPixel color = default;
+ Span rowSpan = row.GetSpan();
+
+ for (int y = 0; y < height; y++)
{
- TPixel color = default;
- Span rowSpan = row.GetSpan();
+ int newY = Invert(y, height, inverted);
+ this.stream.Read(rowSpan);
+ int offset = 0;
+ Span pixelRow = pixels.GetRowSpan(newY);
- for (int y = 0; y < height; y++)
+ for (int x = 0; x < arrayWidth; x++)
{
- int newY = Invert(y, height, inverted);
- this.stream.Read(row.Array, 0, row.Length());
- int offset = 0;
- Span pixelRow = pixels.GetRowSpan(newY);
-
- for (int x = 0; x < arrayWidth; x++)
+ int colOffset = x * ppb;
+ for (int shift = 0, newX = colOffset; shift < ppb && newX < width; shift++, newX++)
{
- int colOffset = x * ppb;
- for (int shift = 0, newX = colOffset; shift < ppb && newX < width; shift++, newX++)
- {
- int colorIndex = ((rowSpan[offset] >> (8 - bitsPerPixel - (shift * bitsPerPixel))) & mask) * bytesPerColorMapEntry;
-
- color.FromBgr24(Unsafe.As(ref colors[colorIndex]));
- pixelRow[newX] = color;
- }
+ int colorIndex = ((rowSpan[offset] >> (8 - bitsPerPixel - (shift * bitsPerPixel))) & mask) * bytesPerColorMapEntry;
- offset++;
+ color.FromBgr24(Unsafe.As(ref colors[colorIndex]));
+ pixelRow[newX] = color;
}
+
+ offset++;
}
}
}
@@ -873,29 +871,29 @@ namespace SixLabors.ImageSharp.Formats.Bmp
int greenMaskBits = CountBits((uint)greenMask);
int blueMaskBits = CountBits((uint)blueMask);
- using (IManagedByteBuffer buffer = this.memoryAllocator.AllocateManagedByteBuffer(stride))
+ using IMemoryOwner buffer = this.memoryAllocator.Allocate(stride);
+ Span bufferSpan = buffer.GetSpan();
+
+ for (int y = 0; y < height; y++)
{
- for (int y = 0; y < height; y++)
- {
- this.stream.Read(buffer.Array, 0, stride);
- int newY = Invert(y, height, inverted);
- Span pixelRow = pixels.GetRowSpan(newY);
+ this.stream.Read(bufferSpan);
+ int newY = Invert(y, height, inverted);
+ Span pixelRow = pixels.GetRowSpan(newY);
- int offset = 0;
- for (int x = 0; x < width; x++)
- {
- short temp = BitConverter.ToInt16(buffer.Array, offset);
+ int offset = 0;
+ for (int x = 0; x < width; x++)
+ {
+ short temp = BinaryPrimitives.ReadInt16LittleEndian(bufferSpan.Slice(offset));
- // Rescale values, so the values range from 0 to 255.
- int r = (redMaskBits == 5) ? GetBytesFrom5BitValue((temp & redMask) >> rightShiftRedMask) : GetBytesFrom6BitValue((temp & redMask) >> rightShiftRedMask);
- int g = (greenMaskBits == 5) ? GetBytesFrom5BitValue((temp & greenMask) >> rightShiftGreenMask) : GetBytesFrom6BitValue((temp & greenMask) >> rightShiftGreenMask);
- int b = (blueMaskBits == 5) ? GetBytesFrom5BitValue((temp & blueMask) >> rightShiftBlueMask) : GetBytesFrom6BitValue((temp & blueMask) >> rightShiftBlueMask);
- var rgb = new Rgb24((byte)r, (byte)g, (byte)b);
+ // Rescale values, so the values range from 0 to 255.
+ int r = (redMaskBits == 5) ? GetBytesFrom5BitValue((temp & redMask) >> rightShiftRedMask) : GetBytesFrom6BitValue((temp & redMask) >> rightShiftRedMask);
+ int g = (greenMaskBits == 5) ? GetBytesFrom5BitValue((temp & greenMask) >> rightShiftGreenMask) : GetBytesFrom6BitValue((temp & greenMask) >> rightShiftGreenMask);
+ int b = (blueMaskBits == 5) ? GetBytesFrom5BitValue((temp & blueMask) >> rightShiftBlueMask) : GetBytesFrom6BitValue((temp & blueMask) >> rightShiftBlueMask);
+ var rgb = new Rgb24((byte)r, (byte)g, (byte)b);
- color.FromRgb24(rgb);
- pixelRow[x] = color;
- offset += 2;
- }
+ color.FromRgb24(rgb);
+ pixelRow[x] = color;
+ offset += 2;
}
}
}
@@ -928,20 +926,19 @@ namespace SixLabors.ImageSharp.Formats.Bmp
where TPixel : unmanaged, IPixel
{
int padding = CalculatePadding(width, 3);
+ using IMemoryOwner row = this.memoryAllocator.AllocatePaddedPixelRowBuffer(width, 3, padding);
+ Span rowSpan = row.GetSpan();
- using (IManagedByteBuffer row = this.memoryAllocator.AllocatePaddedPixelRowBuffer(width, 3, padding))
+ for (int y = 0; y < height; y++)
{
- for (int y = 0; y < height; y++)
- {
- this.stream.Read(row);
- int newY = Invert(y, height, inverted);
- Span pixelSpan = pixels.GetRowSpan(newY);
- PixelOperations.Instance.FromBgr24Bytes(
- this.Configuration,
- row.GetSpan(),
- pixelSpan,
- width);
- }
+ this.stream.Read(rowSpan);
+ int newY = Invert(y, height, inverted);
+ Span pixelSpan = pixels.GetRowSpan(newY);
+ PixelOperations.Instance.FromBgr24Bytes(
+ this.Configuration,
+ rowSpan,
+ pixelSpan,
+ width);
}
}
@@ -957,20 +954,19 @@ namespace SixLabors.ImageSharp.Formats.Bmp
where TPixel : unmanaged, IPixel
{
int padding = CalculatePadding(width, 4);
+ using IMemoryOwner row = this.memoryAllocator.AllocatePaddedPixelRowBuffer(width, 4, padding);
+ Span rowSpan = row.GetSpan();
- using (IManagedByteBuffer row = this.memoryAllocator.AllocatePaddedPixelRowBuffer(width, 4, padding))
+ for (int y = 0; y < height; y++)
{
- for (int y = 0; y < height; y++)
- {
- this.stream.Read(row);
- int newY = Invert(y, height, inverted);
- Span pixelSpan = pixels.GetRowSpan(newY);
- PixelOperations.Instance.FromBgra32Bytes(
- this.Configuration,
- row.GetSpan(),
- pixelSpan,
- width);
- }
+ this.stream.Read(rowSpan);
+ int newY = Invert(y, height, inverted);
+ Span pixelSpan = pixels.GetRowSpan(newY);
+ PixelOperations.Instance.FromBgra32Bytes(
+ this.Configuration,
+ rowSpan,
+ pixelSpan,
+ width);
}
}
@@ -987,87 +983,85 @@ namespace SixLabors.ImageSharp.Formats.Bmp
where TPixel : unmanaged, IPixel
{
int padding = CalculatePadding(width, 4);
-
- using (IManagedByteBuffer row = this.memoryAllocator.AllocatePaddedPixelRowBuffer(width, 4, padding))
- using (IMemoryOwner bgraRow = this.memoryAllocator.Allocate(width))
+ using IMemoryOwner row = this.memoryAllocator.AllocatePaddedPixelRowBuffer(width, 4, padding);
+ using IMemoryOwner bgraRow = this.memoryAllocator.Allocate(width);
+ Span rowSpan = row.GetSpan();
+ Span bgraRowSpan = bgraRow.GetSpan();
+ long currentPosition = this.stream.Position;
+ bool hasAlpha = false;
+
+ // Loop though the rows checking each pixel. We start by assuming it's
+ // an BGR0 image. If we hit a non-zero alpha value, then we know it's
+ // actually a BGRA image, and change tactics accordingly.
+ for (int y = 0; y < height; y++)
{
- Span bgraRowSpan = bgraRow.GetSpan();
- long currentPosition = this.stream.Position;
- bool hasAlpha = false;
+ this.stream.Read(rowSpan);
- // Loop though the rows checking each pixel. We start by assuming it's
- // an BGR0 image. If we hit a non-zero alpha value, then we know it's
- // actually a BGRA image, and change tactics accordingly.
- for (int y = 0; y < height; y++)
- {
- this.stream.Read(row);
-
- PixelOperations.Instance.FromBgra32Bytes(
- this.Configuration,
- row.GetSpan(),
- bgraRowSpan,
- width);
-
- // Check each pixel in the row to see if it has an alpha value.
- for (int x = 0; x < width; x++)
- {
- Bgra32 bgra = bgraRowSpan[x];
- if (bgra.A > 0)
- {
- hasAlpha = true;
- break;
- }
- }
+ PixelOperations.Instance.FromBgra32Bytes(
+ this.Configuration,
+ rowSpan,
+ bgraRowSpan,
+ width);
- if (hasAlpha)
+ // Check each pixel in the row to see if it has an alpha value.
+ for (int x = 0; x < width; x++)
+ {
+ Bgra32 bgra = bgraRowSpan[x];
+ if (bgra.A > 0)
{
+ hasAlpha = true;
break;
}
}
- // Reset our stream for a second pass.
- this.stream.Position = currentPosition;
-
- // Process the pixels in bulk taking the raw alpha component value.
if (hasAlpha)
{
- for (int y = 0; y < height; y++)
- {
- this.stream.Read(row);
-
- int newY = Invert(y, height, inverted);
- Span pixelSpan = pixels.GetRowSpan(newY);
-
- PixelOperations.Instance.FromBgra32Bytes(
- this.Configuration,
- row.GetSpan(),
- pixelSpan,
- width);
- }
-
- return;
+ break;
}
+ }
- // Slow path. We need to set each alpha component value to fully opaque.
+ // Reset our stream for a second pass.
+ this.stream.Position = currentPosition;
+
+ // Process the pixels in bulk taking the raw alpha component value.
+ if (hasAlpha)
+ {
for (int y = 0; y < height; y++)
{
- this.stream.Read(row);
- PixelOperations.Instance.FromBgra32Bytes(
- this.Configuration,
- row.GetSpan(),
- bgraRowSpan,
- width);
+ this.stream.Read(rowSpan);
int newY = Invert(y, height, inverted);
Span pixelSpan = pixels.GetRowSpan(newY);
- for (int x = 0; x < width; x++)
- {
- Bgra32 bgra = bgraRowSpan[x];
- bgra.A = byte.MaxValue;
- ref TPixel pixel = ref pixelSpan[x];
- pixel.FromBgra32(bgra);
- }
+ PixelOperations.Instance.FromBgra32Bytes(
+ this.Configuration,
+ rowSpan,
+ pixelSpan,
+ width);
+ }
+
+ return;
+ }
+
+ // Slow path. We need to set each alpha component value to fully opaque.
+ for (int y = 0; y < height; y++)
+ {
+ this.stream.Read(rowSpan);
+ PixelOperations.Instance.FromBgra32Bytes(
+ this.Configuration,
+ rowSpan,
+ bgraRowSpan,
+ width);
+
+ int newY = Invert(y, height, inverted);
+ Span pixelSpan = pixels.GetRowSpan(newY);
+
+ for (int x = 0; x < width; x++)
+ {
+ Bgra32 bgra = bgraRowSpan[x];
+ bgra.A = byte.MaxValue;
+ ref TPixel pixel = ref pixelSpan[x];
+ pixel.FromBgra32(bgra);
}
}
}
@@ -1108,44 +1102,44 @@ namespace SixLabors.ImageSharp.Formats.Bmp
bool unusualBitMask = bitsRedMask > 8 || bitsGreenMask > 8 || bitsBlueMask > 8 || invMaxValueAlpha > 8;
- using (IManagedByteBuffer buffer = this.memoryAllocator.AllocateManagedByteBuffer(stride))
+ using IMemoryOwner buffer = this.memoryAllocator.Allocate(stride);
+ Span bufferSpan = buffer.GetSpan();
+
+ for (int y = 0; y < height; y++)
{
- for (int y = 0; y < height; y++)
+ this.stream.Read(bufferSpan);
+ int newY = Invert(y, height, inverted);
+ Span pixelRow = pixels.GetRowSpan(newY);
+
+ int offset = 0;
+ for (int x = 0; x < width; x++)
{
- this.stream.Read(buffer.Array, 0, stride);
- int newY = Invert(y, height, inverted);
- Span pixelRow = pixels.GetRowSpan(newY);
+ uint temp = BinaryPrimitives.ReadUInt32LittleEndian(bufferSpan.Slice(offset));
- int offset = 0;
- for (int x = 0; x < width; x++)
+ if (unusualBitMask)
{
- uint temp = BitConverter.ToUInt32(buffer.Array, offset);
-
- if (unusualBitMask)
- {
- uint r = (uint)(temp & redMask) >> rightShiftRedMask;
- uint g = (uint)(temp & greenMask) >> rightShiftGreenMask;
- uint b = (uint)(temp & blueMask) >> rightShiftBlueMask;
- float alpha = alphaMask != 0 ? invMaxValueAlpha * ((uint)(temp & alphaMask) >> rightShiftAlphaMask) : 1.0f;
- var vector4 = new Vector4(
- r * invMaxValueRed,
- g * invMaxValueGreen,
- b * invMaxValueBlue,
- alpha);
- color.FromVector4(vector4);
- }
- else
- {
- byte r = (byte)((temp & redMask) >> rightShiftRedMask);
- byte g = (byte)((temp & greenMask) >> rightShiftGreenMask);
- byte b = (byte)((temp & blueMask) >> rightShiftBlueMask);
- byte a = alphaMask != 0 ? (byte)((temp & alphaMask) >> rightShiftAlphaMask) : (byte)255;
- color.FromRgba32(new Rgba32(r, g, b, a));
- }
-
- pixelRow[x] = color;
- offset += 4;
+ uint r = (uint)(temp & redMask) >> rightShiftRedMask;
+ uint g = (uint)(temp & greenMask) >> rightShiftGreenMask;
+ uint b = (uint)(temp & blueMask) >> rightShiftBlueMask;
+ float alpha = alphaMask != 0 ? invMaxValueAlpha * ((uint)(temp & alphaMask) >> rightShiftAlphaMask) : 1.0f;
+ var vector4 = new Vector4(
+ r * invMaxValueRed,
+ g * invMaxValueGreen,
+ b * invMaxValueBlue,
+ alpha);
+ color.FromVector4(vector4);
}
+ else
+ {
+ byte r = (byte)((temp & redMask) >> rightShiftRedMask);
+ byte g = (byte)((temp & greenMask) >> rightShiftGreenMask);
+ byte b = (byte)((temp & blueMask) >> rightShiftBlueMask);
+ byte a = alphaMask != 0 ? (byte)((temp & alphaMask) >> rightShiftAlphaMask) : (byte)255;
+ color.FromRgba32(new Rgba32(r, g, b, a));
+ }
+
+ pixelRow[x] = color;
+ offset += 4;
}
}
}
@@ -1303,15 +1297,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
short bitsPerPixel = this.infoHeader.BitsPerPixel;
this.bmpMetadata = this.metadata.GetBmpMetadata();
this.bmpMetadata.InfoHeaderType = infoHeaderType;
-
- // We can only encode at these bit rates so far (1 bit and 4 bit are still missing).
- if (bitsPerPixel.Equals((short)BmpBitsPerPixel.Pixel8)
- || bitsPerPixel.Equals((short)BmpBitsPerPixel.Pixel16)
- || bitsPerPixel.Equals((short)BmpBitsPerPixel.Pixel24)
- || bitsPerPixel.Equals((short)BmpBitsPerPixel.Pixel32))
- {
- this.bmpMetadata.BitsPerPixel = (BmpBitsPerPixel)bitsPerPixel;
- }
+ this.bmpMetadata.BitsPerPixel = (BmpBitsPerPixel)bitsPerPixel;
}
///
diff --git a/src/ImageSharp/Formats/Bmp/BmpEncoder.cs b/src/ImageSharp/Formats/Bmp/BmpEncoder.cs
index 2f5c4b7cf..f256ed9f8 100644
--- a/src/ImageSharp/Formats/Bmp/BmpEncoder.cs
+++ b/src/ImageSharp/Formats/Bmp/BmpEncoder.cs
@@ -30,7 +30,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
///
/// Gets or sets the quantizer for reducing the color count for 8-Bit images.
- /// Defaults to OctreeQuantizer.
+ /// Defaults to Wu Quantizer.
///
public IQuantizer Quantizer { get; set; }
diff --git a/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs
index 7819b1ebd..c6ca5b09d 100644
--- a/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs
+++ b/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs
@@ -51,6 +51,16 @@ namespace SixLabors.ImageSharp.Formats.Bmp
///
private const int ColorPaletteSize8Bit = 1024;
+ ///
+ /// The color palette for an 4 bit image will have 16 entry's with 4 bytes for each entry.
+ ///
+ private const int ColorPaletteSize4Bit = 64;
+
+ ///
+ /// The color palette for an 1 bit image will have 2 entry's with 4 bytes for each entry.
+ ///
+ private const int ColorPaletteSize1Bit = 8;
+
///
/// Used for allocating memory during processing operations.
///
@@ -74,7 +84,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
private readonly bool writeV4Header;
///
- /// The quantizer for reducing the color count for 8-Bit images.
+ /// The quantizer for reducing the color count for 8-Bit, 4-Bit and 1-Bit images.
///
private readonly IQuantizer quantizer;
@@ -107,7 +117,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
this.configuration = image.GetConfiguration();
ImageMetadata metadata = image.Metadata;
BmpMetadata bmpMetadata = metadata.GetBmpMetadata();
- this.bitsPerPixel = this.bitsPerPixel ?? bmpMetadata.BitsPerPixel;
+ this.bitsPerPixel ??= bmpMetadata.BitsPerPixel;
short bpp = (short)this.bitsPerPixel;
int bytesPerLine = 4 * (((image.Width * bpp) + 31) / 32);
@@ -166,7 +176,19 @@ namespace SixLabors.ImageSharp.Formats.Bmp
infoHeader.Compression = BmpCompression.BitFields;
}
- int colorPaletteSize = this.bitsPerPixel == BmpBitsPerPixel.Pixel8 ? ColorPaletteSize8Bit : 0;
+ int colorPaletteSize = 0;
+ if (this.bitsPerPixel == BmpBitsPerPixel.Pixel8)
+ {
+ colorPaletteSize = ColorPaletteSize8Bit;
+ }
+ else if (this.bitsPerPixel == BmpBitsPerPixel.Pixel4)
+ {
+ colorPaletteSize = ColorPaletteSize4Bit;
+ }
+ else if (this.bitsPerPixel == BmpBitsPerPixel.Pixel1)
+ {
+ colorPaletteSize = ColorPaletteSize1Bit;
+ }
var fileHeader = new BmpFileHeader(
type: BmpConstants.TypeMarkers.Bitmap,
@@ -224,10 +246,19 @@ namespace SixLabors.ImageSharp.Formats.Bmp
case BmpBitsPerPixel.Pixel8:
this.Write8Bit(stream, image);
break;
+
+ case BmpBitsPerPixel.Pixel4:
+ this.Write4BitColor(stream, image);
+ break;
+
+ case BmpBitsPerPixel.Pixel1:
+ this.Write1BitColor(stream, image);
+ break;
}
}
- private IManagedByteBuffer AllocateRow(int width, int bytesPerPixel) => this.memoryAllocator.AllocatePaddedPixelRowBuffer(width, bytesPerPixel, this.padding);
+ private IMemoryOwner AllocateRow(int width, int bytesPerPixel)
+ => this.memoryAllocator.AllocatePaddedPixelRowBuffer(width, bytesPerPixel, this.padding);
///
/// Writes the 32bit color palette to the stream.
@@ -238,18 +269,18 @@ namespace SixLabors.ImageSharp.Formats.Bmp
private void Write32Bit(Stream stream, Buffer2D pixels)
where TPixel : unmanaged, IPixel
{
- using (IManagedByteBuffer row = this.AllocateRow(pixels.Width, 4))
+ using IMemoryOwner row = this.AllocateRow(pixels.Width, 4);
+ Span rowSpan = row.GetSpan();
+
+ for (int y = pixels.Height - 1; y >= 0; y--)
{
- for (int y = pixels.Height - 1; y >= 0; y--)
- {
- Span pixelSpan = pixels.GetRowSpan(y);
- PixelOperations.Instance.ToBgra32Bytes(
- this.configuration,
- pixelSpan,
- row.GetSpan(),
- pixelSpan.Length);
- stream.Write(row.Array, 0, row.Length());
- }
+ Span pixelSpan = pixels.GetRowSpan(y);
+ PixelOperations.Instance.ToBgra32Bytes(
+ this.configuration,
+ pixelSpan,
+ rowSpan,
+ pixelSpan.Length);
+ stream.Write(rowSpan);
}
}
@@ -264,18 +295,18 @@ namespace SixLabors.ImageSharp.Formats.Bmp
{
int width = pixels.Width;
int rowBytesWithoutPadding = width * 3;
- using (IManagedByteBuffer row = this.AllocateRow(width, 3))
+ using IMemoryOwner row = this.AllocateRow(width, 3);
+ Span rowSpan = row.GetSpan();
+
+ for (int y = pixels.Height - 1; y >= 0; y--)
{
- for (int y = pixels.Height - 1; y >= 0; y--)
- {
- Span pixelSpan = pixels.GetRowSpan(y);
- PixelOperations.Instance.ToBgr24Bytes(
- this.configuration,
- pixelSpan,
- row.Slice(0, rowBytesWithoutPadding),
- width);
- stream.Write(row.Array, 0, row.Length());
- }
+ Span pixelSpan = pixels.GetRowSpan(y);
+ PixelOperations.Instance.ToBgr24Bytes(
+ this.configuration,
+ pixelSpan,
+ row.Slice(0, rowBytesWithoutPadding),
+ width);
+ stream.Write(rowSpan);
}
}
@@ -290,25 +321,25 @@ namespace SixLabors.ImageSharp.Formats.Bmp
{
int width = pixels.Width;
int rowBytesWithoutPadding = width * 2;
- using (IManagedByteBuffer row = this.AllocateRow(width, 2))
+ using IMemoryOwner row = this.AllocateRow(width, 2);
+ Span rowSpan = row.GetSpan();
+
+ for (int y = pixels.Height - 1; y >= 0; y--)
{
- for (int y = pixels.Height - 1; y >= 0; y--)
- {
- Span pixelSpan = pixels.GetRowSpan(y);
+ Span pixelSpan = pixels.GetRowSpan(y);
- PixelOperations.Instance.ToBgra5551Bytes(
- this.configuration,
- pixelSpan,
- row.Slice(0, rowBytesWithoutPadding),
- pixelSpan.Length);
+ PixelOperations.Instance.ToBgra5551Bytes(
+ this.configuration,
+ pixelSpan,
+ row.Slice(0, rowBytesWithoutPadding),
+ pixelSpan.Length);
- stream.Write(row.Array, 0, row.Length());
- }
+ stream.Write(rowSpan);
}
}
///
- /// Writes an 8 Bit image with a color palette. The color palette has 256 entry's with 4 bytes for each entry.
+ /// Writes an 8 bit image with a color palette. The color palette has 256 entry's with 4 bytes for each entry.
///
/// The type of the pixel.
/// The to write to.
@@ -317,22 +348,21 @@ namespace SixLabors.ImageSharp.Formats.Bmp
where TPixel : unmanaged, IPixel
{
bool isL8 = typeof(TPixel) == typeof(L8);
- using (IMemoryOwner colorPaletteBuffer = this.memoryAllocator.AllocateManagedByteBuffer(ColorPaletteSize8Bit, AllocationOptions.Clean))
+ using IMemoryOwner colorPaletteBuffer = this.memoryAllocator.Allocate(ColorPaletteSize8Bit, AllocationOptions.Clean);
+ Span colorPalette = colorPaletteBuffer.GetSpan();
+
+ if (isL8)
{
- Span colorPalette = colorPaletteBuffer.GetSpan();
- if (isL8)
- {
- this.Write8BitGray(stream, image, colorPalette);
- }
- else
- {
- this.Write8BitColor(stream, image, colorPalette);
- }
+ this.Write8BitGray(stream, image, colorPalette);
+ }
+ else
+ {
+ this.Write8BitColor(stream, image, colorPalette);
}
}
///
- /// Writes an 8 Bit color image with a color palette. The color palette has 256 entry's with 4 bytes for each entry.
+ /// Writes an 8 bit color image with a color palette. The color palette has 256 entry's with 4 bytes for each entry.
///
/// The type of the pixel.
/// The to write to.
@@ -344,16 +374,8 @@ namespace SixLabors.ImageSharp.Formats.Bmp
using IQuantizer frameQuantizer = this.quantizer.CreatePixelSpecificQuantizer(this.configuration);
using IndexedImageFrame quantized = frameQuantizer.BuildPaletteAndQuantizeFrame(image, image.Bounds());
- ReadOnlySpan quantizedColors = quantized.Palette.Span;
- var quantizedColorBytes = quantizedColors.Length * 4;
- PixelOperations.Instance.ToBgra32(this.configuration, quantizedColors, MemoryMarshal.Cast(colorPalette.Slice(0, quantizedColorBytes)));
- Span colorPaletteAsUInt = MemoryMarshal.Cast(colorPalette);
- for (int i = 0; i < colorPaletteAsUInt.Length; i++)
- {
- colorPaletteAsUInt[i] = colorPaletteAsUInt[i] & 0x00FFFFFF; // Padding byte, always 0.
- }
-
- stream.Write(colorPalette);
+ ReadOnlySpan quantizedColorPalette = quantized.Palette.Span;
+ this.WriteColorPalette(stream, quantizedColorPalette, colorPalette);
for (int y = image.Height - 1; y >= 0; y--)
{
@@ -368,7 +390,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
}
///
- /// Writes an 8 Bit gray image with a color palette. The color palette has 256 entry's with 4 bytes for each entry.
+ /// Writes an 8 bit gray image with a color palette. The color palette has 256 entry's with 4 bytes for each entry.
///
/// The type of the pixel.
/// The to write to.
@@ -404,5 +426,136 @@ namespace SixLabors.ImageSharp.Formats.Bmp
}
}
}
+
+ ///
+ /// Writes an 4 bit color image with a color palette. The color palette has 16 entry's with 4 bytes for each entry.
+ ///
+ /// The type of the pixel.
+ /// The to write to.
+ /// The containing pixel data.
+ private void Write4BitColor(Stream stream, ImageFrame image)
+ where TPixel : unmanaged, IPixel
+ {
+ using IQuantizer frameQuantizer = this.quantizer.CreatePixelSpecificQuantizer(this.configuration, new QuantizerOptions()
+ {
+ MaxColors = 16
+ });
+ using IndexedImageFrame quantized = frameQuantizer.BuildPaletteAndQuantizeFrame(image, image.Bounds());
+ using IMemoryOwner colorPaletteBuffer = this.memoryAllocator.Allocate(ColorPaletteSize4Bit, AllocationOptions.Clean);
+
+ Span colorPalette = colorPaletteBuffer.GetSpan();
+ ReadOnlySpan quantizedColorPalette = quantized.Palette.Span;
+ this.WriteColorPalette(stream, quantizedColorPalette, colorPalette);
+
+ ReadOnlySpan pixelRowSpan = quantized.GetPixelRowSpan(0);
+ int rowPadding = pixelRowSpan.Length % 2 != 0 ? this.padding - 1 : this.padding;
+ for (int y = image.Height - 1; y >= 0; y--)
+ {
+ pixelRowSpan = quantized.GetPixelRowSpan(y);
+
+ int endIdx = pixelRowSpan.Length % 2 == 0 ? pixelRowSpan.Length : pixelRowSpan.Length - 1;
+ for (int i = 0; i < endIdx; i += 2)
+ {
+ stream.WriteByte((byte)((pixelRowSpan[i] << 4) | pixelRowSpan[i + 1]));
+ }
+
+ if (pixelRowSpan.Length % 2 != 0)
+ {
+ stream.WriteByte((byte)((pixelRowSpan[pixelRowSpan.Length - 1] << 4) | 0));
+ }
+
+ for (int i = 0; i < rowPadding; i++)
+ {
+ stream.WriteByte(0);
+ }
+ }
+ }
+
+ ///
+ /// Writes a 1 bit image with a color palette. The color palette has 2 entry's with 4 bytes for each entry.
+ ///
+ /// The type of the pixel.
+ /// The to write to.
+ /// The containing pixel data.
+ private void Write1BitColor(Stream stream, ImageFrame image)
+ where TPixel : unmanaged, IPixel
+ {
+ using IQuantizer frameQuantizer = this.quantizer.CreatePixelSpecificQuantizer(this.configuration, new QuantizerOptions()
+ {
+ MaxColors = 2
+ });
+ using IndexedImageFrame quantized = frameQuantizer.BuildPaletteAndQuantizeFrame(image, image.Bounds());
+ using IMemoryOwner colorPaletteBuffer = this.memoryAllocator.Allocate(ColorPaletteSize1Bit, AllocationOptions.Clean);
+
+ Span colorPalette = colorPaletteBuffer.GetSpan();
+ ReadOnlySpan quantizedColorPalette = quantized.Palette.Span;
+ this.WriteColorPalette(stream, quantizedColorPalette, colorPalette);
+
+ ReadOnlySpan quantizedPixelRow = quantized.GetPixelRowSpan(0);
+ int rowPadding = quantizedPixelRow.Length % 8 != 0 ? this.padding - 1 : this.padding;
+ for (int y = image.Height - 1; y >= 0; y--)
+ {
+ quantizedPixelRow = quantized.GetPixelRowSpan(y);
+
+ int endIdx = quantizedPixelRow.Length % 8 == 0 ? quantizedPixelRow.Length : quantizedPixelRow.Length - 8;
+ for (int i = 0; i < endIdx; i += 8)
+ {
+ Write1BitPalette(stream, i, i + 8, quantizedPixelRow);
+ }
+
+ if (quantizedPixelRow.Length % 8 != 0)
+ {
+ int startIdx = quantizedPixelRow.Length - 7;
+ endIdx = quantizedPixelRow.Length;
+ Write1BitPalette(stream, startIdx, endIdx, quantizedPixelRow);
+ }
+
+ for (int i = 0; i < rowPadding; i++)
+ {
+ stream.WriteByte(0);
+ }
+ }
+ }
+
+ ///
+ /// Writes the color palette to the stream. The color palette has 4 bytes for each entry.
+ ///
+ /// The type of the pixel.
+ /// The to write to.
+ /// The color palette from the quantized image.
+ /// A temporary byte span to write the color palette to.
+ private void WriteColorPalette(Stream stream, ReadOnlySpan quantizedColorPalette, Span colorPalette)
+ where TPixel : unmanaged, IPixel
+ {
+ int quantizedColorBytes = quantizedColorPalette.Length * 4;
+ PixelOperations.Instance.ToBgra32(this.configuration, quantizedColorPalette, MemoryMarshal.Cast(colorPalette.Slice(0, quantizedColorBytes)));
+ Span colorPaletteAsUInt = MemoryMarshal.Cast(colorPalette);
+ for (int i = 0; i < colorPaletteAsUInt.Length; i++)
+ {
+ colorPaletteAsUInt[i] = colorPaletteAsUInt[i] & 0x00FFFFFF; // Padding byte, always 0.
+ }
+
+ stream.Write(colorPalette);
+ }
+
+ ///
+ /// Writes a 1-bit palette.
+ ///
+ /// The stream to write the palette to.
+ /// The start index.
+ /// The end index.
+ /// A quantized pixel row.
+ private static void Write1BitPalette(Stream stream, int startIdx, int endIdx, ReadOnlySpan quantizedPixelRow)
+ {
+ int shift = 7;
+ byte indices = 0;
+ for (int j = startIdx; j < endIdx; j++)
+ {
+ indices = (byte)(indices | ((byte)(quantizedPixelRow[j] & 1) << shift));
+ shift--;
+ }
+
+ stream.WriteByte(indices);
+ }
}
}
diff --git a/src/ImageSharp/Formats/Bmp/BmpFormat.cs b/src/ImageSharp/Formats/Bmp/BmpFormat.cs
index 9e367c6da..d92a73104 100644
--- a/src/ImageSharp/Formats/Bmp/BmpFormat.cs
+++ b/src/ImageSharp/Formats/Bmp/BmpFormat.cs
@@ -34,4 +34,4 @@ namespace SixLabors.ImageSharp.Formats.Bmp
///
public BmpMetadata CreateDefaultFormatMetadata() => new BmpMetadata();
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Formats/Bmp/BmpMetadata.cs b/src/ImageSharp/Formats/Bmp/BmpMetadata.cs
index 50cf32fcb..b7b668a7a 100644
--- a/src/ImageSharp/Formats/Bmp/BmpMetadata.cs
+++ b/src/ImageSharp/Formats/Bmp/BmpMetadata.cs
@@ -40,4 +40,4 @@ namespace SixLabors.ImageSharp.Formats.Bmp
// TODO: Colors used once we support encoding palette bmps.
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Formats/Bmp/IBmpDecoderOptions.cs b/src/ImageSharp/Formats/Bmp/IBmpDecoderOptions.cs
index d359e9f1d..ff88d15a3 100644
--- a/src/ImageSharp/Formats/Bmp/IBmpDecoderOptions.cs
+++ b/src/ImageSharp/Formats/Bmp/IBmpDecoderOptions.cs
@@ -13,4 +13,4 @@ namespace SixLabors.ImageSharp.Formats.Bmp
///
RleSkippedPixelHandling RleSkippedPixelHandling { get; }
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Formats/Bmp/IBmpEncoderOptions.cs b/src/ImageSharp/Formats/Bmp/IBmpEncoderOptions.cs
index d4a22d66e..30aa70452 100644
--- a/src/ImageSharp/Formats/Bmp/IBmpEncoderOptions.cs
+++ b/src/ImageSharp/Formats/Bmp/IBmpEncoderOptions.cs
@@ -1,4 +1,4 @@
-// Copyright (c) Six Labors.
+// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.Processing.Processors.Quantization;
@@ -24,8 +24,8 @@ namespace SixLabors.ImageSharp.Formats.Bmp
bool SupportTransparency { get; }
///
- /// Gets the quantizer for reducing the color count for 8-Bit images.
+ /// Gets the quantizer for reducing the color count for 8-Bit, 4-Bit, and 1-Bit images.
///
IQuantizer Quantizer { get; }
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Formats/Gif/GifConfigurationModule.cs b/src/ImageSharp/Formats/Gif/GifConfigurationModule.cs
index b08a3c38e..8f846f9d5 100644
--- a/src/ImageSharp/Formats/Gif/GifConfigurationModule.cs
+++ b/src/ImageSharp/Formats/Gif/GifConfigurationModule.cs
@@ -16,4 +16,4 @@ namespace SixLabors.ImageSharp.Formats.Gif
configuration.ImageFormatsManager.AddImageFormatDetector(new GifImageFormatDetector());
}
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs
index 2f6b45aff..482a76153 100644
--- a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs
+++ b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs
@@ -2,12 +2,12 @@
// Licensed under the Apache License, Version 2.0.
using System;
+using System.Buffers;
using System.IO;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
-using System.Threading.Tasks;
using SixLabors.ImageSharp.IO;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Metadata;
@@ -33,7 +33,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
///
/// The global color table.
///
- private IManagedByteBuffer globalColorTable;
+ private IMemoryOwner globalColorTable;
///
/// The area to restore.
@@ -323,12 +323,12 @@ namespace SixLabors.ImageSharp.Formats.Gif
continue;
}
- using (IManagedByteBuffer commentsBuffer = this.MemoryAllocator.AllocateManagedByteBuffer(length))
- {
- this.stream.Read(commentsBuffer.Array, 0, length);
- string commentPart = GifConstants.Encoding.GetString(commentsBuffer.Array, 0, length);
- stringBuilder.Append(commentPart);
- }
+ using IMemoryOwner commentsBuffer = this.MemoryAllocator.Allocate(length);
+ Span commentsSpan = commentsBuffer.GetSpan();
+
+ this.stream.Read(commentsSpan);
+ string commentPart = GifConstants.Encoding.GetString(commentsSpan);
+ stringBuilder.Append(commentPart);
}
if (stringBuilder.Length > 0)
@@ -348,7 +348,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
{
this.ReadImageDescriptor();
- IManagedByteBuffer localColorTable = null;
+ IMemoryOwner localColorTable = null;
Buffer2D indices = null;
try
{
@@ -356,8 +356,8 @@ namespace SixLabors.ImageSharp.Formats.Gif
if (this.imageDescriptor.LocalColorTableFlag)
{
int length = this.imageDescriptor.LocalColorTableSize * 3;
- localColorTable = this.Configuration.MemoryAllocator.AllocateManagedByteBuffer(length, AllocationOptions.Clean);
- this.stream.Read(localColorTable.Array, 0, length);
+ localColorTable = this.Configuration.MemoryAllocator.Allocate(length, AllocationOptions.Clean);
+ this.stream.Read(localColorTable.GetSpan());
}
indices = this.Configuration.MemoryAllocator.Allocate2D(this.imageDescriptor.Width, this.imageDescriptor.Height, AllocationOptions.Clean);
@@ -441,6 +441,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
int descriptorRight = descriptorLeft + descriptor.Width;
bool transFlag = this.graphicsControlExtension.TransparencyFlag;
byte transIndex = this.graphicsControlExtension.TransparencyIndex;
+ int colorTableMaxIdx = colorTable.Length - 1;
for (int y = descriptorTop; y < descriptorBottom && y < imageHeight; y++)
{
@@ -487,7 +488,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
// #403 The left + width value can be larger than the image width
for (int x = descriptorLeft; x < descriptorRight && x < imageWidth; x++)
{
- int index = Unsafe.Add(ref indicesRowRef, x - descriptorLeft);
+ int index = Numerics.Clamp(Unsafe.Add(ref indicesRowRef, x - descriptorLeft), 0, colorTableMaxIdx);
ref TPixel pixel = ref Unsafe.Add(ref rowRef, x);
Rgb24 rgb = colorTable[index];
pixel.FromRgb24(rgb);
@@ -497,7 +498,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
{
for (int x = descriptorLeft; x < descriptorRight && x < imageWidth; x++)
{
- int index = Unsafe.Add(ref indicesRowRef, x - descriptorLeft);
+ int index = Numerics.Clamp(Unsafe.Add(ref indicesRowRef, x - descriptorLeft), 0, colorTableMaxIdx);
if (transIndex != index)
{
ref TPixel pixel = ref Unsafe.Add(ref rowRef, x);
@@ -621,10 +622,10 @@ namespace SixLabors.ImageSharp.Formats.Gif
int globalColorTableLength = this.logicalScreenDescriptor.GlobalColorTableSize * 3;
this.gifMetadata.GlobalColorTableLength = globalColorTableLength;
- this.globalColorTable = this.MemoryAllocator.AllocateManagedByteBuffer(globalColorTableLength, AllocationOptions.Clean);
+ this.globalColorTable = this.MemoryAllocator.Allocate(globalColorTableLength, AllocationOptions.Clean);
// Read the global color table data from the stream
- stream.Read(this.globalColorTable.Array, 0, globalColorTableLength);
+ stream.Read(this.globalColorTable.GetSpan());
}
}
}
diff --git a/src/ImageSharp/Formats/Gif/GifDisposalMethod.cs b/src/ImageSharp/Formats/Gif/GifDisposalMethod.cs
index b57491cf9..2211dfe4b 100644
--- a/src/ImageSharp/Formats/Gif/GifDisposalMethod.cs
+++ b/src/ImageSharp/Formats/Gif/GifDisposalMethod.cs
@@ -35,4 +35,4 @@ namespace SixLabors.ImageSharp.Formats.Gif
///
RestoreToPrevious = 3
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs
index 9c1e95285..05ea14e9c 100644
--- a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs
+++ b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs
@@ -7,7 +7,6 @@ using System.IO;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading;
-using System.Threading.Tasks;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Metadata;
@@ -54,7 +53,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
///
/// The pixel sampling strategy for global quantization.
///
- private IPixelSamplingStrategy pixelSamplingStrategy;
+ private readonly IPixelSamplingStrategy pixelSamplingStrategy;
///
/// Initializes a new instance of the class.
@@ -150,8 +149,8 @@ namespace SixLabors.ImageSharp.Formats.Gif
// The palette quantizer can reuse the same pixel map across multiple frames
// since the palette is unchanging. This allows a reduction of memory usage across
// multi frame gifs using a global palette.
- EuclideanPixelMap pixelMap = default;
- bool pixelMapSet = false;
+ PaletteQuantizer paletteFrameQuantizer = default;
+ bool quantizerInitialized = false;
for (int i = 0; i < image.Frames.Count; i++)
{
ImageFrame frame = image.Frames[i];
@@ -166,17 +165,18 @@ namespace SixLabors.ImageSharp.Formats.Gif
}
else
{
- if (!pixelMapSet)
+ if (!quantizerInitialized)
{
- pixelMapSet = true;
- pixelMap = new EuclideanPixelMap(this.configuration, quantized.Palette);
+ quantizerInitialized = true;
+ paletteFrameQuantizer = new PaletteQuantizer(this.configuration, this.quantizer.Options, quantized.Palette);
}
- using var paletteFrameQuantizer = new PaletteQuantizer(this.configuration, this.quantizer.Options, pixelMap);
using IndexedImageFrame paletteQuantized = paletteFrameQuantizer.QuantizeFrame(frame, frame.Bounds());
this.WriteImageData(paletteQuantized, stream);
}
}
+
+ paletteFrameQuantizer.Dispose();
}
private void EncodeLocal(Image image, IndexedImageFrame quantized, Stream stream)
@@ -305,7 +305,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
}
else
{
- ratio = (byte)(((1 / vr) * 64) - 15);
+ ratio = (byte)((1 / vr * 64) - 15);
}
}
}
@@ -349,7 +349,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
return;
}
- for (var i = 0; i < metadata.Comments.Count; i++)
+ for (int i = 0; i < metadata.Comments.Count; i++)
{
string comment = metadata.Comments[i];
this.buffer[0] = GifConstants.ExtensionIntroducer;
@@ -470,14 +470,16 @@ namespace SixLabors.ImageSharp.Formats.Gif
// The maximum number of colors for the bit depth
int colorTableLength = ColorNumerics.GetColorCountForBitDepth(this.bitDepth) * Unsafe.SizeOf();
- using IManagedByteBuffer colorTable = this.memoryAllocator.AllocateManagedByteBuffer(colorTableLength, AllocationOptions.Clean);
+ using IMemoryOwner colorTable = this.memoryAllocator.Allocate(colorTableLength, AllocationOptions.Clean);
+ Span colorTableSpan = colorTable.GetSpan();
+
PixelOperations.Instance.ToRgb24Bytes(
this.configuration,
image.Palette.Span,
- colorTable.GetSpan(),
+ colorTableSpan,
image.Palette.Length);
- stream.Write(colorTable.Array, 0, colorTableLength);
+ stream.Write(colorTableSpan);
}
///
diff --git a/src/ImageSharp/Formats/Gif/GifFormat.cs b/src/ImageSharp/Formats/Gif/GifFormat.cs
index 4ff53a409..459f0068b 100644
--- a/src/ImageSharp/Formats/Gif/GifFormat.cs
+++ b/src/ImageSharp/Formats/Gif/GifFormat.cs
@@ -37,4 +37,4 @@ namespace SixLabors.ImageSharp.Formats.Gif
///
public GifFrameMetadata CreateDefaultFormatFrameMetadata() => new GifFrameMetadata();
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Formats/Gif/GifImageFormatDetector.cs b/src/ImageSharp/Formats/Gif/GifImageFormatDetector.cs
index 3b3dd0bf1..736b9246d 100644
--- a/src/ImageSharp/Formats/Gif/GifImageFormatDetector.cs
+++ b/src/ImageSharp/Formats/Gif/GifImageFormatDetector.cs
@@ -30,4 +30,4 @@ namespace SixLabors.ImageSharp.Formats.Gif
header[5] == 0x61; // a
}
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Formats/Gif/LzwEncoder.cs b/src/ImageSharp/Formats/Gif/LzwEncoder.cs
index 195a84a1d..e9fb7ab00 100644
--- a/src/ImageSharp/Formats/Gif/LzwEncoder.cs
+++ b/src/ImageSharp/Formats/Gif/LzwEncoder.cs
@@ -6,7 +6,6 @@ using System.Buffers;
using System.IO;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
-
using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp.Formats.Gif
diff --git a/src/ImageSharp/Formats/Gif/Sections/GifGraphicControlExtension.cs b/src/ImageSharp/Formats/Gif/Sections/GifGraphicControlExtension.cs
index 77b32f77d..ee5a43d80 100644
--- a/src/ImageSharp/Formats/Gif/Sections/GifGraphicControlExtension.cs
+++ b/src/ImageSharp/Formats/Gif/Sections/GifGraphicControlExtension.cs
@@ -103,4 +103,4 @@ namespace SixLabors.ImageSharp.Formats.Gif
return value;
}
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Formats/Gif/Sections/GifImageDescriptor.cs b/src/ImageSharp/Formats/Gif/Sections/GifImageDescriptor.cs
index 68b048482..1eaebe11d 100644
--- a/src/ImageSharp/Formats/Gif/Sections/GifImageDescriptor.cs
+++ b/src/ImageSharp/Formats/Gif/Sections/GifImageDescriptor.cs
@@ -113,4 +113,4 @@ namespace SixLabors.ImageSharp.Formats.Gif
return value;
}
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Formats/Gif/Sections/GifLogicalScreenDescriptor.cs b/src/ImageSharp/Formats/Gif/Sections/GifLogicalScreenDescriptor.cs
index 88c13d203..e3bc2e883 100644
--- a/src/ImageSharp/Formats/Gif/Sections/GifLogicalScreenDescriptor.cs
+++ b/src/ImageSharp/Formats/Gif/Sections/GifLogicalScreenDescriptor.cs
@@ -130,4 +130,4 @@ namespace SixLabors.ImageSharp.Formats.Gif
return value;
}
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Formats/Gif/Sections/IGifExtension.cs b/src/ImageSharp/Formats/Gif/Sections/IGifExtension.cs
index bec188123..5a15a6dfa 100644
--- a/src/ImageSharp/Formats/Gif/Sections/IGifExtension.cs
+++ b/src/ImageSharp/Formats/Gif/Sections/IGifExtension.cs
@@ -22,4 +22,4 @@ namespace SixLabors.ImageSharp.Formats.Gif
/// The number of bytes written to the buffer.
int WriteTo(Span buffer);
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Formats/IImageFormat.cs b/src/ImageSharp/Formats/IImageFormat.cs
index 06b96caad..812984ba8 100644
--- a/src/ImageSharp/Formats/IImageFormat.cs
+++ b/src/ImageSharp/Formats/IImageFormat.cs
@@ -60,4 +60,4 @@ namespace SixLabors.ImageSharp.Formats
/// The .
TFormatFrameMetadata CreateDefaultFormatFrameMetadata();
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Formats/ImageExtensions.Save.cs b/src/ImageSharp/Formats/ImageExtensions.Save.cs
index 075c708b6..c5237f2bc 100644
--- a/src/ImageSharp/Formats/ImageExtensions.Save.cs
+++ b/src/ImageSharp/Formats/ImageExtensions.Save.cs
@@ -1,4 +1,4 @@
-// Copyright (c) Six Labors.
+// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
//
@@ -12,6 +12,8 @@ using SixLabors.ImageSharp.Formats.Gif;
using SixLabors.ImageSharp.Formats.Jpeg;
using SixLabors.ImageSharp.Formats.Png;
using SixLabors.ImageSharp.Formats.Tga;
+using SixLabors.ImageSharp.Formats.Webp;
+using SixLabors.ImageSharp.Formats.Tiff;
namespace SixLabors.ImageSharp
{
@@ -535,5 +537,211 @@ namespace SixLabors.ImageSharp
encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(TgaFormat.Instance),
cancellationToken);
+ ///
+ /// Saves the image to the given stream with the Webp format.
+ ///
+ /// The image this method extends.
+ /// The file path to save the image to.
+ /// Thrown if the path is null.
+ public static void SaveAsWebp(this Image source, string path) => SaveAsWebp(source, path, null);
+
+ ///
+ /// Saves the image to the given stream with the Webp format.
+ ///
+ /// The image this method extends.
+ /// The file path to save the image to.
+ /// Thrown if the path is null.
+ /// A representing the asynchronous operation.
+ public static Task SaveAsWebpAsync(this Image source, string path) => SaveAsWebpAsync(source, path, null);
+
+ ///
+ /// Saves the image to the given stream with the Webp format.
+ ///
+ /// The image this method extends.
+ /// The file path to save the image to.
+ /// The token to monitor for cancellation requests.
+ /// Thrown if the path is null.
+ /// A representing the asynchronous operation.
+ public static Task SaveAsWebpAsync(this Image source, string path, CancellationToken cancellationToken)
+ => SaveAsWebpAsync(source, path, null, cancellationToken);
+
+ ///
+ /// Saves the image to the given stream with the Webp format.
+ ///
+ /// The image this method extends.
+ /// The file path to save the image to.
+ /// The encoder to save the image with.
+ /// Thrown if the path is null.
+ public static void SaveAsWebp(this Image source, string path, WebpEncoder encoder) =>
+ source.Save(
+ path,
+ encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(WebpFormat.Instance));
+
+ ///
+ /// Saves the image to the given stream with the Webp format.
+ ///
+ /// The image this method extends.
+ /// The file path to save the image to.
+ /// The encoder to save the image with.
+ /// The token to monitor for cancellation requests.
+ /// Thrown if the path is null.
+ /// A representing the asynchronous operation.
+ public static Task SaveAsWebpAsync(this Image source, string path, WebpEncoder encoder, CancellationToken cancellationToken = default) =>
+ source.SaveAsync(
+ path,
+ encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(WebpFormat.Instance),
+ cancellationToken);
+
+ ///
+ /// Saves the image to the given stream with the Webp format.
+ ///
+ /// The image this method extends.
+ /// The stream to save the image to.
+ /// Thrown if the stream is null.
+ public static void SaveAsWebp(this Image source, Stream stream)
+ => SaveAsWebp(source, stream, null);
+
+ ///
+ /// Saves the image to the given stream with the Webp format.
+ ///
+ /// The image this method extends.
+ /// The stream to save the image to.
+ /// The token to monitor for cancellation requests.
+ /// Thrown if the stream is null.
+ /// A representing the asynchronous operation.
+ public static Task SaveAsWebpAsync(this Image source, Stream stream, CancellationToken cancellationToken = default)
+ => SaveAsWebpAsync(source, stream, null, cancellationToken);
+
+ ///
+ /// Saves the image to the given stream with the Webp format.
+ ///
+ /// The image this method extends.
+ /// The stream to save the image to.
+ /// The encoder to save the image with.
+ /// Thrown if the stream is null.
+ /// A representing the asynchronous operation.
+ public static void SaveAsWebp(this Image source, Stream stream, WebpEncoder encoder)
+ => source.Save(
+ stream,
+ encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(WebpFormat.Instance));
+
+ ///
+ /// Saves the image to the given stream with the Webp format.
+ ///
+ /// The image this method extends.
+ /// The stream to save the image to.
+ /// The encoder to save the image with.
+ /// The token to monitor for cancellation requests.
+ /// Thrown if the stream is null.
+ /// A representing the asynchronous operation.
+ public static Task SaveAsWebpAsync(this Image source, Stream stream, WebpEncoder encoder, CancellationToken cancellationToken = default) =>
+ source.SaveAsync(
+ stream,
+ encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(WebpFormat.Instance),
+ cancellationToken);
+
+ ///
+ /// Saves the image to the given stream with the Tiff format.
+ ///
+ /// The image this method extends.
+ /// The file path to save the image to.
+ /// Thrown if the path is null.
+ public static void SaveAsTiff(this Image source, string path) => SaveAsTiff(source, path, null);
+
+ ///
+ /// Saves the image to the given stream with the Tiff format.
+ ///
+ /// The image this method extends.
+ /// The file path to save the image to.
+ /// Thrown if the path is null.
+ /// A representing the asynchronous operation.
+ public static Task SaveAsTiffAsync(this Image source, string path) => SaveAsTiffAsync(source, path, null);
+
+ ///
+ /// Saves the image to the given stream with the Tiff format.
+ ///
+ /// The image this method extends.
+ /// The file path to save the image to.
+ /// The token to monitor for cancellation requests.
+ /// Thrown if the path is null.
+ /// A representing the asynchronous operation.
+ public static Task SaveAsTiffAsync(this Image source, string path, CancellationToken cancellationToken)
+ => SaveAsTiffAsync(source, path, null, cancellationToken);
+
+ ///
+ /// Saves the image to the given stream with the Tiff format.
+ ///
+ /// The image this method extends.
+ /// The file path to save the image to.
+ /// The encoder to save the image with.
+ /// Thrown if the path is null.
+ public static void SaveAsTiff(this Image source, string path, TiffEncoder encoder) =>
+ source.Save(
+ path,
+ encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(TiffFormat.Instance));
+
+ ///
+ /// Saves the image to the given stream with the Tiff format.
+ ///
+ /// The image this method extends.
+ /// The file path to save the image to.
+ /// The encoder to save the image with.
+ /// The token to monitor for cancellation requests.
+ /// Thrown if the path is null.
+ /// A representing the asynchronous operation.
+ public static Task SaveAsTiffAsync(this Image source, string path, TiffEncoder encoder, CancellationToken cancellationToken = default) =>
+ source.SaveAsync(
+ path,
+ encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(TiffFormat.Instance),
+ cancellationToken);
+
+ ///
+ /// Saves the image to the given stream with the Tiff format.
+ ///
+ /// The image this method extends.
+ /// The stream to save the image to.
+ /// Thrown if the stream is null.
+ public static void SaveAsTiff(this Image source, Stream stream)
+ => SaveAsTiff(source, stream, null);
+
+ ///
+ /// Saves the image to the given stream with the Tiff format.
+ ///
+ /// The image this method extends.
+ /// The stream to save the image to.
+ /// The token to monitor for cancellation requests.
+ /// Thrown if the stream is null.
+ /// A representing the asynchronous operation.
+ public static Task SaveAsTiffAsync(this Image source, Stream stream, CancellationToken cancellationToken = default)
+ => SaveAsTiffAsync(source, stream, null, cancellationToken);
+
+ ///
+ /// Saves the image to the given stream with the Tiff format.
+ ///
+ /// The image this method extends.
+ /// The stream to save the image to.
+ /// The encoder to save the image with.
+ /// Thrown if the stream is null.
+ /// A representing the asynchronous operation.
+ public static void SaveAsTiff(this Image source, Stream stream, TiffEncoder encoder)
+ => source.Save(
+ stream,
+ encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(TiffFormat.Instance));
+
+ ///
+ /// Saves the image to the given stream with the Tiff format.
+ ///
+ /// The image this method extends.
+ /// The stream to save the image to.
+ /// The encoder to save the image with.
+ /// The token to monitor for cancellation requests.
+ /// Thrown if the stream is null.
+ /// A representing the asynchronous operation.
+ public static Task SaveAsTiffAsync(this Image source, Stream stream, TiffEncoder encoder, CancellationToken cancellationToken = default) =>
+ source.SaveAsync(
+ stream,
+ encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(TiffFormat.Instance),
+ cancellationToken);
+
}
}
diff --git a/src/ImageSharp/Formats/ImageExtensions.Save.tt b/src/ImageSharp/Formats/ImageExtensions.Save.tt
index 63b404cc4..874f3ab0d 100644
--- a/src/ImageSharp/Formats/ImageExtensions.Save.tt
+++ b/src/ImageSharp/Formats/ImageExtensions.Save.tt
@@ -1,4 +1,4 @@
-<#@ template language="C#" #>
+<#@ template language="C#" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
// Copyright (c) Six Labors.
@@ -17,6 +17,8 @@ using SixLabors.ImageSharp.Advanced;
"Jpeg",
"Png",
"Tga",
+ "Webp",
+ "Tiff",
};
foreach (string fmt in formats)
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Block8x8.cs b/src/ImageSharp/Formats/Jpeg/Components/Block8x8.cs
index bc6036903..9d49b8c45 100644
--- a/src/ImageSharp/Formats/Jpeg/Components/Block8x8.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Block8x8.cs
@@ -2,17 +2,22 @@
// Licensed under the Apache License, Version 2.0.
using System;
-using System.Diagnostics;
+using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
+#if SUPPORTS_RUNTIME_INTRINSICS
+using System.Runtime.Intrinsics;
+using System.Runtime.Intrinsics.X86;
+#endif
using System.Text;
namespace SixLabors.ImageSharp.Formats.Jpeg.Components
{
///
- /// Represents a Jpeg block with coefficients.
+ /// 8x8 matrix of coefficients.
///
// ReSharper disable once InconsistentNaming
+ [StructLayout(LayoutKind.Explicit)]
internal unsafe struct Block8x8 : IEquatable
{
///
@@ -20,24 +25,44 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
///
public const int Size = 64;
+#pragma warning disable IDE0051 // Remove unused private member
///
- /// A fixed size buffer holding the values.
- /// See:
- /// https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/unsafe-code-pointers/fixed-size-buffers
- ///
+ /// A placeholder buffer so the actual struct occupies exactly 64 * 2 bytes.
///
+ ///
+ /// This is not used directly in the code.
+ ///
+ [FieldOffset(0)]
private fixed short data[Size];
-
- ///
- /// Initializes a new instance of the struct.
- ///
- /// A of coefficients
- public Block8x8(Span coefficients)
- {
- ref byte selfRef = ref Unsafe.As(ref this);
- ref byte sourceRef = ref Unsafe.As(ref MemoryMarshal.GetReference(coefficients));
- Unsafe.CopyBlock(ref selfRef, ref sourceRef, Size * sizeof(short));
- }
+#pragma warning restore IDE0051
+
+#if SUPPORTS_RUNTIME_INTRINSICS
+ [FieldOffset(0)]
+ public Vector128 V0;
+ [FieldOffset(16)]
+ public Vector128 V1;
+ [FieldOffset(32)]
+ public Vector128 V2;
+ [FieldOffset(48)]
+ public Vector128 V3;
+ [FieldOffset(64)]
+ public Vector128 V4;
+ [FieldOffset(80)]
+ public Vector128 V5;
+ [FieldOffset(96)]
+ public Vector128 V6;
+ [FieldOffset(112)]
+ public Vector128 V7;
+
+ [FieldOffset(0)]
+ public Vector256 V01;
+ [FieldOffset(32)]
+ public Vector256 V23;
+ [FieldOffset(64)]
+ public Vector256 V45;
+ [FieldOffset(96)]
+ public Vector256 V67;
+#endif
///
/// Gets or sets a value at the given index
@@ -49,7 +74,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
- GuardBlockIndex(idx);
+ DebugGuard.MustBeBetweenOrEqualTo(idx, 0, Size - 1, nameof(idx));
+
ref short selfRef = ref Unsafe.As(ref this);
return Unsafe.Add(ref selfRef, idx);
}
@@ -57,7 +83,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
[MethodImpl(MethodImplOptions.AggressiveInlining)]
set
{
- GuardBlockIndex(idx);
+ DebugGuard.MustBeBetweenOrEqualTo(idx, 0, Size - 1, nameof(idx));
+
ref short selfRef = ref Unsafe.As(ref this);
Unsafe.Add(ref selfRef, idx) = value;
}
@@ -75,15 +102,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
set => this[(y * 8) + x] = value;
}
- public static bool operator ==(Block8x8 left, Block8x8 right)
- {
- return left.Equals(right);
- }
+ public static bool operator ==(Block8x8 left, Block8x8 right) => left.Equals(right);
- public static bool operator !=(Block8x8 left, Block8x8 right)
- {
- return !left.Equals(right);
- }
+ public static bool operator !=(Block8x8 left, Block8x8 right) => !left.Equals(right);
///
/// Multiply all elements by a given
@@ -149,34 +170,11 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
return result;
}
- ///
- /// Pointer-based "Indexer" (getter part)
- ///
- /// Block pointer
- /// Index
- /// The scaleVec value at the specified index
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static short GetScalarAt(Block8x8* blockPtr, int idx)
- {
- GuardBlockIndex(idx);
-
- short* fp = blockPtr->data;
- return fp[idx];
- }
-
- ///
- /// Pointer-based "Indexer" (setter part)
- ///
- /// Block pointer
- /// Index
- /// Value
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static void SetScalarAt(Block8x8* blockPtr, int idx, short value)
+ public static Block8x8 Load(Span data)
{
- GuardBlockIndex(idx);
-
- short* fp = blockPtr->data;
- fp[idx] = value;
+ Unsafe.SkipInit(out Block8x8 result);
+ result.LoadFrom(data);
+ return result;
}
///
@@ -194,7 +192,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
///
public short[] ToArray()
{
- var result = new short[Size];
+ short[] result = new short[Size];
this.CopyTo(result);
return result;
}
@@ -206,7 +204,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
{
ref byte selfRef = ref Unsafe.As(ref this);
ref byte destRef = ref MemoryMarshal.GetReference(MemoryMarshal.Cast(destination));
- Unsafe.CopyBlock(ref destRef, ref selfRef, Size * sizeof(short));
+ Unsafe.CopyBlockUnaligned(ref destRef, ref selfRef, Size * sizeof(short));
}
///
@@ -220,6 +218,19 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
}
}
+ ///
+ /// Load raw 16bit integers from source.
+ ///
+ /// Source
+ [MethodImpl(InliningOptions.ShortMethod)]
+ public void LoadFrom(Span source)
+ {
+ ref byte sourceRef = ref Unsafe.As(ref MemoryMarshal.GetReference(source));
+ ref byte destRef = ref Unsafe.As(ref this);
+
+ Unsafe.CopyBlockUnaligned(ref destRef, ref sourceRef, Size * sizeof(short));
+ }
+
///
/// Cast and copy -s from the beginning of 'source' span.
///
@@ -231,13 +242,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
}
}
- [Conditional("DEBUG")]
- private static void GuardBlockIndex(int idx)
- {
- DebugGuard.MustBeLessThan(idx, Size, nameof(idx));
- DebugGuard.MustBeGreaterThanOrEqualTo(idx, 0, nameof(idx));
- }
-
///
public override string ToString()
{
@@ -271,15 +275,66 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
}
///
- public override bool Equals(object obj)
- {
- return obj is Block8x8 other && this.Equals(other);
- }
+ public override bool Equals(object obj) => obj is Block8x8 other && this.Equals(other);
///
- public override int GetHashCode()
+ public override int GetHashCode() => (this[0] * 31) + this[1];
+
+ ///
+ /// Returns index of the last non-zero element in given matrix.
+ ///
+ ///
+ /// Index of the last non-zero element. Returns -1 if all elements are equal to zero.
+ ///
+ [MethodImpl(InliningOptions.ShortMethod)]
+ public nint GetLastNonZeroIndex()
{
- return (this[0] * 31) + this[1];
+#if SUPPORTS_RUNTIME_INTRINSICS
+ if (Avx2.IsSupported)
+ {
+ const int equalityMask = unchecked((int)0b1111_1111_1111_1111_1111_1111_1111_1111);
+
+ Vector256 zero16 = Vector256.Zero;
+
+ ref Vector256 mcuStride = ref Unsafe.As>(ref this);
+
+ for (nint i = 3; i >= 0; i--)
+ {
+ int areEqual = Avx2.MoveMask(Avx2.CompareEqual(Unsafe.Add(ref mcuStride, i), zero16).AsByte());
+
+ if (areEqual != equalityMask)
+ {
+ // Each 2 bits represents comparison operation for each 2-byte element in input vectors
+ // LSB represents first element in the stride
+ // MSB represents last element in the stride
+ // lzcnt operation would calculate number of zero numbers at the end
+
+ // Given mask is not actually suitable for lzcnt as 1's represent zero elements and 0's represent non-zero elements
+ // So we need to invert it
+ int lzcnt = BitOperations.LeadingZeroCount(~(uint)areEqual);
+
+ // As input number is represented by 2 bits in the mask, we need to divide lzcnt result by 2
+ // to get the exact number of zero elements in the stride
+ int strideRelativeIndex = 15 - (lzcnt / 2);
+ return (i * 16) + strideRelativeIndex;
+ }
+ }
+
+ return -1;
+ }
+ else
+#endif
+ {
+ nint index = Size - 1;
+ ref short elemRef = ref Unsafe.As(ref this);
+
+ while (index >= 0 && Unsafe.Add(ref elemRef, index) == 0)
+ {
+ index--;
+ }
+
+ return index;
+ }
}
///
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Intrinsic.cs b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Intrinsic.cs
new file mode 100644
index 000000000..0971ccdca
--- /dev/null
+++ b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Intrinsic.cs
@@ -0,0 +1,149 @@
+// Copyright (c) Six Labors.
+// Licensed under the Apache License, Version 2.0.
+
+#if SUPPORTS_RUNTIME_INTRINSICS
+using System;
+using System.Numerics;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Runtime.Intrinsics;
+using System.Runtime.Intrinsics.X86;
+
+namespace SixLabors.ImageSharp.Formats.Jpeg.Components
+{
+ internal partial struct Block8x8F
+ {
+ ///
+ /// A number of rows of 8 scalar coefficients each in
+ ///
+ public const int RowCount = 8;
+
+ [FieldOffset(0)]
+ public Vector256 V0;
+ [FieldOffset(32)]
+ public Vector256 V1;
+ [FieldOffset(64)]
+ public Vector256 V2;
+ [FieldOffset(96)]
+ public Vector256 V3;
+ [FieldOffset(128)]
+ public Vector256 V4;
+ [FieldOffset(160)]
+ public Vector256 V5;
+ [FieldOffset(192)]
+ public Vector256 V6;
+ [FieldOffset(224)]
+ public Vector256 V7;
+
+ private static readonly Vector256 MultiplyIntoInt16ShuffleMask = Vector256.Create(0, 1, 4, 5, 2, 3, 6, 7);
+
+ private static unsafe void MultiplyIntoInt16_Avx2(ref Block8x8F a, ref Block8x8F b, ref Block8x8 dest)
+ {
+ DebugGuard.IsTrue(Avx2.IsSupported, "Avx2 support is required to run this operation!");
+
+ ref Vector256 aBase = ref a.V0;
+ ref Vector256 bBase = ref b.V0;
+
+ ref Vector256 destRef = ref dest.V01;
+
+ for (nint i = 0; i < 8; i += 2)
+ {
+ Vector256 row0 = Avx.ConvertToVector256Int32(Avx.Multiply(Unsafe.Add(ref aBase, i + 0), Unsafe.Add(ref bBase, i + 0)));
+ Vector256 row1 = Avx.ConvertToVector256Int32(Avx.Multiply(Unsafe.Add(ref aBase, i + 1), Unsafe.Add(ref bBase, i + 1)));
+
+ Vector256 row = Avx2.PackSignedSaturate(row0, row1);
+ row = Avx2.PermuteVar8x32(row.AsInt32(), MultiplyIntoInt16ShuffleMask).AsInt16();
+
+ Unsafe.Add(ref destRef, (IntPtr)((uint)i / 2)) = row;
+ }
+ }
+
+ private static void MultiplyIntoInt16_Sse2(ref Block8x8F a, ref Block8x8F b, ref Block8x8 dest)
+ {
+ DebugGuard.IsTrue(Sse2.IsSupported, "Sse2 support is required to run this operation!");
+
+ ref Vector128 aBase = ref Unsafe.As>(ref a);
+ ref Vector128 bBase = ref Unsafe.As>(ref b);
+
+ ref Vector128 destBase = ref Unsafe.As>(ref dest);
+
+ for (int i = 0; i < 16; i += 2)
+ {
+ Vector128 left = Sse2.ConvertToVector128Int32(Sse.Multiply(Unsafe.Add(ref aBase, i + 0), Unsafe.Add(ref bBase, i + 0)));
+ Vector128 right = Sse2.ConvertToVector128Int32(Sse.Multiply(Unsafe.Add(ref aBase, i + 1), Unsafe.Add(ref bBase, i + 1)));
+
+ Vector128 row = Sse2.PackSignedSaturate(left, right);
+ Unsafe.Add(ref destBase, (IntPtr)((uint)i / 2)) = row;
+ }
+ }
+
+ private void TransposeInplace_Avx()
+ {
+ // https://stackoverflow.com/questions/25622745/transpose-an-8x8-float-using-avx-avx2/25627536#25627536
+ Vector256 r0 = Avx.InsertVector128(
+ this.V0,
+ Unsafe.As>(ref this.V4L),
+ 1);
+
+ Vector256 r1 = Avx.InsertVector128(
+ this.V1,
+ Unsafe.As>(ref this.V5L),
+ 1);
+
+ Vector256 r2 = Avx.InsertVector128(
+ this.V2,
+ Unsafe.As>(ref this.V6L),
+ 1);
+
+ Vector256 r3 = Avx.InsertVector128(
+ this.V3,
+ Unsafe.As>(ref this.V7L),
+ 1);
+
+ Vector256