diff --git a/.gitattributes b/.gitattributes
index 70ced6903..355b64dce 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -87,7 +87,6 @@
*.eot binary
*.exe binary
*.otf binary
-*.pbm binary
*.pdf binary
*.ppt binary
*.pptx binary
@@ -95,7 +94,6 @@
*.snk binary
*.ttc binary
*.ttf binary
-*.wbmp binary
*.woff binary
*.woff2 binary
*.xls binary
@@ -126,3 +124,9 @@
*.dds filter=lfs diff=lfs merge=lfs -text
*.ktx filter=lfs diff=lfs merge=lfs -text
*.ktx2 filter=lfs diff=lfs merge=lfs -text
+*.pam filter=lfs diff=lfs merge=lfs -text
+*.pbm filter=lfs diff=lfs merge=lfs -text
+*.pgm filter=lfs diff=lfs merge=lfs -text
+*.ppm filter=lfs diff=lfs merge=lfs -text
+*.pnm filter=lfs diff=lfs merge=lfs -text
+*.wbmp filter=lfs diff=lfs merge=lfs -text
diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
index 1326c72e8..62a8bf2b4 100644
--- a/.github/ISSUE_TEMPLATE/config.yml
+++ b/.github/ISSUE_TEMPLATE/config.yml
@@ -1,8 +1,5 @@
blank_issues_enabled: false
contact_links:
- - name: Ask a Question
- url: https://github.com/SixLabors/ImageSharp/discussions?discussions_q=category%3AQ%26A
- about: Ask a question about this project.
- name: Feature Request
url: https://github.com/SixLabors/ImageSharp/discussions?discussions_q=category%3AIdeas
about: Share ideas for new features for this project.
diff --git a/.github/ISSUE_TEMPLATE/oss-bug-report.md b/.github/ISSUE_TEMPLATE/oss-bug-report.md
index e0d37de53..9e9567a99 100644
--- a/.github/ISSUE_TEMPLATE/oss-bug-report.md
+++ b/.github/ISSUE_TEMPLATE/oss-bug-report.md
@@ -1,6 +1,6 @@
---
name: "OSS : Bug Report"
-about: Create a report to help us improve the project.
+about: Create a report to help us improve the project. OSS Issues are not guaranteed to be triaged.
labels: needs triage
---
diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml
index 5189f0435..6d31e8c53 100644
--- a/.github/workflows/build-and-test.yml
+++ b/.github/workflows/build-and-test.yml
@@ -1,202 +1,196 @@
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
- codecov: false
- - os: macos-latest
- framework: net5.0
- runtime: -x64
- codecov: false
- - os: windows-latest
- framework: net5.0
- runtime: -x64
- codecov: false
- - os: ubuntu-latest
- framework: netcoreapp3.1
- runtime: -x64
- codecov: true
- - os: macos-latest
- framework: netcoreapp3.1
- runtime: -x64
- codecov: false
- - os: windows-latest
- framework: netcoreapp3.1
- runtime: -x64
- codecov: false
- - os: windows-latest
- framework: netcoreapp2.1
- runtime: -x64
- codecov: false
- - os: windows-latest
- framework: net472
- runtime: -x64
- codecov: false
- - os: windows-latest
- framework: net472
- runtime: -x86
- codecov: false
-
- runs-on: ${{matrix.options.os}}
-
- steps:
- - 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: Git Create LFS FileList
- run: git lfs ls-files -l | cut -d' ' -f1 | sort > .lfs-assets-id
-
- - 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 Pull LFS
- run: git lfs pull
-
- - 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 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: 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
-
- - 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: Codecov Update
- uses: codecov/codecov-action@v1
- if: matrix.options.codecov == true && startsWith(github.repository, 'SixLabors')
- with:
- flags: unittests
-
- Publish:
- needs: [Build]
-
- runs-on: ubuntu-latest
-
- if: (github.event_name == 'push')
-
- steps:
- - 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
-
- - 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: MyGet Publish
- shell: pwsh
- run: |
- 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
+ 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
+ codecov: false
+ - os: macos-latest
+ framework: net5.0
+ runtime: -x64
+ codecov: false
+ - os: windows-latest
+ framework: net5.0
+ runtime: -x64
+ codecov: false
+ - os: ubuntu-latest
+ framework: netcoreapp3.1
+ runtime: -x64
+ codecov: false
+ - os: macos-latest
+ framework: netcoreapp3.1
+ runtime: -x64
+ codecov: false
+ - os: windows-latest
+ framework: netcoreapp3.1
+ runtime: -x64
+ codecov: false
+ - os: windows-latest
+ framework: netcoreapp2.1
+ runtime: -x64
+ codecov: false
+ - os: windows-latest
+ framework: net472
+ runtime: -x64
+ codecov: false
+ - os: windows-latest
+ framework: net472
+ runtime: -x86
+ codecov: false
+
+ runs-on: ${{matrix.options.os}}
+
+ steps:
+ - 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: Git Create LFS FileList
+ run: git lfs ls-files -l | cut -d' ' -f1 | sort > .lfs-assets-id
+
+ - 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 Pull LFS
+ run: git lfs pull
+
+ - 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 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: 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
+
+ - 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/
+
+ Publish:
+ needs: [Build]
+
+ runs-on: ubuntu-latest
+
+ if: (github.event_name == 'push')
+
+ steps:
+ - 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
+
+ - 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: MyGet Publish
+ shell: pwsh
+ run: |
+ 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/.github/workflows/code-coverage.yml b/.github/workflows/code-coverage.yml
new file mode 100644
index 000000000..2b14f2a4b
--- /dev/null
+++ b/.github/workflows/code-coverage.yml
@@ -0,0 +1,81 @@
+name: CodeCoverage
+
+on:
+ schedule:
+ # 2AM every Tuesday/Thursday
+ - cron: "0 2 * * 2,4"
+jobs:
+ Build:
+ strategy:
+ matrix:
+ options:
+ - os: ubuntu-latest
+ framework: netcoreapp3.1
+ runtime: -x64
+ codecov: true
+
+ runs-on: ${{matrix.options.os}}
+
+ steps:
+ - 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: Git Create LFS FileList
+ run: git lfs ls-files -l | cut -d' ' -f1 | sort > .lfs-assets-id
+
+ - 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 Pull LFS
+ run: git lfs pull
+
+ - 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 Build
+ shell: pwsh
+ run: ./ci-build.ps1 "${{matrix.options.framework}}"
+ env:
+ SIXLABORS_TESTING: True
+
+ - name: DotNet Test
+ 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
+
+ - 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: Codecov Update
+ uses: codecov/codecov-action@v1
+ if: matrix.options.codecov == true && startsWith(github.repository, 'SixLabors')
+ with:
+ flags: unittests
diff --git a/Directory.Build.props b/Directory.Build.props
index 3899ce939..26b3cc5af 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -13,6 +13,9 @@
$(MSBuildThisFileDirectory)
+
+
+ $(DefineConstants);DEBUG
@@ -30,5 +33,4 @@
true
-
diff --git a/ImageSharp.sln b/ImageSharp.sln
index f16f98ac5..17d293b43 100644
--- a/ImageSharp.sln
+++ b/ImageSharp.sln
@@ -551,6 +551,7 @@ EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "workflows", "workflows", "{C0D7754B-5277-438E-ABEB-2BA34401B5A7}"
ProjectSection(SolutionItems) = preProject
.github\workflows\build-and-test.yml = .github\workflows\build-and-test.yml
+ .github\workflows\code-coverage.yml = .github\workflows\code-coverage.yml
EndProjectSection
EndProject
Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "SharedInfrastructure", "shared-infrastructure\src\SharedInfrastructure\SharedInfrastructure.shproj", "{68A8CC40-6AED-4E96-B524-31B1158FDEEA}"
diff --git a/README.md b/README.md
index ab16bbb76..fdf14b496 100644
--- a/README.md
+++ b/README.md
@@ -20,7 +20,7 @@ ImageSharp is a new, fully featured, fully managed, cross-platform, 2D graphics
ImageSharp is designed from the ground up to be flexible and extensible. The library provides API endpoints for common image processing operations and the building blocks to allow for the development of additional operations.
-Built against [.NET Standard 1.3](https://docs.microsoft.com/en-us/dotnet/standard/net-standard), ImageSharp can be used in device, cloud, and embedded/IoT scenarios.
+Built against [.NET Standard 2.0](https://docs.microsoft.com/en-us/dotnet/standard/net-standard), ImageSharp can be used in device, cloud, and embedded/IoT scenarios.
## License
diff --git a/shared-infrastructure b/shared-infrastructure
index 33cb12ca7..59ce17f5a 160000
--- a/shared-infrastructure
+++ b/shared-infrastructure
@@ -1 +1 @@
-Subproject commit 33cb12ca77f919b44de56f344d2627cc2a108c3a
+Subproject commit 59ce17f5a4e1f956811133f41add7638e74c2836
diff --git a/src/ImageSharp/Advanced/AdvancedImageExtensions.cs b/src/ImageSharp/Advanced/AdvancedImageExtensions.cs
index 54a773be0..829c6155d 100644
--- a/src/ImageSharp/Advanced/AdvancedImageExtensions.cs
+++ b/src/ImageSharp/Advanced/AdvancedImageExtensions.cs
@@ -143,7 +143,7 @@ namespace SixLabors.ImageSharp.Advanced
/// The source.
/// The row.
/// The
- public static Memory GetPixelRowMemory(this ImageFrame source, int rowIndex)
+ public static Memory DangerousGetPixelRowMemory(this ImageFrame source, int rowIndex)
where TPixel : unmanaged, IPixel
{
Guard.NotNull(source, nameof(source));
@@ -161,7 +161,7 @@ namespace SixLabors.ImageSharp.Advanced
/// The source.
/// The row.
/// The
- public static Memory GetPixelRowMemory(this Image source, int rowIndex)
+ public static Memory DangerousGetPixelRowMemory(this Image source, int rowIndex)
where TPixel : unmanaged, IPixel
{
Guard.NotNull(source, nameof(source));
diff --git a/src/ImageSharp/Advanced/AotCompilerTools.cs b/src/ImageSharp/Advanced/AotCompilerTools.cs
index 3961cc6c5..82a146dc7 100644
--- a/src/ImageSharp/Advanced/AotCompilerTools.cs
+++ b/src/ImageSharp/Advanced/AotCompilerTools.cs
@@ -10,6 +10,7 @@ using SixLabors.ImageSharp.Formats.Bmp;
using SixLabors.ImageSharp.Formats.Gif;
using SixLabors.ImageSharp.Formats.Jpeg;
using SixLabors.ImageSharp.Formats.Jpeg.Components;
+using SixLabors.ImageSharp.Formats.Pbm;
using SixLabors.ImageSharp.Formats.Png;
using SixLabors.ImageSharp.Formats.Tga;
using SixLabors.ImageSharp.Formats.Tiff;
@@ -74,6 +75,7 @@ namespace SixLabors.ImageSharp.Advanced
Seed();
Seed();
+ Seed();
Seed();
Seed();
Seed();
@@ -148,6 +150,7 @@ namespace SixLabors.ImageSharp.Advanced
Image img = default;
img.CloneAs(default);
img.CloneAs(default);
+ img.CloneAs(default);
img.CloneAs(default);
img.CloneAs(default);
img.CloneAs(default);
@@ -200,6 +203,7 @@ namespace SixLabors.ImageSharp.Advanced
default(BmpEncoderCore).Encode(default, default, default);
default(GifEncoderCore).Encode(default, default, default);
default(JpegEncoderCore).Encode(default, default, default);
+ default(PbmEncoderCore).Encode(default, default, default);
default(PngEncoderCore).Encode(default, default, default);
default(TgaEncoderCore).Encode(default, default, default);
default(TiffEncoderCore).Encode(default, default, default);
@@ -217,6 +221,7 @@ namespace SixLabors.ImageSharp.Advanced
default(BmpDecoderCore).Decode(default, default, default);
default(GifDecoderCore).Decode(default, default, default);
default(JpegDecoderCore).Decode(default, default, default);
+ default(PbmDecoderCore).Decode(default, default, default);
default(PngDecoderCore).Decode(default, default, default);
default(TgaDecoderCore).Decode(default, default, default);
default(TiffDecoderCore).Decode(default, default, default);
@@ -234,6 +239,7 @@ namespace SixLabors.ImageSharp.Advanced
AotCompileImageEncoder();
AotCompileImageEncoder();
AotCompileImageEncoder();
+ AotCompileImageEncoder();
AotCompileImageEncoder();
AotCompileImageEncoder();
AotCompileImageEncoder();
@@ -251,6 +257,7 @@ namespace SixLabors.ImageSharp.Advanced
AotCompileImageDecoder();
AotCompileImageDecoder();
AotCompileImageDecoder();
+ AotCompileImageDecoder();
AotCompileImageDecoder();
AotCompileImageDecoder();
AotCompileImageDecoder();
@@ -529,7 +536,7 @@ namespace SixLabors.ImageSharp.Advanced
private static void AotCompileMemoryManagers()
where TPixel : unmanaged, IPixel
{
- AotCompileMemoryManager();
+ AotCompileMemoryManager();
AotCompileMemoryManager();
}
diff --git a/src/ImageSharp/Color/Color.Conversions.cs b/src/ImageSharp/Color/Color.Conversions.cs
index bf7869e53..5c10bfaa0 100644
--- a/src/ImageSharp/Color/Color.Conversions.cs
+++ b/src/ImageSharp/Color/Color.Conversions.cs
@@ -89,6 +89,17 @@ namespace SixLabors.ImageSharp
this.boxedHighPrecisionPixel = null;
}
+ ///
+ /// Initializes a new instance of the struct.
+ ///
+ /// The containing the color information.
+ [MethodImpl(InliningOptions.ShortMethod)]
+ public Color(Abgr32 pixel)
+ {
+ this.data = new Rgba64(pixel);
+ this.boxedHighPrecisionPixel = null;
+ }
+
///
/// Initializes a new instance of the struct.
///
@@ -177,6 +188,19 @@ namespace SixLabors.ImageSharp
return value;
}
+ [MethodImpl(InliningOptions.ShortMethod)]
+ internal Abgr32 ToAbgr32()
+ {
+ if (this.boxedHighPrecisionPixel is null)
+ {
+ return this.data.ToAbgr32();
+ }
+
+ Abgr32 value = default;
+ value.FromScaledVector4(this.boxedHighPrecisionPixel.ToScaledVector4());
+ return value;
+ }
+
[MethodImpl(InliningOptions.ShortMethod)]
internal Rgb24 ToRgb24()
{
diff --git a/src/ImageSharp/Color/Color.cs b/src/ImageSharp/Color/Color.cs
index 7c21d62dd..cd0583361 100644
--- a/src/ImageSharp/Color/Color.cs
+++ b/src/ImageSharp/Color/Color.cs
@@ -270,8 +270,15 @@ namespace SixLabors.ImageSharp
return pixel;
}
+ if (this.boxedHighPrecisionPixel is null)
+ {
+ pixel = default;
+ pixel.FromRgba64(this.data);
+ return pixel;
+ }
+
pixel = default;
- pixel.FromRgba64(this.data);
+ pixel.FromScaledVector4(this.boxedHighPrecisionPixel.ToScaledVector4());
return pixel;
}
diff --git a/src/ImageSharp/Common/Helpers/DebugGuard.cs b/src/ImageSharp/Common/Helpers/DebugGuard.cs
index f56cb37a8..f438ca9e2 100644
--- a/src/ImageSharp/Common/Helpers/DebugGuard.cs
+++ b/src/ImageSharp/Common/Helpers/DebugGuard.cs
@@ -26,6 +26,20 @@ namespace SixLabors
}
}
+ ///
+ /// Verifies whether a condition (indicating disposed state) is met, throwing an ObjectDisposedException if it's true.
+ ///
+ /// Whether the object is disposed.
+ /// The name of the object.
+ [Conditional("DEBUG")]
+ public static void NotDisposed(bool isDisposed, string objectName)
+ {
+ if (isDisposed)
+ {
+ throw new ObjectDisposedException(objectName);
+ }
+ }
+
///
/// Verifies, that the target span is of same size than the 'other' span.
///
diff --git a/src/ImageSharp/Common/Helpers/Guard.cs b/src/ImageSharp/Common/Helpers/Guard.cs
index 0b5cc21cb..0f6efcb3c 100644
--- a/src/ImageSharp/Common/Helpers/Guard.cs
+++ b/src/ImageSharp/Common/Helpers/Guard.cs
@@ -2,9 +2,6 @@
// Licensed under the Apache License, Version 2.0.
using System;
-#if NETSTANDARD1_3
-using System.Reflection;
-#endif
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp;
@@ -22,11 +19,7 @@ namespace SixLabors
[MethodImpl(InliningOptions.ShortMethod)]
public static void MustBeValueType(TValue value, string parameterName)
{
- if (value.GetType()
-#if NETSTANDARD1_3
- .GetTypeInfo()
-#endif
- .IsValueType)
+ if (value.GetType().IsValueType)
{
return;
}
diff --git a/src/ImageSharp/Common/Helpers/HexConverter.cs b/src/ImageSharp/Common/Helpers/HexConverter.cs
new file mode 100644
index 000000000..c55e9bbd9
--- /dev/null
+++ b/src/ImageSharp/Common/Helpers/HexConverter.cs
@@ -0,0 +1,98 @@
+// Copyright (c) Six Labors.
+// Licensed under the Apache License, Version 2.0.
+
+using System;
+using System.Runtime.CompilerServices;
+
+namespace SixLabors.ImageSharp.Common.Helpers
+{
+ internal static class HexConverter
+ {
+ ///
+ /// Parses a hexadecimal string into a byte array without allocations. Throws on non-hexadecimal character.
+ /// Adapted from https://source.dot.net/#System.Private.CoreLib/Convert.cs,c9e4fbeaca708991.
+ ///
+ /// The hexadecimal string to parse.
+ /// The destination for the parsed bytes. Must be at least .Length / 2 bytes long.
+ /// The number of bytes written to .
+ public static int HexStringToBytes(ReadOnlySpan chars, Span bytes)
+ {
+ if ((chars.Length % 2) != 0)
+ {
+ throw new ArgumentException("Input string length must be a multiple of 2", nameof(chars));
+ }
+
+ if ((bytes.Length * 2) < chars.Length)
+ {
+ throw new ArgumentException("Output span must be at least half the length of the input string");
+ }
+ else
+ {
+ // Slightly better performance in the loop below, allows us to skip a bounds check
+ // while still supporting output buffers that are larger than necessary
+ bytes = bytes.Slice(0, chars.Length / 2);
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ static int FromChar(int c)
+ {
+ // Map from an ASCII char to its hex value, e.g. arr['b'] == 11. 0xFF means it's not a hex digit.
+ // This doesn't actually allocate.
+ ReadOnlySpan charToHexLookup = new byte[]
+ {
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 15
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 31
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 47
+ 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 63
+ 0xFF, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 79
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 95
+ 0xFF, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 111
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 127
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 143
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 159
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 175
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 191
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 207
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 223
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 239
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 255
+ };
+
+ return c >= charToHexLookup.Length ? 0xFF : charToHexLookup[c];
+ }
+
+ // See https://source.dot.net/#System.Private.CoreLib/HexConverter.cs,4681d45a0aa0b361
+ int i = 0;
+ int j = 0;
+ int byteLo = 0;
+ int byteHi = 0;
+ while (j < bytes.Length)
+ {
+ byteLo = FromChar(chars[i + 1]);
+ byteHi = FromChar(chars[i]);
+
+ // byteHi hasn't been shifted to the high half yet, so the only way the bitwise or produces this pattern
+ // is if either byteHi or byteLo was not a hex character.
+ if ((byteLo | byteHi) == 0xFF)
+ {
+ break;
+ }
+
+ bytes[j++] = (byte)((byteHi << 4) | byteLo);
+ i += 2;
+ }
+
+ if (byteLo == 0xFF)
+ {
+ i++;
+ }
+
+ if ((byteLo | byteHi) == 0xFF)
+ {
+ throw new ArgumentException("Input string contained non-hexadecimal characters", nameof(chars));
+ }
+
+ return j;
+ }
+ }
+}
diff --git a/src/ImageSharp/Common/Helpers/Numerics.cs b/src/ImageSharp/Common/Helpers/Numerics.cs
index ba5c588ca..7de838bc9 100644
--- a/src/ImageSharp/Common/Helpers/Numerics.cs
+++ b/src/ImageSharp/Common/Helpers/Numerics.cs
@@ -820,6 +820,26 @@ namespace SixLabors.ImageSharp
}
}
+ ///
+ /// Reduces elements of the vector into one sum.
+ ///
+ /// The accumulator to reduce.
+ /// The sum of all elements.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static int ReduceSum(Vector256 accumulator)
+ {
+ // Add upper lane to lower lane.
+ Vector128 vsum = Sse2.Add(accumulator.GetLower(), accumulator.GetUpper());
+
+ // Add odd to even.
+ vsum = Sse2.Add(vsum, Sse2.Shuffle(vsum, 0b_11_11_01_01));
+
+ // Add high to low.
+ vsum = Sse2.Add(vsum, Sse2.Shuffle(vsum, 0b_11_10_11_10));
+
+ return Sse2.ConvertToInt32(vsum);
+ }
+
///
/// Reduces even elements of the vector into one sum.
///
@@ -887,5 +907,71 @@ namespace SixLabors.ImageSharp
/// Divisor value.
/// Ceiled division result.
public static uint DivideCeil(uint value, uint divisor) => (value + divisor - 1) / divisor;
+
+ ///
+ /// Rotates the specified value left by the specified number of bits.
+ ///
+ /// The value to rotate.
+ /// The number of bits to rotate with.
+ /// The rotated value.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static uint RotateLeft(uint value, int offset)
+ {
+#if SUPPORTS_BITOPERATIONS
+ return BitOperations.RotateLeft(value, offset);
+#else
+ return RotateLeftSoftwareFallback(value, offset);
+#endif
+ }
+
+#if !SUPPORTS_BITOPERATIONS
+ ///
+ /// Rotates the specified value left by the specified number of bits.
+ ///
+ /// The value to rotate.
+ /// The number of bits to rotate with.
+ /// The rotated value.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static uint RotateLeftSoftwareFallback(uint value, int offset)
+ => (value << offset) | (value >> (32 - offset));
+#endif
+
+ ///
+ /// Rotates the specified value right by the specified number of bits.
+ ///
+ /// The value to rotate.
+ /// The number of bits to rotate with.
+ /// The rotated value.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static uint RotateRight(uint value, int offset)
+ {
+#if SUPPORTS_BITOPERATIONS
+ return BitOperations.RotateRight(value, offset);
+#else
+ return RotateRightSoftwareFallback(value, offset);
+#endif
+ }
+
+#if !SUPPORTS_BITOPERATIONS
+ ///
+ /// Rotates the specified value right by the specified number of bits.
+ ///
+ /// The value to rotate.
+ /// The number of bits to rotate with.
+ /// The rotated value.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static uint RotateRightSoftwareFallback(uint value, int offset)
+ => (value >> offset) | (value << (32 - offset));
+#endif
+
+ ///
+ /// Tells whether input value is outside of the given range.
+ ///
+ /// Value.
+ /// Mininum value, inclusive.
+ /// Maximum value, inclusive.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static bool IsOutOfRange(int value, int min, int max)
+ => (uint)(value - min) > (uint)(max - min);
}
}
diff --git a/src/ImageSharp/Common/Helpers/Shuffle/IComponentShuffle.cs b/src/ImageSharp/Common/Helpers/Shuffle/IComponentShuffle.cs
index 7687a5b95..049c61185 100644
--- a/src/ImageSharp/Common/Helpers/Shuffle/IComponentShuffle.cs
+++ b/src/ImageSharp/Common/Helpers/Shuffle/IComponentShuffle.cs
@@ -28,6 +28,10 @@ namespace SixLabors.ImageSharp
///
/// The source span of bytes.
/// The destination span of bytes.
+ ///
+ /// Implementation can assume that source.Length is less or equal than dest.Length.
+ /// Loops should iterate using source.Length.
+ ///
void RunFallbackShuffle(ReadOnlySpan source, Span dest);
}
@@ -153,7 +157,7 @@ namespace SixLabors.ImageSharp
// packed = [W Z Y X]
// ROTR(8, packedArgb) = [Y Z W X]
- Unsafe.Add(ref dBase, i) = (packed >> 8) | (packed << 24);
+ Unsafe.Add(ref dBase, i) = Numerics.RotateRight(packed, 8);
}
}
}
@@ -184,7 +188,40 @@ namespace SixLabors.ImageSharp
// tmp1 + tmp3 = [W X Y Z]
uint tmp1 = packed & 0xFF00FF00;
uint tmp2 = packed & 0x00FF00FF;
- uint tmp3 = (tmp2 << 16) | (tmp2 >> 16);
+ uint tmp3 = Numerics.RotateLeft(tmp2, 16);
+
+ Unsafe.Add(ref dBase, i) = tmp1 + tmp3;
+ }
+ }
+ }
+
+ internal readonly struct XWZYShuffle4 : IShuffle4
+ {
+ public byte Control
+ {
+ [MethodImpl(InliningOptions.ShortMethod)]
+ get => SimdUtils.Shuffle.MmShuffle(1, 2, 3, 0);
+ }
+
+ [MethodImpl(InliningOptions.ShortMethod)]
+ public void RunFallbackShuffle(ReadOnlySpan source, Span dest)
+ {
+ ref uint sBase = ref Unsafe.As(ref MemoryMarshal.GetReference(source));
+ ref uint dBase = ref Unsafe.As(ref MemoryMarshal.GetReference(dest));
+ int n = source.Length / 4;
+
+ for (int i = 0; i < n; i++)
+ {
+ uint packed = Unsafe.Add(ref sBase, i);
+
+ // packed = [W Z Y X]
+ // tmp1 = [0 Z 0 X]
+ // tmp2 = [W 0 Y 0]
+ // tmp3=ROTL(16, tmp2) = [Y 0 W 0]
+ // tmp1 + tmp3 = [Y Z W X]
+ uint tmp1 = packed & 0x00FF00FF;
+ uint tmp2 = packed & 0xFF00FF00;
+ uint tmp3 = Numerics.RotateLeft(tmp2, 16);
Unsafe.Add(ref dBase, i) = tmp1 + tmp3;
}
diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.Shuffle.cs b/src/ImageSharp/Common/Helpers/SimdUtils.Shuffle.cs
index 07744566a..abf9e9fed 100644
--- a/src/ImageSharp/Common/Helpers/SimdUtils.Shuffle.cs
+++ b/src/ImageSharp/Common/Helpers/SimdUtils.Shuffle.cs
@@ -77,6 +77,7 @@ namespace SixLabors.ImageSharp
TShuffle shuffle)
where TShuffle : struct, IShuffle3
{
+ // Source length should be smaller than dest length, and divisible by 3.
VerifyShuffle3SpanInput(source, dest);
#if SUPPORTS_RUNTIME_INTRINSICS
@@ -182,9 +183,9 @@ namespace SixLabors.ImageSharp
where T : struct
{
DebugGuard.IsTrue(
- source.Length == dest.Length,
+ source.Length <= dest.Length,
nameof(source),
- "Input spans must be of same length!");
+ "Source should fit into dest!");
DebugGuard.IsTrue(
source.Length % 3 == 0,
diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.cs b/src/ImageSharp/Common/Helpers/SimdUtils.cs
index 6d82cfad0..29068a82c 100644
--- a/src/ImageSharp/Common/Helpers/SimdUtils.cs
+++ b/src/ImageSharp/Common/Helpers/SimdUtils.cs
@@ -33,18 +33,6 @@ namespace SixLabors.ImageSharp
public static bool HasVector4 { get; } =
Vector.IsHardwareAccelerated && Vector.Count == 4;
- public static bool HasAvx2
- {
- get
- {
-#if SUPPORTS_RUNTIME_INTRINSICS
- return Avx2.IsSupported;
-#else
- return false;
-#endif
- }
- }
-
///
/// Transform all scalars in 'v' in a way that converting them to would have rounding semantics.
///
diff --git a/src/ImageSharp/Common/Tuples/Vector4Pair.cs b/src/ImageSharp/Common/Tuples/Vector4Pair.cs
deleted file mode 100644
index 6294a6177..000000000
--- a/src/ImageSharp/Common/Tuples/Vector4Pair.cs
+++ /dev/null
@@ -1,82 +0,0 @@
-// Copyright (c) Six Labors.
-// Licensed under the Apache License, Version 2.0.
-
-using System.Numerics;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-
-namespace SixLabors.ImageSharp.Tuples
-{
- ///
- /// Its faster to process multiple Vector4-s together, so let's pair them!
- /// On AVX2 this pair should be convertible to of !
- /// TODO: Investigate defining this as union with an Octet.OfSingle type.
- ///
- [StructLayout(LayoutKind.Sequential)]
- internal struct Vector4Pair
- {
- public Vector4 A;
-
- public Vector4 B;
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void MultiplyInplace(float value)
- {
- this.A *= value;
- this.B *= value;
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void AddInplace(Vector4 value)
- {
- this.A += value;
- this.B += value;
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void AddInplace(ref Vector4Pair other)
- {
- this.A += other.A;
- this.B += other.B;
- }
-
- /// .
- /// Downscale method, specific to Jpeg color conversion. Works only if Vector{float}.Count == 4! /// TODO: Move it somewhere else.
- ///
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal void RoundAndDownscalePreVector8(float downscaleFactor)
- {
- ref Vector a = ref Unsafe.As>(ref this.A);
- a = a.FastRound();
-
- ref Vector b = ref Unsafe.As>(ref this.B);
- b = b.FastRound();
-
- // Downscale by 1/factor
- var scale = new Vector4(1 / downscaleFactor);
- this.A *= scale;
- this.B *= scale;
- }
-
- ///
- /// AVX2-only Downscale method, specific to Jpeg color conversion.
- /// TODO: Move it somewhere else.
- ///
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal void RoundAndDownscaleVector8(float downscaleFactor)
- {
- ref Vector self = ref Unsafe.As>(ref this);
- Vector v = self;
- v = v.FastRound();
-
- // Downscale by 1/factor
- v *= new Vector(1 / downscaleFactor);
- self = v;
- }
-
- public override string ToString()
- {
- return $"{nameof(Vector4Pair)}({this.A}, {this.B})";
- }
- }
-}
diff --git a/src/ImageSharp/Configuration.cs b/src/ImageSharp/Configuration.cs
index ea9524827..3e021dda8 100644
--- a/src/ImageSharp/Configuration.cs
+++ b/src/ImageSharp/Configuration.cs
@@ -8,6 +8,7 @@ using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.Formats.Bmp;
using SixLabors.ImageSharp.Formats.Gif;
using SixLabors.ImageSharp.Formats.Jpeg;
+using SixLabors.ImageSharp.Formats.Pbm;
using SixLabors.ImageSharp.Formats.Png;
using SixLabors.ImageSharp.Formats.Tga;
using SixLabors.ImageSharp.Formats.Tiff;
@@ -26,10 +27,11 @@ namespace SixLabors.ImageSharp
///
/// A lazily initialized configuration default instance.
///
- private static readonly Lazy Lazy = new Lazy(CreateDefaultInstance);
+ private static readonly Lazy Lazy = new(CreateDefaultInstance);
private const int DefaultStreamProcessingBufferSize = 8096;
private int streamProcessingBufferSize = DefaultStreamProcessingBufferSize;
private int maxDegreeOfParallelism = Environment.ProcessorCount;
+ private MemoryAllocator memoryAllocator = MemoryAllocator.Default;
///
/// Initializes a new instance of the class.
@@ -95,6 +97,14 @@ namespace SixLabors.ImageSharp
}
}
+ ///
+ /// Gets or sets a value indicating whether to force image buffers to be contiguous whenever possible.
+ ///
+ ///
+ /// Contiguous allocations are not possible, if the image needs a buffer larger than .
+ ///
+ public bool PreferContiguousImageBuffers { get; set; }
+
///
/// Gets a set of properties for the Configuration.
///
@@ -112,14 +122,36 @@ namespace SixLabors.ImageSharp
public ReadOrigin ReadOrigin { get; set; } = ReadOrigin.Current;
///
- /// Gets or sets the that is currently in use.
+ /// Gets or the that is currently in use.
///
- public ImageFormatManager ImageFormatsManager { get; set; } = new ImageFormatManager();
+ public ImageFormatManager ImageFormatsManager { get; private set; } = new ImageFormatManager();
///
- /// Gets or sets the that is currently in use.
+ /// Gets or sets the that is currently in use.
+ /// Defaults to .
+ ///
+ /// Allocators are expensive, so it is strongly recommended to use only one busy instance per process.
+ /// In case you need to customize it, you can ensure this by changing
///
- public MemoryAllocator MemoryAllocator { get; set; } = ArrayPoolMemoryAllocator.CreateDefault();
+ ///
+ /// It's possible to reduce allocator footprint by assigning a custom instance created with
+ /// , but note that since the default pooling
+ /// allocators are expensive, it is strictly recommended to use a single process-wide allocator.
+ /// You can ensure this by altering the allocator of , or by implementing custom application logic that
+ /// manages allocator lifetime.
+ ///
+ /// If an allocator has to be dropped for some reason,
+ /// shall be invoked after disposing all associated instances.
+ ///
+ public MemoryAllocator MemoryAllocator
+ {
+ get => this.memoryAllocator;
+ set
+ {
+ Guard.NotNull(value, nameof(this.MemoryAllocator));
+ this.memoryAllocator = value;
+ }
+ }
///
/// Gets the maximum header size of all the formats.
@@ -160,12 +192,12 @@ namespace SixLabors.ImageSharp
/// Creates a shallow copy of the .
///
/// A new configuration instance.
- public Configuration Clone() => new Configuration
+ public Configuration Clone() => new()
{
MaxDegreeOfParallelism = this.MaxDegreeOfParallelism,
StreamProcessingBufferSize = this.StreamProcessingBufferSize,
ImageFormatsManager = this.ImageFormatsManager,
- MemoryAllocator = this.MemoryAllocator,
+ memoryAllocator = this.memoryAllocator,
ImageOperationsProvider = this.ImageOperationsProvider,
ReadOrigin = this.ReadOrigin,
FileSystem = this.FileSystem,
@@ -178,16 +210,18 @@ namespace SixLabors.ImageSharp
///
///
/// .
+ /// .
/// .
/// .
/// .
///
/// The default configuration of .
- internal static Configuration CreateDefaultInstance() => new Configuration(
+ internal static Configuration CreateDefaultInstance() => new(
new PngConfigurationModule(),
new JpegConfigurationModule(),
new GifConfigurationModule(),
new BmpConfigurationModule(),
+ new PbmConfigurationModule(),
new TgaConfigurationModule(),
new TiffConfigurationModule(),
new WebpConfigurationModule());
diff --git a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs
index 8919befcb..41adc1cff 100644
--- a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs
+++ b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs
@@ -306,7 +306,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
int newY = Invert(y, height, inverted);
int rowStartIdx = y * width;
Span bufferRow = bufferSpan.Slice(rowStartIdx, width);
- Span pixelRow = pixels.GetRowSpan(newY);
+ Span pixelRow = pixels.DangerousGetRowSpan(newY);
bool rowHasUndefinedPixels = rowsWithUndefinedPixelsSpan[y];
if (rowHasUndefinedPixels)
@@ -377,7 +377,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
for (int y = 0; y < height; y++)
{
int newY = Invert(y, height, inverted);
- Span pixelRow = pixels.GetRowSpan(newY);
+ Span pixelRow = pixels.DangerousGetRowSpan(newY);
bool rowHasUndefinedPixels = rowsWithUndefinedPixelsSpan[y];
if (rowHasUndefinedPixels)
{
@@ -826,7 +826,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
int newY = Invert(y, height, inverted);
this.stream.Read(rowSpan);
int offset = 0;
- Span pixelRow = pixels.GetRowSpan(newY);
+ Span pixelRow = pixels.DangerousGetRowSpan(newY);
for (int x = 0; x < arrayWidth; x++)
{
@@ -878,7 +878,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
{
this.stream.Read(bufferSpan);
int newY = Invert(y, height, inverted);
- Span pixelRow = pixels.GetRowSpan(newY);
+ Span pixelRow = pixels.DangerousGetRowSpan(newY);
int offset = 0;
for (int x = 0; x < width; x++)
@@ -933,7 +933,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
{
this.stream.Read(rowSpan);
int newY = Invert(y, height, inverted);
- Span pixelSpan = pixels.GetRowSpan(newY);
+ Span pixelSpan = pixels.DangerousGetRowSpan(newY);
PixelOperations.Instance.FromBgr24Bytes(
this.Configuration,
rowSpan,
@@ -961,7 +961,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
{
this.stream.Read(rowSpan);
int newY = Invert(y, height, inverted);
- Span pixelSpan = pixels.GetRowSpan(newY);
+ Span pixelSpan = pixels.DangerousGetRowSpan(newY);
PixelOperations.Instance.FromBgra32Bytes(
this.Configuration,
rowSpan,
@@ -1031,7 +1031,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
this.stream.Read(rowSpan);
int newY = Invert(y, height, inverted);
- Span pixelSpan = pixels.GetRowSpan(newY);
+ Span pixelSpan = pixels.DangerousGetRowSpan(newY);
PixelOperations.Instance.FromBgra32Bytes(
this.Configuration,
@@ -1054,7 +1054,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
width);
int newY = Invert(y, height, inverted);
- Span pixelSpan = pixels.GetRowSpan(newY);
+ Span pixelSpan = pixels.DangerousGetRowSpan(newY);
for (int x = 0; x < width; x++)
{
@@ -1109,7 +1109,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
{
this.stream.Read(bufferSpan);
int newY = Invert(y, height, inverted);
- Span pixelRow = pixels.GetRowSpan(newY);
+ Span pixelRow = pixels.DangerousGetRowSpan(newY);
int offset = 0;
for (int x = 0; x < width; x++)
diff --git a/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs
index c6ca5b09d..6384074df 100644
--- a/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs
+++ b/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs
@@ -274,7 +274,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
for (int y = pixels.Height - 1; y >= 0; y--)
{
- Span pixelSpan = pixels.GetRowSpan(y);
+ Span pixelSpan = pixels.DangerousGetRowSpan(y);
PixelOperations.Instance.ToBgra32Bytes(
this.configuration,
pixelSpan,
@@ -300,7 +300,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
for (int y = pixels.Height - 1; y >= 0; y--)
{
- Span pixelSpan = pixels.GetRowSpan(y);
+ Span pixelSpan = pixels.DangerousGetRowSpan(y);
PixelOperations.Instance.ToBgr24Bytes(
this.configuration,
pixelSpan,
@@ -326,7 +326,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
for (int y = pixels.Height - 1; y >= 0; y--)
{
- Span pixelSpan = pixels.GetRowSpan(y);
+ Span pixelSpan = pixels.DangerousGetRowSpan(y);
PixelOperations.Instance.ToBgra5551Bytes(
this.configuration,
@@ -379,7 +379,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
for (int y = image.Height - 1; y >= 0; y--)
{
- ReadOnlySpan pixelSpan = quantized.GetPixelRowSpan(y);
+ ReadOnlySpan pixelSpan = quantized.DangerousGetRowSpan(y);
stream.Write(pixelSpan);
for (int i = 0; i < this.padding; i++)
@@ -413,10 +413,10 @@ namespace SixLabors.ImageSharp.Formats.Bmp
}
stream.Write(colorPalette);
-
+ Buffer2D imageBuffer = image.PixelBuffer;
for (int y = image.Height - 1; y >= 0; y--)
{
- ReadOnlySpan inputPixelRow = image.GetPixelRowSpan(y);
+ ReadOnlySpan inputPixelRow = imageBuffer.DangerousGetRowSpan(y);
ReadOnlySpan outputPixelRow = MemoryMarshal.AsBytes(inputPixelRow);
stream.Write(outputPixelRow);
@@ -447,11 +447,11 @@ namespace SixLabors.ImageSharp.Formats.Bmp
ReadOnlySpan quantizedColorPalette = quantized.Palette.Span;
this.WriteColorPalette(stream, quantizedColorPalette, colorPalette);
- ReadOnlySpan pixelRowSpan = quantized.GetPixelRowSpan(0);
+ ReadOnlySpan pixelRowSpan = quantized.DangerousGetRowSpan(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);
+ pixelRowSpan = quantized.DangerousGetRowSpan(y);
int endIdx = pixelRowSpan.Length % 2 == 0 ? pixelRowSpan.Length : pixelRowSpan.Length - 1;
for (int i = 0; i < endIdx; i += 2)
@@ -491,11 +491,11 @@ namespace SixLabors.ImageSharp.Formats.Bmp
ReadOnlySpan quantizedColorPalette = quantized.Palette.Span;
this.WriteColorPalette(stream, quantizedColorPalette, colorPalette);
- ReadOnlySpan quantizedPixelRow = quantized.GetPixelRowSpan(0);
+ ReadOnlySpan quantizedPixelRow = quantized.DangerousGetRowSpan(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);
+ quantizedPixelRow = quantized.DangerousGetRowSpan(y);
int endIdx = quantizedPixelRow.Length % 8 == 0 ? quantizedPixelRow.Length : quantizedPixelRow.Length - 8;
for (int i = 0; i < endIdx; i += 8)
diff --git a/src/ImageSharp/Formats/Gif/GifConstants.cs b/src/ImageSharp/Formats/Gif/GifConstants.cs
index 24fd8a936..1179b67b1 100644
--- a/src/ImageSharp/Formats/Gif/GifConstants.cs
+++ b/src/ImageSharp/Formats/Gif/GifConstants.cs
@@ -121,5 +121,16 @@ namespace SixLabors.ImageSharp.Formats.Gif
(byte)'P', (byte)'E',
(byte)'2', (byte)'.', (byte)'0'
};
+
+ ///
+ /// Gets the ASCII encoded application identification bytes.
+ ///
+ internal static ReadOnlySpan XmpApplicationIdentificationBytes => new[]
+ {
+ (byte)'X', (byte)'M', (byte)'P',
+ (byte)' ', (byte)'D', (byte)'a',
+ (byte)'t', (byte)'a',
+ (byte)'X', (byte)'M', (byte)'P'
+ };
}
}
diff --git a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs
index 482a76153..b6348803a 100644
--- a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs
+++ b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs
@@ -11,6 +11,7 @@ using System.Threading;
using SixLabors.ImageSharp.IO;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Metadata;
+using SixLabors.ImageSharp.Metadata.Profiles.Xmp;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Formats.Gif
@@ -250,7 +251,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
}
///
- /// Reads the application extension block parsing any animation information
+ /// Reads the application extension block parsing any animation or XMP information
/// if present.
///
private void ReadApplicationExtension()
@@ -258,25 +259,37 @@ namespace SixLabors.ImageSharp.Formats.Gif
int appLength = this.stream.ReadByte();
// If the length is 11 then it's a valid extension and most likely
- // a NETSCAPE or ANIMEXTS extension. We want the loop count from this.
+ // a NETSCAPE, XMP or ANIMEXTS extension. We want the loop count from this.
if (appLength == GifConstants.ApplicationBlockSize)
{
- this.stream.Skip(appLength);
- int subBlockSize = this.stream.ReadByte();
+ this.stream.Read(this.buffer, 0, GifConstants.ApplicationBlockSize);
+ bool isXmp = this.buffer.AsSpan().StartsWith(GifConstants.XmpApplicationIdentificationBytes);
- // TODO: There's also a NETSCAPE buffer extension.
- // http://www.vurdalakov.net/misc/gif/netscape-buffering-application-extension
- if (subBlockSize == GifConstants.NetscapeLoopingSubBlockSize)
+ if (isXmp)
{
- this.stream.Read(this.buffer, 0, GifConstants.NetscapeLoopingSubBlockSize);
- this.gifMetadata.RepeatCount = GifNetscapeLoopingApplicationExtension.Parse(this.buffer.AsSpan(1)).RepeatCount;
- this.stream.Skip(1); // Skip the terminator.
+ var extension = GifXmpApplicationExtension.Read(this.stream);
+ this.metadata.XmpProfile = new XmpProfile(extension.Data);
return;
}
+ else
+ {
+ int subBlockSize = this.stream.ReadByte();
+
+ // TODO: There's also a NETSCAPE buffer extension.
+ // http://www.vurdalakov.net/misc/gif/netscape-buffering-application-extension
+ if (subBlockSize == GifConstants.NetscapeLoopingSubBlockSize)
+ {
+ this.stream.Read(this.buffer, 0, GifConstants.NetscapeLoopingSubBlockSize);
+ this.gifMetadata.RepeatCount = GifNetscapeLoopingApplicationExtension.Parse(this.buffer.AsSpan(1)).RepeatCount;
+ this.stream.Skip(1); // Skip the terminator.
+ return;
+ }
+
+ // Could be something else not supported yet.
+ // Skip the subblock and terminator.
+ this.SkipBlock(subBlockSize);
+ }
- // Could be XMP or something else not supported yet.
- // Skip the subblock and terminator.
- this.SkipBlock(subBlockSize);
return;
}
@@ -445,7 +458,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
for (int y = descriptorTop; y < descriptorBottom && y < imageHeight; y++)
{
- ref byte indicesRowRef = ref MemoryMarshal.GetReference(indices.GetRowSpan(y - descriptorTop));
+ ref byte indicesRowRef = ref MemoryMarshal.GetReference(indices.DangerousGetRowSpan(y - descriptorTop));
// Check if this image is interlaced.
int writeY; // the target y offset to write to
@@ -481,7 +494,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
writeY = y;
}
- ref TPixel rowRef = ref MemoryMarshal.GetReference(imageFrame.GetPixelRowSpan(writeY));
+ ref TPixel rowRef = ref MemoryMarshal.GetReference(imageFrame.PixelBuffer.DangerousGetRowSpan(writeY));
if (!transFlag)
{
diff --git a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs
index 05ea14e9c..a21b050a8 100644
--- a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs
+++ b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs
@@ -10,6 +10,7 @@ using System.Threading;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Metadata;
+using SixLabors.ImageSharp.Metadata.Profiles.Xmp;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Processors.Quantization;
@@ -121,11 +122,8 @@ namespace SixLabors.ImageSharp.Formats.Gif
// Write the comments.
this.WriteComments(gifMetadata, stream);
- // Write application extension to allow additional frames.
- if (image.Frames.Count > 1)
- {
- this.WriteApplicationExtension(stream, gifMetadata.RepeatCount);
- }
+ // Write application extensions.
+ this.WriteApplicationExtensions(stream, image.Frames.Count, gifMetadata.RepeatCount, metadata.XmpProfile);
if (useGlobalTable)
{
@@ -326,15 +324,24 @@ namespace SixLabors.ImageSharp.Formats.Gif
/// Writes the application extension to the stream.
///
/// The stream to write to.
+ /// The frame count fo this image.
/// The animated image repeat count.
- private void WriteApplicationExtension(Stream stream, ushort repeatCount)
+ /// The XMP metadata profile. Null if profile is not to be written.
+ private void WriteApplicationExtensions(Stream stream, int frameCount, ushort repeatCount, XmpProfile xmpProfile)
{
- // Application Extension Header
- if (repeatCount != 1)
+ // Application Extension: Loop repeat count.
+ if (frameCount > 1 && repeatCount != 1)
{
var loopingExtension = new GifNetscapeLoopingApplicationExtension(repeatCount);
this.WriteExtension(loopingExtension, stream);
}
+
+ // Application Extension: XMP Profile.
+ if (xmpProfile != null)
+ {
+ var xmpExtension = new GifXmpApplicationExtension(xmpProfile.Data);
+ this.WriteExtension(xmpExtension, stream);
+ }
}
///
@@ -420,14 +427,28 @@ namespace SixLabors.ImageSharp.Formats.Gif
private void WriteExtension(TGifExtension extension, Stream stream)
where TGifExtension : struct, IGifExtension
{
- this.buffer[0] = GifConstants.ExtensionIntroducer;
- this.buffer[1] = extension.Label;
+ IMemoryOwner owner = null;
+ Span buffer;
+ int extensionSize = extension.ContentLength;
+ if (extensionSize > this.buffer.Length - 3)
+ {
+ owner = this.memoryAllocator.Allocate(extensionSize + 3);
+ buffer = owner.GetSpan();
+ }
+ else
+ {
+ buffer = this.buffer;
+ }
+
+ buffer[0] = GifConstants.ExtensionIntroducer;
+ buffer[1] = extension.Label;
- int extensionSize = extension.WriteTo(this.buffer.AsSpan(2));
+ extension.WriteTo(buffer.Slice(2));
- this.buffer[extensionSize + 2] = GifConstants.Terminator;
+ buffer[extensionSize + 2] = GifConstants.Terminator;
- stream.Write(this.buffer, 0, extensionSize + 3);
+ stream.Write(buffer, 0, extensionSize + 3);
+ owner?.Dispose();
}
///
diff --git a/src/ImageSharp/Formats/Gif/LzwDecoder.cs b/src/ImageSharp/Formats/Gif/LzwDecoder.cs
index 9eaa55566..68227db53 100644
--- a/src/ImageSharp/Formats/Gif/LzwDecoder.cs
+++ b/src/ImageSharp/Formats/Gif/LzwDecoder.cs
@@ -115,14 +115,14 @@ namespace SixLabors.ImageSharp.Formats.Gif
int y = 0;
int x = 0;
int rowMax = width;
- ref byte pixelsRowRef = ref MemoryMarshal.GetReference(pixels.GetRowSpan(y));
+ ref byte pixelsRowRef = ref MemoryMarshal.GetReference(pixels.DangerousGetRowSpan(y));
while (xyz < length)
{
// Reset row reference.
if (xyz == rowMax)
{
x = 0;
- pixelsRowRef = ref MemoryMarshal.GetReference(pixels.GetRowSpan(++y));
+ pixelsRowRef = ref MemoryMarshal.GetReference(pixels.DangerousGetRowSpan(++y));
rowMax = (y * width) + width;
}
diff --git a/src/ImageSharp/Formats/Gif/LzwEncoder.cs b/src/ImageSharp/Formats/Gif/LzwEncoder.cs
index e9fb7ab00..c52e34f96 100644
--- a/src/ImageSharp/Formats/Gif/LzwEncoder.cs
+++ b/src/ImageSharp/Formats/Gif/LzwEncoder.cs
@@ -275,7 +275,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
for (int y = 0; y < indexedPixels.Height; y++)
{
- ref byte rowSpanRef = ref MemoryMarshal.GetReference(indexedPixels.GetRowSpan(y));
+ ref byte rowSpanRef = ref MemoryMarshal.GetReference(indexedPixels.DangerousGetRowSpan(y));
int offsetX = y == 0 ? 1 : 0;
for (int x = offsetX; x < indexedPixels.Width; x++)
diff --git a/src/ImageSharp/Formats/Gif/Sections/GifGraphicControlExtension.cs b/src/ImageSharp/Formats/Gif/Sections/GifGraphicControlExtension.cs
index ee5a43d80..801849c9b 100644
--- a/src/ImageSharp/Formats/Gif/Sections/GifGraphicControlExtension.cs
+++ b/src/ImageSharp/Formats/Gif/Sections/GifGraphicControlExtension.cs
@@ -1,4 +1,4 @@
-// Copyright (c) Six Labors.
+// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
using System;
@@ -63,6 +63,8 @@ namespace SixLabors.ImageSharp.Formats.Gif
byte IGifExtension.Label => GifConstants.GraphicControlLabel;
+ int IGifExtension.ContentLength => 5;
+
public int WriteTo(Span buffer)
{
ref GifGraphicControlExtension dest = ref Unsafe.As(ref MemoryMarshal.GetReference(buffer));
diff --git a/src/ImageSharp/Formats/Gif/Sections/GifNetscapeLoopingApplicationExtension.cs b/src/ImageSharp/Formats/Gif/Sections/GifNetscapeLoopingApplicationExtension.cs
index 26faa8925..2c7bed611 100644
--- a/src/ImageSharp/Formats/Gif/Sections/GifNetscapeLoopingApplicationExtension.cs
+++ b/src/ImageSharp/Formats/Gif/Sections/GifNetscapeLoopingApplicationExtension.cs
@@ -12,6 +12,8 @@ namespace SixLabors.ImageSharp.Formats.Gif
public byte Label => GifConstants.ApplicationExtensionLabel;
+ public int ContentLength => 16;
+
///
/// Gets the repeat count.
/// 0 means loop indefinitely. Count is set as play n + 1 times.
diff --git a/src/ImageSharp/Formats/Gif/Sections/GifXmpApplicationExtension.cs b/src/ImageSharp/Formats/Gif/Sections/GifXmpApplicationExtension.cs
new file mode 100644
index 000000000..236508fe9
--- /dev/null
+++ b/src/ImageSharp/Formats/Gif/Sections/GifXmpApplicationExtension.cs
@@ -0,0 +1,97 @@
+// Copyright (c) Six Labors.
+// Licensed under the Apache License, Version 2.0.
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using SixLabors.ImageSharp.Metadata.Profiles.Xmp;
+
+namespace SixLabors.ImageSharp.Formats.Gif
+{
+ internal readonly struct GifXmpApplicationExtension : IGifExtension
+ {
+ public GifXmpApplicationExtension(byte[] data) => this.Data = data;
+
+ public byte Label => GifConstants.ApplicationExtensionLabel;
+
+ public int ContentLength => this.Data.Length + 269; // 12 + Data Length + 1 + 256
+
+ ///
+ /// Gets the raw Data.
+ ///
+ public byte[] Data { get; }
+
+ ///
+ /// Reads the XMP metadata from the specified stream.
+ ///
+ /// The stream to read from.
+ /// The XMP metadata
+ /// Thrown if the XMP block is not properly terminated.
+ public static GifXmpApplicationExtension Read(Stream stream)
+ {
+ // Read data in blocks, until an \0 character is encountered.
+ // We overshoot, indicated by the terminatorIndex variable.
+ const int bufferSize = 256;
+ var list = new List();
+ int terminationIndex = -1;
+ while (terminationIndex < 0)
+ {
+ byte[] temp = new byte[bufferSize];
+ int bytesRead = stream.Read(temp);
+ list.Add(temp);
+ terminationIndex = Array.IndexOf(temp, (byte)1);
+ }
+
+ // Pack all the blocks (except magic trailer) into one single array again.
+ int dataSize = ((list.Count - 1) * bufferSize) + terminationIndex;
+ byte[] buffer = new byte[dataSize];
+ Span bufferSpan = buffer;
+ int pos = 0;
+ for (int j = 0; j < list.Count - 1; j++)
+ {
+ list[j].CopyTo(bufferSpan.Slice(pos));
+ pos += bufferSize;
+ }
+
+ // Last one only needs the portion until terminationIndex copied over.
+ Span lastBytes = list[list.Count - 1];
+ lastBytes.Slice(0, terminationIndex).CopyTo(bufferSpan.Slice(pos));
+
+ // Skip the remainder of the magic trailer.
+ stream.Skip(258 - (bufferSize - terminationIndex));
+ return new GifXmpApplicationExtension(buffer);
+ }
+
+ public int WriteTo(Span buffer)
+ {
+ int totalSize = this.ContentLength;
+ if (buffer.Length < totalSize)
+ {
+ throw new InsufficientMemoryException("Unable to write XMP metadata to GIF image");
+ }
+
+ int bytesWritten = 0;
+ buffer[bytesWritten++] = GifConstants.ApplicationBlockSize;
+
+ // Write "XMP DataXMP"
+ ReadOnlySpan idBytes = GifConstants.XmpApplicationIdentificationBytes;
+ idBytes.CopyTo(buffer.Slice(bytesWritten));
+ bytesWritten += idBytes.Length;
+
+ // XMP Data itself
+ this.Data.CopyTo(buffer.Slice(bytesWritten));
+ bytesWritten += this.Data.Length;
+
+ // Write the Magic Trailer
+ buffer[bytesWritten++] = 0x01;
+ for (byte i = 255; i > 0; i--)
+ {
+ buffer[bytesWritten++] = i;
+ }
+
+ buffer[bytesWritten++] = 0x00;
+
+ return totalSize;
+ }
+ }
+}
diff --git a/src/ImageSharp/Formats/Gif/Sections/IGifExtension.cs b/src/ImageSharp/Formats/Gif/Sections/IGifExtension.cs
index 5a15a6dfa..d2783fc48 100644
--- a/src/ImageSharp/Formats/Gif/Sections/IGifExtension.cs
+++ b/src/ImageSharp/Formats/Gif/Sections/IGifExtension.cs
@@ -1,4 +1,4 @@
-// Copyright (c) Six Labors.
+// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
using System;
@@ -15,6 +15,11 @@ namespace SixLabors.ImageSharp.Formats.Gif
///
byte Label { get; }
+ ///
+ /// Gets the length of the contents of this extension.
+ ///
+ int ContentLength { get; }
+
///
/// Writes the extension data to the buffer.
///
diff --git a/src/ImageSharp/Formats/ImageExtensions.Save.cs b/src/ImageSharp/Formats/ImageExtensions.Save.cs
index c5237f2bc..84f9d69b7 100644
--- a/src/ImageSharp/Formats/ImageExtensions.Save.cs
+++ b/src/ImageSharp/Formats/ImageExtensions.Save.cs
@@ -10,6 +10,7 @@ using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Formats.Bmp;
using SixLabors.ImageSharp.Formats.Gif;
using SixLabors.ImageSharp.Formats.Jpeg;
+using SixLabors.ImageSharp.Formats.Pbm;
using SixLabors.ImageSharp.Formats.Png;
using SixLabors.ImageSharp.Formats.Tga;
using SixLabors.ImageSharp.Formats.Webp;
@@ -104,7 +105,6 @@ namespace SixLabors.ImageSharp
/// 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 SaveAsBmp(this Image source, Stream stream, BmpEncoder encoder)
=> source.Save(
stream,
@@ -207,7 +207,6 @@ namespace SixLabors.ImageSharp
/// 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 SaveAsGif(this Image source, Stream stream, GifEncoder encoder)
=> source.Save(
stream,
@@ -310,7 +309,6 @@ namespace SixLabors.ImageSharp
/// 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 SaveAsJpeg(this Image source, Stream stream, JpegEncoder encoder)
=> source.Save(
stream,
@@ -331,6 +329,108 @@ namespace SixLabors.ImageSharp
encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(JpegFormat.Instance),
cancellationToken);
+ ///
+ /// Saves the image to the given stream with the Pbm format.
+ ///
+ /// The image this method extends.
+ /// The file path to save the image to.
+ /// Thrown if the path is null.
+ public static void SaveAsPbm(this Image source, string path) => SaveAsPbm(source, path, null);
+
+ ///
+ /// Saves the image to the given stream with the Pbm 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 SaveAsPbmAsync(this Image source, string path) => SaveAsPbmAsync(source, path, null);
+
+ ///
+ /// Saves the image to the given stream with the Pbm 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 SaveAsPbmAsync(this Image source, string path, CancellationToken cancellationToken)
+ => SaveAsPbmAsync(source, path, null, cancellationToken);
+
+ ///
+ /// Saves the image to the given stream with the Pbm 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 SaveAsPbm(this Image source, string path, PbmEncoder encoder) =>
+ source.Save(
+ path,
+ encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(PbmFormat.Instance));
+
+ ///
+ /// Saves the image to the given stream with the Pbm 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 SaveAsPbmAsync(this Image source, string path, PbmEncoder encoder, CancellationToken cancellationToken = default) =>
+ source.SaveAsync(
+ path,
+ encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(PbmFormat.Instance),
+ cancellationToken);
+
+ ///
+ /// Saves the image to the given stream with the Pbm format.
+ ///
+ /// The image this method extends.
+ /// The stream to save the image to.
+ /// Thrown if the stream is null.
+ public static void SaveAsPbm(this Image source, Stream stream)
+ => SaveAsPbm(source, stream, null);
+
+ ///
+ /// Saves the image to the given stream with the Pbm 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 SaveAsPbmAsync(this Image source, Stream stream, CancellationToken cancellationToken = default)
+ => SaveAsPbmAsync(source, stream, null, cancellationToken);
+
+ ///
+ /// Saves the image to the given stream with the Pbm 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.
+ public static void SaveAsPbm(this Image source, Stream stream, PbmEncoder encoder)
+ => source.Save(
+ stream,
+ encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(PbmFormat.Instance));
+
+ ///
+ /// Saves the image to the given stream with the Pbm 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 SaveAsPbmAsync(this Image source, Stream stream, PbmEncoder encoder, CancellationToken cancellationToken = default) =>
+ source.SaveAsync(
+ stream,
+ encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(PbmFormat.Instance),
+ cancellationToken);
+
///
/// Saves the image to the given stream with the Png format.
///
@@ -413,7 +513,6 @@ namespace SixLabors.ImageSharp
/// 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 SaveAsPng(this Image source, Stream stream, PngEncoder encoder)
=> source.Save(
stream,
@@ -516,7 +615,6 @@ namespace SixLabors.ImageSharp
/// 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 SaveAsTga(this Image source, Stream stream, TgaEncoder encoder)
=> source.Save(
stream,
@@ -619,7 +717,6 @@ namespace SixLabors.ImageSharp
/// 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,
@@ -722,7 +819,6 @@ namespace SixLabors.ImageSharp
/// 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,
diff --git a/src/ImageSharp/Formats/ImageExtensions.Save.tt b/src/ImageSharp/Formats/ImageExtensions.Save.tt
index 874f3ab0d..ae7648522 100644
--- a/src/ImageSharp/Formats/ImageExtensions.Save.tt
+++ b/src/ImageSharp/Formats/ImageExtensions.Save.tt
@@ -15,6 +15,7 @@ using SixLabors.ImageSharp.Advanced;
"Bmp",
"Gif",
"Jpeg",
+ "Pbm",
"Png",
"Tga",
"Webp",
@@ -123,7 +124,6 @@ namespace SixLabors.ImageSharp
/// 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 SaveAs<#= fmt #>(this Image source, Stream stream, <#= fmt #>Encoder encoder)
=> source.Save(
stream,
diff --git a/src/ImageSharp/Formats/ImageFormatManager.cs b/src/ImageSharp/Formats/ImageFormatManager.cs
index 2e1874592..f3fde403d 100644
--- a/src/ImageSharp/Formats/ImageFormatManager.cs
+++ b/src/ImageSharp/Formats/ImageFormatManager.cs
@@ -1,4 +1,4 @@
-// Copyright (c) Six Labors.
+// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
using System;
@@ -17,27 +17,27 @@ namespace SixLabors.ImageSharp.Formats
/// Used for locking against as there is no ConcurrentSet type.
///
///
- private static readonly object HashLock = new object();
+ private static readonly object HashLock = new();
///
/// The list of supported keyed to mime types.
///
- private readonly ConcurrentDictionary mimeTypeEncoders = new ConcurrentDictionary();
+ private readonly ConcurrentDictionary mimeTypeEncoders = new();
///
/// The list of supported keyed to mime types.
///
- private readonly ConcurrentDictionary mimeTypeDecoders = new ConcurrentDictionary();
+ private readonly ConcurrentDictionary mimeTypeDecoders = new();
///
/// The list of supported s.
///
- private readonly HashSet imageFormats = new HashSet();
+ private readonly HashSet imageFormats = new();
///
/// The list of supported s.
///
- private ConcurrentBag imageFormatDetectors = new ConcurrentBag();
+ private ConcurrentBag imageFormatDetectors = new();
///
/// Initializes a new instance of the class.
@@ -113,9 +113,7 @@ namespace SixLabors.ImageSharp.Formats
/// The mime-type to discover
/// The if found; otherwise null
public IImageFormat FindFormatByMimeType(string mimeType)
- {
- return this.imageFormats.FirstOrDefault(x => x.MimeTypes.Contains(mimeType, StringComparer.OrdinalIgnoreCase));
- }
+ => this.imageFormats.FirstOrDefault(x => x.MimeTypes.Contains(mimeType, StringComparer.OrdinalIgnoreCase));
///
/// Sets a specific image encoder as the encoder for a specific image format.
@@ -146,10 +144,7 @@ namespace SixLabors.ImageSharp.Formats
///
/// Removes all the registered image format detectors.
///
- public void ClearImageFormatDetectors()
- {
- this.imageFormatDetectors = new ConcurrentBag();
- }
+ public void ClearImageFormatDetectors() => this.imageFormatDetectors = new();
///
/// Adds a new detector for detecting mime types.
@@ -193,9 +188,6 @@ namespace SixLabors.ImageSharp.Formats
///
/// Sets the max header size.
///
- private void SetMaxHeaderSize()
- {
- this.MaxHeaderSize = this.imageFormatDetectors.Max(x => x.HeaderSize);
- }
+ private void SetMaxHeaderSize() => this.MaxHeaderSize = this.imageFormatDetectors.Max(x => x.HeaderSize);
}
}
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Block8x8.Intrinsic.cs b/src/ImageSharp/Formats/Jpeg/Components/Block8x8.Intrinsic.cs
new file mode 100644
index 000000000..002d382dc
--- /dev/null
+++ b/src/ImageSharp/Formats/Jpeg/Components/Block8x8.Intrinsic.cs
@@ -0,0 +1,39 @@
+// Copyright (c) Six Labors.
+// Licensed under the Apache License, Version 2.0.
+
+#if SUPPORTS_RUNTIME_INTRINSICS
+using System.Runtime.InteropServices;
+using System.Runtime.Intrinsics;
+
+namespace SixLabors.ImageSharp.Formats.Jpeg.Components
+{
+ internal unsafe partial struct Block8x8
+ {
+ [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
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Block8x8.cs b/src/ImageSharp/Formats/Jpeg/Components/Block8x8.cs
index 9d49b8c45..4b03f9f7b 100644
--- a/src/ImageSharp/Formats/Jpeg/Components/Block8x8.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Block8x8.cs
@@ -18,7 +18,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
///
// ReSharper disable once InconsistentNaming
[StructLayout(LayoutKind.Explicit)]
- internal unsafe struct Block8x8 : IEquatable
+ internal unsafe partial struct Block8x8
{
///
/// A number of scalar coefficients in a
@@ -36,34 +36,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
private fixed short data[Size];
#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
///
@@ -102,74 +74,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
set => this[(y * 8) + x] = value;
}
- public static bool operator ==(Block8x8 left, Block8x8 right) => left.Equals(right);
-
- public static bool operator !=(Block8x8 left, Block8x8 right) => !left.Equals(right);
-
- ///
- /// Multiply all elements by a given
- ///
- public static Block8x8 operator *(Block8x8 block, int value)
- {
- Block8x8 result = block;
- for (int i = 0; i < Size; i++)
- {
- int val = result[i];
- val *= value;
- result[i] = (short)val;
- }
-
- return result;
- }
-
- ///
- /// Divide all elements by a given
- ///
- public static Block8x8 operator /(Block8x8 block, int value)
- {
- Block8x8 result = block;
- for (int i = 0; i < Size; i++)
- {
- int val = result[i];
- val /= value;
- result[i] = (short)val;
- }
-
- return result;
- }
-
- ///
- /// Add an to all elements
- ///
- public static Block8x8 operator +(Block8x8 block, int value)
- {
- Block8x8 result = block;
- for (int i = 0; i < Size; i++)
- {
- int val = result[i];
- val += value;
- result[i] = (short)val;
- }
-
- return result;
- }
-
- ///
- /// Subtract an from all elements
- ///
- public static Block8x8 operator -(Block8x8 block, int value)
- {
- Block8x8 result = block;
- for (int i = 0; i < Size; i++)
- {
- int val = result[i];
- val -= value;
- result[i] = (short)val;
- }
-
- return result;
- }
-
public static Block8x8 Load(Span data)
{
Unsafe.SkipInit(out Block8x8 result);
@@ -260,26 +164,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
return sb.ToString();
}
- ///
- public bool Equals(Block8x8 other)
- {
- for (int i = 0; i < Size; i++)
- {
- if (this[i] != other[i])
- {
- return false;
- }
- }
-
- return true;
- }
-
- ///
- public override bool Equals(object obj) => obj is Block8x8 other && this.Equals(other);
-
- ///
- public override int GetHashCode() => (this[0] * 31) + this[1];
-
///
/// Returns index of the last non-zero element in given matrix.
///
@@ -337,6 +221,64 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
}
}
+ ///
+ /// Transpose the block inplace.
+ ///
+ [MethodImpl(InliningOptions.ShortMethod)]
+ public void TransposeInplace()
+ {
+ ref short elemRef = ref Unsafe.As(ref this);
+
+ // row #0
+ Swap(ref Unsafe.Add(ref elemRef, 1), ref Unsafe.Add(ref elemRef, 8));
+ Swap(ref Unsafe.Add(ref elemRef, 2), ref Unsafe.Add(ref elemRef, 16));
+ Swap(ref Unsafe.Add(ref elemRef, 3), ref Unsafe.Add(ref elemRef, 24));
+ Swap(ref Unsafe.Add(ref elemRef, 4), ref Unsafe.Add(ref elemRef, 32));
+ Swap(ref Unsafe.Add(ref elemRef, 5), ref Unsafe.Add(ref elemRef, 40));
+ Swap(ref Unsafe.Add(ref elemRef, 6), ref Unsafe.Add(ref elemRef, 48));
+ Swap(ref Unsafe.Add(ref elemRef, 7), ref Unsafe.Add(ref elemRef, 56));
+
+ // row #1
+ Swap(ref Unsafe.Add(ref elemRef, 10), ref Unsafe.Add(ref elemRef, 17));
+ Swap(ref Unsafe.Add(ref elemRef, 11), ref Unsafe.Add(ref elemRef, 25));
+ Swap(ref Unsafe.Add(ref elemRef, 12), ref Unsafe.Add(ref elemRef, 33));
+ Swap(ref Unsafe.Add(ref elemRef, 13), ref Unsafe.Add(ref elemRef, 41));
+ Swap(ref Unsafe.Add(ref elemRef, 14), ref Unsafe.Add(ref elemRef, 49));
+ Swap(ref Unsafe.Add(ref elemRef, 15), ref Unsafe.Add(ref elemRef, 57));
+
+ // row #2
+ Swap(ref Unsafe.Add(ref elemRef, 19), ref Unsafe.Add(ref elemRef, 26));
+ Swap(ref Unsafe.Add(ref elemRef, 20), ref Unsafe.Add(ref elemRef, 34));
+ Swap(ref Unsafe.Add(ref elemRef, 21), ref Unsafe.Add(ref elemRef, 42));
+ Swap(ref Unsafe.Add(ref elemRef, 22), ref Unsafe.Add(ref elemRef, 50));
+ Swap(ref Unsafe.Add(ref elemRef, 23), ref Unsafe.Add(ref elemRef, 58));
+
+ // row #3
+ Swap(ref Unsafe.Add(ref elemRef, 28), ref Unsafe.Add(ref elemRef, 35));
+ Swap(ref Unsafe.Add(ref elemRef, 29), ref Unsafe.Add(ref elemRef, 43));
+ Swap(ref Unsafe.Add(ref elemRef, 30), ref Unsafe.Add(ref elemRef, 51));
+ Swap(ref Unsafe.Add(ref elemRef, 31), ref Unsafe.Add(ref elemRef, 59));
+
+ // row #4
+ Swap(ref Unsafe.Add(ref elemRef, 37), ref Unsafe.Add(ref elemRef, 44));
+ Swap(ref Unsafe.Add(ref elemRef, 38), ref Unsafe.Add(ref elemRef, 52));
+ Swap(ref Unsafe.Add(ref elemRef, 39), ref Unsafe.Add(ref elemRef, 60));
+
+ // row #5
+ Swap(ref Unsafe.Add(ref elemRef, 46), ref Unsafe.Add(ref elemRef, 53));
+ Swap(ref Unsafe.Add(ref elemRef, 47), ref Unsafe.Add(ref elemRef, 61));
+
+ // row #6
+ Swap(ref Unsafe.Add(ref elemRef, 55), ref Unsafe.Add(ref elemRef, 62));
+
+ static void Swap(ref short a, ref short b)
+ {
+ short tmp = a;
+ a = b;
+ b = tmp;
+ }
+ }
+
///
/// Calculate the total sum of absolute differences of elements in 'a' and 'b'.
///
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs
index 02f5a1324..f25286447 100644
--- a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs
@@ -2,7 +2,6 @@
// Licensed under the Apache License, Version 2.0.
using System;
-using System.Diagnostics;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
@@ -98,58 +97,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
set => this[(y * 8) + x] = value;
}
- public static Block8x8F operator *(Block8x8F block, float value)
- {
- Block8x8F result = block;
- for (int i = 0; i < Size; i++)
- {
- float val = result[i];
- val *= value;
- result[i] = val;
- }
-
- return result;
- }
-
- public static Block8x8F operator /(Block8x8F block, float value)
- {
- Block8x8F result = block;
- for (int i = 0; i < Size; i++)
- {
- float val = result[i];
- val /= value;
- result[i] = val;
- }
-
- return result;
- }
-
- public static Block8x8F operator +(Block8x8F block, float value)
- {
- Block8x8F result = block;
- for (int i = 0; i < Size; i++)
- {
- float val = result[i];
- val += value;
- result[i] = val;
- }
-
- return result;
- }
-
- public static Block8x8F operator -(Block8x8F block, float value)
- {
- Block8x8F result = block;
- for (int i = 0; i < Size; i++)
- {
- float val = result[i];
- val -= value;
- result[i] = val;
- }
-
- return result;
- }
-
public static Block8x8F Load(Span data)
{
Block8x8F result = default;
@@ -157,13 +104,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
return result;
}
- public static Block8x8F Load(Span data)
- {
- Block8x8F result = default;
- result.LoadFrom(data);
- return result;
- }
-
///
/// Load raw 32bit floating point data from source.
///
@@ -177,15 +117,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
Unsafe.CopyBlock(ref d, ref s, Size * sizeof(float));
}
- ///
- /// Load raw 32bit floating point data from source.
- ///
- /// Block pointer
- /// Source
- [MethodImpl(InliningOptions.ShortMethod)]
- public static unsafe void LoadFrom(Block8x8F* blockPtr, Span source)
- => blockPtr->LoadFrom(source);
-
///
/// Load raw 32bit floating point data from source
///
@@ -202,44 +133,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
}
}
- ///
- /// Copy raw 32bit floating point data to dest,
- ///
- /// Destination
- [MethodImpl(InliningOptions.ShortMethod)]
- public void ScaledCopyTo(Span dest)
- {
- ref byte d = ref Unsafe.As(ref MemoryMarshal.GetReference(dest));
- ref byte s = ref Unsafe.As(ref this);
-
- Unsafe.CopyBlock(ref d, ref s, Size * sizeof(float));
- }
-
- ///
- /// Convert scalars to byte-s and copy to dest,
- ///
- /// Pointer to block
- /// Destination
- [MethodImpl(InliningOptions.ShortMethod)]
- public static unsafe void ScaledCopyTo(Block8x8F* blockPtr, Span dest)
- {
- float* fPtr = (float*)blockPtr;
- for (int i = 0; i < Size; i++)
- {
- dest[i] = (byte)*fPtr;
- fPtr++;
- }
- }
-
- ///
- /// Copy raw 32bit floating point data to dest.
- ///
- /// The block pointer.
- /// The destination.
- [MethodImpl(InliningOptions.ShortMethod)]
- public static unsafe void ScaledCopyTo(Block8x8F* blockPtr, Span dest)
- => blockPtr->ScaledCopyTo(dest);
-
///
/// Copy raw 32bit floating point data to dest
///
@@ -253,22 +146,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
}
}
- ///
- /// Copy raw 32bit floating point data to dest
- ///
- /// Destination
- public unsafe void ScaledCopyTo(Span dest)
- {
- fixed (Vector4* ptr = &this.V0L)
- {
- var fp = (float*)ptr;
- for (int i = 0; i < Size; i++)
- {
- dest[i] = (int)fp[i];
- }
- }
- }
-
public float[] ToArray()
{
float[] result = new float[Size];
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.Avx2JpegColorConverter.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.Avx2JpegColorConverter.cs
deleted file mode 100644
index 90ebce3b8..000000000
--- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.Avx2JpegColorConverter.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright (c) Six Labors.
-// Licensed under the Apache License, Version 2.0.
-
-namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
-{
- internal abstract partial class JpegColorConverter
- {
- internal abstract class Avx2JpegColorConverter : VectorizedJpegColorConverter
- {
- protected Avx2JpegColorConverter(JpegColorSpace colorSpace, int precision)
- : base(colorSpace, precision, 8)
- {
- }
-
- protected sealed override bool IsAvailable => SimdUtils.HasAvx2;
- }
- }
-}
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.BasicJpegColorConverter.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.BasicJpegColorConverter.cs
deleted file mode 100644
index ed2e2cd76..000000000
--- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.BasicJpegColorConverter.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright (c) Six Labors.
-// Licensed under the Apache License, Version 2.0.
-
-namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
-{
- internal abstract partial class JpegColorConverter
- {
- internal abstract class BasicJpegColorConverter : JpegColorConverter
- {
- protected BasicJpegColorConverter(JpegColorSpace colorSpace, int precision)
- : base(colorSpace, precision)
- {
- }
-
- protected override bool IsAvailable => true;
- }
- }
-}
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykAvx.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykAvx.cs
new file mode 100644
index 000000000..7366ee30a
--- /dev/null
+++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykAvx.cs
@@ -0,0 +1,52 @@
+// Copyright (c) Six Labors.
+// Licensed under the Apache License, Version 2.0.
+
+#if SUPPORTS_RUNTIME_INTRINSICS
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Runtime.Intrinsics;
+using System.Runtime.Intrinsics.X86;
+
+namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
+{
+ internal abstract partial class JpegColorConverterBase
+ {
+ internal sealed class FromCmykAvx : JpegColorConverterAvx
+ {
+ public FromCmykAvx(int precision)
+ : base(JpegColorSpace.Cmyk, precision)
+ {
+ }
+
+ public override void ConvertToRgbInplace(in ComponentValues values)
+ {
+ ref Vector256 c0Base =
+ ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component0));
+ ref Vector256 c1Base =
+ ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component1));
+ ref Vector256 c2Base =
+ ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component2));
+ ref Vector256 c3Base =
+ ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component3));
+
+ // Used for the color conversion
+ var scale = Vector256.Create(1 / (this.MaximumValue * this.MaximumValue));
+
+ nint n = values.Component0.Length / Vector256.Count;
+ for (nint i = 0; i < n; i++)
+ {
+ ref Vector256 c = ref Unsafe.Add(ref c0Base, i);
+ ref Vector256 m = ref Unsafe.Add(ref c1Base, i);
+ ref Vector256 y = ref Unsafe.Add(ref c2Base, i);
+ Vector256 k = Unsafe.Add(ref c3Base, i);
+
+ k = Avx.Multiply(k, scale);
+ c = Avx.Multiply(c, k);
+ m = Avx.Multiply(m, k);
+ y = Avx.Multiply(y, k);
+ }
+ }
+ }
+ }
+}
+#endif
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykAvx2.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykAvx2.cs
deleted file mode 100644
index 216c12735..000000000
--- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykAvx2.cs
+++ /dev/null
@@ -1,60 +0,0 @@
-// Copyright (c) Six Labors.
-// Licensed under the Apache License, Version 2.0.
-
-using System;
-using System.Numerics;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-#if SUPPORTS_RUNTIME_INTRINSICS
-using System.Runtime.Intrinsics;
-using System.Runtime.Intrinsics.X86;
-using static SixLabors.ImageSharp.SimdUtils;
-#endif
-
-namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
-{
- internal abstract partial class JpegColorConverter
- {
- internal sealed class FromCmykAvx2 : Avx2JpegColorConverter
- {
- public FromCmykAvx2(int precision)
- : base(JpegColorSpace.Cmyk, precision)
- {
- }
-
- protected override void ConvertCoreVectorizedInplace(in ComponentValues values)
- {
-#if SUPPORTS_RUNTIME_INTRINSICS
- ref Vector256 c0Base =
- ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component0));
- ref Vector256 c1Base =
- ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component1));
- ref Vector256 c2Base =
- ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component2));
- ref Vector256 c3Base =
- ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component3));
-
- // Used for the color conversion
- var scale = Vector256.Create(1 / this.MaximumValue);
-
- nint n = values.Component0.Length / 8;
- for (nint i = 0; i < n; i++)
- {
- ref Vector256 c = ref Unsafe.Add(ref c0Base, i);
- ref Vector256 m = ref Unsafe.Add(ref c1Base, i);
- ref Vector256 y = ref Unsafe.Add(ref c2Base, i);
- Vector256 k = Unsafe.Add(ref c3Base, i);
-
- k = Avx.Multiply(k, scale);
- c = Avx.Multiply(Avx.Multiply(c, k), scale);
- m = Avx.Multiply(Avx.Multiply(m, k), scale);
- y = Avx.Multiply(Avx.Multiply(y, k), scale);
- }
-#endif
- }
-
- protected override void ConvertCoreInplace(in ComponentValues values) =>
- FromCmykBasic.ConvertCoreInplace(values, this.MaximumValue);
- }
- }
-}
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykBasic.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykScalar.cs
similarity index 67%
rename from src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykBasic.cs
rename to src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykScalar.cs
index b0ad50301..68dfa9bfb 100644
--- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykBasic.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykScalar.cs
@@ -1,16 +1,15 @@
-// Copyright (c) Six Labors.
+// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
using System;
-using System.Numerics;
namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
{
- internal abstract partial class JpegColorConverter
+ internal abstract partial class JpegColorConverterBase
{
- internal sealed class FromCmykBasic : BasicJpegColorConverter
+ internal sealed class FromCmykScalar : JpegColorConverterScalar
{
- public FromCmykBasic(int precision)
+ public FromCmykScalar(int precision)
: base(JpegColorSpace.Cmyk, precision)
{
}
@@ -25,17 +24,18 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
Span c2 = values.Component2;
Span c3 = values.Component3;
- float scale = 1 / maxValue;
+ float scale = 1 / (maxValue * maxValue);
for (int i = 0; i < c0.Length; i++)
{
float c = c0[i];
float m = c1[i];
float y = c2[i];
- float k = c3[i] / maxValue;
+ float k = c3[i];
- c0[i] = c * k * scale;
- c1[i] = m * k * scale;
- c2[i] = y * k * scale;
+ k *= scale;
+ c0[i] = c * k;
+ c1[i] = m * k;
+ c2[i] = y * k;
}
}
}
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykVector.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykVector.cs
new file mode 100644
index 000000000..6b7ed169e
--- /dev/null
+++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykVector.cs
@@ -0,0 +1,51 @@
+// Copyright (c) Six Labors.
+// Licensed under the Apache License, Version 2.0.
+
+using System.Numerics;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
+{
+ internal abstract partial class JpegColorConverterBase
+ {
+ internal sealed class FromCmykVector : JpegColorConverterVector
+ {
+ public FromCmykVector(int precision)
+ : base(JpegColorSpace.Cmyk, precision)
+ {
+ }
+
+ protected override void ConvertCoreVectorizedInplace(in ComponentValues values)
+ {
+ ref Vector cBase =
+ ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component0));
+ ref Vector mBase =
+ ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component1));
+ ref Vector yBase =
+ ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component2));
+ ref Vector kBase =
+ ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component3));
+
+ var scale = new Vector(1 / (this.MaximumValue * this.MaximumValue));
+
+ nint n = values.Component0.Length / Vector.Count;
+ for (nint i = 0; i < n; i++)
+ {
+ ref Vector c = ref Unsafe.Add(ref cBase, i);
+ ref Vector m = ref Unsafe.Add(ref mBase, i);
+ ref Vector y = ref Unsafe.Add(ref yBase, i);
+ Vector k = Unsafe.Add(ref kBase, i);
+
+ k *= scale;
+ c *= k;
+ m *= k;
+ y *= k;
+ }
+ }
+
+ protected override void ConvertCoreInplace(in ComponentValues values) =>
+ FromCmykScalar.ConvertCoreInplace(values, this.MaximumValue);
+ }
+ }
+}
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykVector8.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykVector8.cs
deleted file mode 100644
index 0da4c9ec2..000000000
--- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykVector8.cs
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright (c) Six Labors.
-// Licensed under the Apache License, Version 2.0.
-
-using System;
-using System.Numerics;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-using SixLabors.ImageSharp.Tuples;
-
-namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
-{
- internal abstract partial class JpegColorConverter
- {
- internal sealed class FromCmykVector8 : Vector8JpegColorConverter
- {
- public FromCmykVector8(int precision)
- : base(JpegColorSpace.Cmyk, precision)
- {
- }
-
- protected override void ConvertCoreVectorizedInplace(in ComponentValues values)
- {
- ref Vector cBase =
- ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component0));
- ref Vector mBase =
- ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component1));
- ref Vector yBase =
- ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component2));
- ref Vector kBase =
- ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component3));
-
- var scale = new Vector(1 / this.MaximumValue);
-
- // Walking 8 elements at one step:
- nint n = values.Component0.Length / 8;
- for (nint i = 0; i < n; i++)
- {
- ref Vector c = ref Unsafe.Add(ref cBase, i);
- ref Vector m = ref Unsafe.Add(ref mBase, i);
- ref Vector y = ref Unsafe.Add(ref yBase, i);
- Vector k = Unsafe.Add(ref kBase, i) * scale;
-
- c = (c * k) * scale;
- m = (m * k) * scale;
- y = (y * k) * scale;
- }
- }
-
- protected override void ConvertCoreInplace(in ComponentValues values) =>
- FromCmykBasic.ConvertCoreInplace(values, this.MaximumValue);
- }
- }
-}
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleAvx2.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleAvx.cs
similarity index 59%
rename from src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleAvx2.cs
rename to src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleAvx.cs
index eca6b6292..963543ad4 100644
--- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleAvx2.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleAvx.cs
@@ -1,47 +1,39 @@
-// Copyright (c) Six Labors.
+// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
-using System;
-using System.Numerics;
+#if SUPPORTS_RUNTIME_INTRINSICS
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
-#if SUPPORTS_RUNTIME_INTRINSICS
using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.X86;
-using static SixLabors.ImageSharp.SimdUtils;
-#endif
namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
{
- internal abstract partial class JpegColorConverter
+ internal abstract partial class JpegColorConverterBase
{
- internal sealed class FromGrayscaleAvx2 : Avx2JpegColorConverter
+ internal sealed class FromGrayscaleAvx : JpegColorConverterAvx
{
- public FromGrayscaleAvx2(int precision)
+ public FromGrayscaleAvx(int precision)
: base(JpegColorSpace.Grayscale, precision)
{
}
- protected override void ConvertCoreVectorizedInplace(in ComponentValues values)
+ public override void ConvertToRgbInplace(in ComponentValues values)
{
-#if SUPPORTS_RUNTIME_INTRINSICS
ref Vector256 c0Base =
ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component0));
// Used for the color conversion
var scale = Vector256.Create(1 / this.MaximumValue);
- nint n = values.Component0.Length / 8;
+ nint n = values.Component0.Length / Vector256.Count;
for (nint i = 0; i < n; i++)
{
ref Vector256 c0 = ref Unsafe.Add(ref c0Base, i);
c0 = Avx.Multiply(c0, scale);
}
-#endif
}
-
- protected override void ConvertCoreInplace(in ComponentValues values) =>
- FromGrayscaleBasic.ScaleValues(values.Component0, this.MaximumValue);
}
}
}
+#endif
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleBasic.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleBasic.cs
deleted file mode 100644
index 76d57bf06..000000000
--- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleBasic.cs
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright (c) Six Labors.
-// Licensed under the Apache License, Version 2.0.
-
-using System;
-using System.Numerics;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-
-namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
-{
- internal abstract partial class JpegColorConverter
- {
- internal sealed class FromGrayscaleBasic : BasicJpegColorConverter
- {
- public FromGrayscaleBasic(int precision)
- : base(JpegColorSpace.Grayscale, precision)
- {
- }
-
- public override void ConvertToRgbInplace(in ComponentValues values) =>
- ScaleValues(values.Component0, this.MaximumValue);
-
- internal static void ScaleValues(Span values, float maxValue)
- {
- Span vecValues = MemoryMarshal.Cast(values);
-
- var scaleVector = new Vector4(1 / maxValue);
-
- for (int i = 0; i < vecValues.Length; i++)
- {
- vecValues[i] *= scaleVector;
- }
-
- values = values.Slice(vecValues.Length * 4);
- if (!values.IsEmpty)
- {
- float scaleValue = 1f / maxValue;
- values[0] *= scaleValue;
-
- if ((uint)values.Length > 1)
- {
- values[1] *= scaleValue;
-
- if ((uint)values.Length > 2)
- {
- values[2] *= scaleValue;
- }
- }
- }
- }
- }
- }
-}
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleScalar.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleScalar.cs
new file mode 100644
index 000000000..3f6a6caa4
--- /dev/null
+++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleScalar.cs
@@ -0,0 +1,34 @@
+// Copyright (c) Six Labors.
+// Licensed under the Apache License, Version 2.0.
+
+using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
+{
+ internal abstract partial class JpegColorConverterBase
+ {
+ internal sealed class FromGrayscaleScalar : JpegColorConverterScalar
+ {
+ public FromGrayscaleScalar(int precision)
+ : base(JpegColorSpace.Grayscale, precision)
+ {
+ }
+
+ public override void ConvertToRgbInplace(in ComponentValues values) =>
+ ConvertCoreInplace(values.Component0, this.MaximumValue);
+
+ internal static void ConvertCoreInplace(Span values, float maxValue)
+ {
+ ref float valuesRef = ref MemoryMarshal.GetReference(values);
+ float scale = 1 / maxValue;
+
+ for (nint i = 0; i < values.Length; i++)
+ {
+ Unsafe.Add(ref valuesRef, i) *= scale;
+ }
+ }
+ }
+ }
+}
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleVector.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleVector.cs
new file mode 100644
index 000000000..c484aac28
--- /dev/null
+++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleVector.cs
@@ -0,0 +1,38 @@
+// Copyright (c) Six Labors.
+// Licensed under the Apache License, Version 2.0.
+
+using System.Numerics;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
+{
+ internal abstract partial class JpegColorConverterBase
+ {
+ internal sealed class FromGrayScaleVector : JpegColorConverterVector
+ {
+ public FromGrayScaleVector(int precision)
+ : base(JpegColorSpace.Grayscale, precision)
+ {
+ }
+
+ protected override void ConvertCoreVectorizedInplace(in ComponentValues values)
+ {
+ ref Vector cBase =
+ ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component0));
+
+ var scale = new Vector(1 / this.MaximumValue);
+
+ nint n = values.Component0.Length / Vector.Count;
+ for (nint i = 0; i < n; i++)
+ {
+ ref Vector c0 = ref Unsafe.Add(ref cBase, i);
+ c0 *= scale;
+ }
+ }
+
+ protected override void ConvertCoreInplace(in ComponentValues values) =>
+ FromGrayscaleScalar.ConvertCoreInplace(values.Component0, this.MaximumValue);
+ }
+ }
+}
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbAvx2.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbAvx.cs
similarity index 53%
rename from src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbAvx2.cs
rename to src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbAvx.cs
index 557e4e417..f017716e3 100644
--- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbAvx2.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbAvx.cs
@@ -1,40 +1,35 @@
-// Copyright (c) Six Labors.
+// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
-using System;
-using System.Numerics;
+#if SUPPORTS_RUNTIME_INTRINSICS
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
-#if SUPPORTS_RUNTIME_INTRINSICS
using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.X86;
-using static SixLabors.ImageSharp.SimdUtils;
-#endif
namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
{
- internal abstract partial class JpegColorConverter
+ internal abstract partial class JpegColorConverterBase
{
- internal sealed class FromRgbAvx2 : Avx2JpegColorConverter
+ internal sealed class FromRgbAvx : JpegColorConverterAvx
{
- public FromRgbAvx2(int precision)
+ public FromRgbAvx(int precision)
: base(JpegColorSpace.RGB, precision)
{
}
- protected override void ConvertCoreVectorizedInplace(in ComponentValues values)
+ public override void ConvertToRgbInplace(in ComponentValues values)
{
-#if SUPPORTS_RUNTIME_INTRINSICS
ref Vector256 rBase =
- ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component0));
+ ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component0));
ref Vector256 gBase =
- ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component1));
+ ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component1));
ref Vector256 bBase =
- ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component2));
+ ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component2));
// Used for the color conversion
var scale = Vector256.Create(1 / this.MaximumValue);
- nint n = values.Component0.Length / 8;
+ nint n = values.Component0.Length / Vector256.Count;
for (nint i = 0; i < n; i++)
{
ref Vector256 r = ref Unsafe.Add(ref rBase, i);
@@ -44,11 +39,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
g = Avx.Multiply(g, scale);
b = Avx.Multiply(b, scale);
}
-#endif
}
-
- protected override void ConvertCoreInplace(in ComponentValues values) =>
- FromRgbBasic.ConvertCoreInplace(values, this.MaximumValue);
}
}
}
+#endif
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbBasic.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbBasic.cs
deleted file mode 100644
index 1425e7b58..000000000
--- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbBasic.cs
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright (c) Six Labors.
-// Licensed under the Apache License, Version 2.0.
-
-using System;
-using System.Numerics;
-using System.Runtime.InteropServices;
-
-namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
-{
- internal abstract partial class JpegColorConverter
- {
- internal sealed class FromRgbBasic : BasicJpegColorConverter
- {
- public FromRgbBasic(int precision)
- : base(JpegColorSpace.RGB, precision)
- {
- }
-
- public override void ConvertToRgbInplace(in ComponentValues values)
- {
- ConvertCoreInplace(values, this.MaximumValue);
- }
-
- internal static void ConvertCoreInplace(ComponentValues values, float maxValue)
- {
- FromGrayscaleBasic.ScaleValues(values.Component0, maxValue);
- FromGrayscaleBasic.ScaleValues(values.Component1, maxValue);
- FromGrayscaleBasic.ScaleValues(values.Component2, maxValue);
- }
- }
- }
-}
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbScalar.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbScalar.cs
new file mode 100644
index 000000000..24c59206d
--- /dev/null
+++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbScalar.cs
@@ -0,0 +1,26 @@
+// Copyright (c) Six Labors.
+// Licensed under the Apache License, Version 2.0.
+
+namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
+{
+ internal abstract partial class JpegColorConverterBase
+ {
+ internal sealed class FromRgbScalar : JpegColorConverterScalar
+ {
+ public FromRgbScalar(int precision)
+ : base(JpegColorSpace.RGB, precision)
+ {
+ }
+
+ public override void ConvertToRgbInplace(in ComponentValues values) =>
+ ConvertCoreInplace(values, this.MaximumValue);
+
+ internal static void ConvertCoreInplace(ComponentValues values, float maxValue)
+ {
+ FromGrayscaleScalar.ConvertCoreInplace(values.Component0, maxValue);
+ FromGrayscaleScalar.ConvertCoreInplace(values.Component1, maxValue);
+ FromGrayscaleScalar.ConvertCoreInplace(values.Component2, maxValue);
+ }
+ }
+ }
+}
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbVector8.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbVector.cs
similarity index 76%
rename from src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbVector8.cs
rename to src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbVector.cs
index a00361d97..ff3a2bee1 100644
--- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbVector8.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbVector.cs
@@ -1,19 +1,17 @@
-// Copyright (c) Six Labors.
+// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
-using System;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
-using SixLabors.ImageSharp.Tuples;
namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
{
- internal abstract partial class JpegColorConverter
+ internal abstract partial class JpegColorConverterBase
{
- internal sealed class FromRgbVector8 : Vector8JpegColorConverter
+ internal sealed class FromRgbVector : JpegColorConverterVector
{
- public FromRgbVector8(int precision)
+ public FromRgbVector(int precision)
: base(JpegColorSpace.RGB, precision)
{
}
@@ -29,8 +27,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
var scale = new Vector(1 / this.MaximumValue);
- // Walking 8 elements at one step:
- nint n = values.Component0.Length / 8;
+ nint n = values.Component0.Length / Vector.Count;
for (nint i = 0; i < n; i++)
{
ref Vector r = ref Unsafe.Add(ref rBase, i);
@@ -43,7 +40,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
}
protected override void ConvertCoreInplace(in ComponentValues values) =>
- FromRgbBasic.ConvertCoreInplace(values, this.MaximumValue);
+ FromRgbScalar.ConvertCoreInplace(values, this.MaximumValue);
}
}
}
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrAvx2.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrAvx.cs
similarity index 70%
rename from src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrAvx2.cs
rename to src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrAvx.cs
index 5aae1faa2..892bcc79e 100644
--- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrAvx2.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrAvx.cs
@@ -1,31 +1,27 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
-using System;
-using System.Numerics;
+#if SUPPORTS_RUNTIME_INTRINSICS
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
-#if SUPPORTS_RUNTIME_INTRINSICS
using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.X86;
using static SixLabors.ImageSharp.SimdUtils;
-#endif
// ReSharper disable ImpureMethodCallOnReadonlyValueField
namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
{
- internal abstract partial class JpegColorConverter
+ internal abstract partial class JpegColorConverterBase
{
- internal sealed class FromYCbCrAvx2 : Avx2JpegColorConverter
+ internal sealed class FromYCbCrAvx : JpegColorConverterAvx
{
- public FromYCbCrAvx2(int precision)
+ public FromYCbCrAvx(int precision)
: base(JpegColorSpace.YCbCr, precision)
{
}
- protected override void ConvertCoreVectorizedInplace(in ComponentValues values)
+ public override void ConvertToRgbInplace(in ComponentValues values)
{
-#if SUPPORTS_RUNTIME_INTRINSICS
ref Vector256