diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml
index 4828f4f21..5189f0435 100644
--- a/.github/workflows/build-and-test.yml
+++ b/.github/workflows/build-and-test.yml
@@ -1,19 +1,37 @@
name: Build
on:
- push:
- branches:
- - master
- tags:
- - "v*"
- pull_request:
- branches:
- - master
+ push:
+ branches:
+ - master
+ tags:
+ - "v*"
+ pull_request:
+ branches:
+ - master
jobs:
Build:
strategy:
matrix:
options:
+ - os: ubuntu-latest
+ framework: net6.0
+ sdk: 6.0.x
+ sdk-preview: true
+ runtime: -x64
+ codecov: false
+ - os: macos-latest
+ framework: net6.0
+ sdk: 6.0.x
+ sdk-preview: true
+ runtime: -x64
+ codecov: false
+ - os: windows-latest
+ framework: net6.0
+ sdk: 6.0.x
+ sdk-preview: true
+ runtime: -x64
+ codecov: false
- os: ubuntu-latest
framework: net5.0
runtime: -x64
@@ -52,37 +70,38 @@ jobs:
codecov: false
runs-on: ${{matrix.options.os}}
- if: "!contains(github.event.head_commit.message, '[skip ci]')"
steps:
- - uses: actions/checkout@v2
+ - name: Git Config
+ shell: bash
+ run: |
+ git config --global core.autocrlf false
+ git config --global core.longpaths true
+
+ - name: Git Checkout
+ uses: actions/checkout@v2
+ with:
+ fetch-depth: 0
+ submodules: recursive
# See https://github.com/actions/checkout/issues/165#issuecomment-657673315
- - name: Create LFS file list
+ - name: Git Create LFS FileList
run: git lfs ls-files -l | cut -d' ' -f1 | sort > .lfs-assets-id
- - name: Restore LFS cache
+ - name: Git Setup LFS Cache
uses: actions/cache@v2
id: lfs-cache
with:
path: .git/lfs
key: ${{ runner.os }}-lfs-${{ hashFiles('.lfs-assets-id') }}-v1
- - name: Git LFS Pull
+ - name: Git Pull LFS
run: git lfs pull
- - name: Install NuGet
+ - name: NuGet Install
uses: NuGet/setup-nuget@v1
- - name: Setup Git
- shell: bash
- run: |
- git config --global core.autocrlf false
- git config --global core.longpaths true
- git fetch --prune --unshallow
- git submodule -q update --init --recursive
-
- - name: Setup NuGet Cache
+ - name: NuGet Setup Cache
uses: actions/cache@v2
id: nuget-cache
with:
@@ -90,60 +109,94 @@ jobs:
key: ${{ runner.os }}-nuget-${{ hashFiles('**/*.csproj', '**/*.props', '**/*.targets') }}
restore-keys: ${{ runner.os }}-nuget-
- - name: Build
+ - name: DotNet Setup Preview
+ if: ${{ matrix.options.sdk-preview == true }}
+ uses: actions/setup-dotnet@v1
+ with:
+ dotnet-version: ${{ matrix.options.sdk }}
+ include-prerelease: true
+
+ - name: DotNet Build
+ if: ${{ matrix.options.sdk-preview != true }}
shell: pwsh
run: ./ci-build.ps1 "${{matrix.options.framework}}"
env:
SIXLABORS_TESTING: True
- - name: Test
+ - name: DotNet Build Preview
+ if: ${{ matrix.options.sdk-preview == true }}
+ shell: pwsh
+ run: ./ci-build.ps1 "${{matrix.options.framework}}"
+ env:
+ SIXLABORS_TESTING_PREVIEW: True
+
+ - name: DotNet Test
+ if: ${{ matrix.options.sdk-preview != true }}
shell: pwsh
run: ./ci-test.ps1 "${{matrix.options.os}}" "${{matrix.options.framework}}" "${{matrix.options.runtime}}" "${{matrix.options.codecov}}"
env:
- SIXLABORS_TESTING: True
- XUNIT_PATH: .\tests\ImageSharp.Tests # Required for xunit
+ SIXLABORS_TESTING: True
+ XUNIT_PATH: .\tests\ImageSharp.Tests # Required for xunit
+
+ - name: DotNet Test Preview
+ if: ${{ matrix.options.sdk-preview == true }}
+ shell: pwsh
+ run: ./ci-test.ps1 "${{matrix.options.os}}" "${{matrix.options.framework}}" "${{matrix.options.runtime}}" "${{matrix.options.codecov}}"
+ env:
+ SIXLABORS_TESTING_PREVIEW: True
+ XUNIT_PATH: .\tests\ImageSharp.Tests # Required for xunit
- name: Export Failed Output
uses: actions/upload-artifact@v2
if: failure()
with:
- name: actual_output_${{ runner.os }}_${{ matrix.options.framework }}${{ matrix.options.runtime }}.zip
- path: tests/Images/ActualOutput/
+ name: actual_output_${{ runner.os }}_${{ matrix.options.framework }}${{ matrix.options.runtime }}.zip
+ path: tests/Images/ActualOutput/
- - name: Update Codecov
+ - name: Codecov Update
uses: codecov/codecov-action@v1
if: matrix.options.codecov == true && startsWith(github.repository, 'SixLabors')
with:
- flags: unittests
+ flags: unittests
Publish:
needs: [Build]
- runs-on: windows-latest
+ runs-on: ubuntu-latest
if: (github.event_name == 'push')
steps:
- - uses: actions/checkout@v2
-
- - name: Install NuGet
- uses: NuGet/setup-nuget@v1
-
- - name: Setup Git
+ - name: Git Config
shell: bash
run: |
git config --global core.autocrlf false
git config --global core.longpaths true
- git fetch --prune --unshallow
- git submodule -q update --init --recursive
- - name: Pack
+ - name: Git Checkout
+ uses: actions/checkout@v2
+ with:
+ fetch-depth: 0
+ submodules: recursive
+
+ - name: NuGet Install
+ uses: NuGet/setup-nuget@v1
+
+ - name: NuGet Setup Cache
+ uses: actions/cache@v2
+ id: nuget-cache
+ with:
+ path: ~/.nuget
+ key: ${{ runner.os }}-nuget-${{ hashFiles('**/*.csproj', '**/*.props', '**/*.targets') }}
+ restore-keys: ${{ runner.os }}-nuget-
+
+ - name: DotNet Pack
shell: pwsh
run: ./ci-pack.ps1
- - name: Publish to MyGet
+ - name: MyGet Publish
shell: pwsh
run: |
- nuget.exe push .\artifacts\*.nupkg ${{secrets.MYGET_TOKEN}} -Source https://www.myget.org/F/sixlabors/api/v2/package
- nuget.exe push .\artifacts\*.snupkg ${{secrets.MYGET_TOKEN}} -Source https://www.myget.org/F/sixlabors/api/v3/index.json
+ dotnet nuget push .\artifacts\*.nupkg -k ${{secrets.MYGET_TOKEN}} -s https://www.myget.org/F/sixlabors/api/v2/package
+ dotnet nuget push .\artifacts\*.snupkg -k ${{secrets.MYGET_TOKEN}} -s https://www.myget.org/F/sixlabors/api/v3/index.json
# TODO: If github.ref starts with 'refs/tags' then it was tag push and we can optionally push out package to nuget.org
diff --git a/.gitignore b/.gitignore
index 769a40c6c..fadf36964 100644
--- a/.gitignore
+++ b/.gitignore
@@ -223,3 +223,7 @@ artifacts/
**/Images/ReferenceOutput
**/Images/Input/MemoryStress
.DS_Store
+
+#lfs
+hooks/**
+lfs/**
diff --git a/Directory.Build.props b/Directory.Build.props
index b3e18e5a5..3899ce939 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -18,6 +18,11 @@
+
+
+ preview
+
+
+ 2.0
+
+
+
+
+ net6.0;net5.0;netcoreapp3.1;netcoreapp2.1;netstandard2.1;netstandard2.0;netstandard1.3;net472
+
+
net5.0;netcoreapp3.1;netcoreapp2.1;netstandard2.1;netstandard2.0;netstandard1.3;net472
diff --git a/src/ImageSharp/Image{TPixel}.cs b/src/ImageSharp/Image{TPixel}.cs
index b43ff0422..2aa9c5394 100644
--- a/src/ImageSharp/Image{TPixel}.cs
+++ b/src/ImageSharp/Image{TPixel}.cs
@@ -87,6 +87,21 @@ namespace SixLabors.ImageSharp
this.frames = new ImageFrameCollection(this, width, height, default(TPixel));
}
+ ///
+ /// Initializes a new instance of the class
+ /// wrapping an external pixel bufferx.
+ ///
+ /// The configuration providing initialization code which allows extending the library.
+ /// Pixel buffer.
+ /// The images metadata.
+ internal Image(
+ Configuration configuration,
+ Buffer2D pixelBuffer,
+ ImageMetadata metadata)
+ : this(configuration, pixelBuffer.FastMemoryGroup, pixelBuffer.Width, pixelBuffer.Height, metadata)
+ {
+ }
+
///
/// Initializes a new instance of the class
/// wrapping an external .
diff --git a/src/ImageSharp/Memory/Allocators/IManagedByteBuffer.cs b/src/ImageSharp/Memory/Allocators/IManagedByteBuffer.cs
index 8088a2c47..b8298edcd 100644
--- a/src/ImageSharp/Memory/Allocators/IManagedByteBuffer.cs
+++ b/src/ImageSharp/Memory/Allocators/IManagedByteBuffer.cs
@@ -15,4 +15,4 @@ namespace SixLabors.ImageSharp.Memory
///
byte[] Array { get; }
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Memory/Allocators/Internals/BasicArrayBuffer.cs b/src/ImageSharp/Memory/Allocators/Internals/BasicArrayBuffer.cs
index 3a3c695b2..d70811600 100644
--- a/src/ImageSharp/Memory/Allocators/Internals/BasicArrayBuffer.cs
+++ b/src/ImageSharp/Memory/Allocators/Internals/BasicArrayBuffer.cs
@@ -57,4 +57,4 @@ namespace SixLabors.ImageSharp.Memory.Internals
return this.Array;
}
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Memory/Allocators/Internals/BasicByteBuffer.cs b/src/ImageSharp/Memory/Allocators/Internals/BasicByteBuffer.cs
index 499a9228c..e21592a12 100644
--- a/src/ImageSharp/Memory/Allocators/Internals/BasicByteBuffer.cs
+++ b/src/ImageSharp/Memory/Allocators/Internals/BasicByteBuffer.cs
@@ -17,4 +17,4 @@ namespace SixLabors.ImageSharp.Memory.Internals
{
}
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Memory/Allocators/Internals/ManagedBufferBase.cs b/src/ImageSharp/Memory/Allocators/Internals/ManagedBufferBase.cs
index 3f54e335e..296a8bd3a 100644
--- a/src/ImageSharp/Memory/Allocators/Internals/ManagedBufferBase.cs
+++ b/src/ImageSharp/Memory/Allocators/Internals/ManagedBufferBase.cs
@@ -24,7 +24,9 @@ namespace SixLabors.ImageSharp.Memory.Internals
}
void* ptr = (void*)this.pinHandle.AddrOfPinnedObject();
- return new MemoryHandle(ptr, this.pinHandle);
+
+ // We should only pass pinnable:this, when GCHandle lifetime is managed by the MemoryManager instance.
+ return new MemoryHandle(ptr, pinnable: this);
}
///
@@ -42,4 +44,4 @@ namespace SixLabors.ImageSharp.Memory.Internals
/// The pinnable .
protected abstract object GetPinnableObject();
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Memory/Buffer2D{T}.cs b/src/ImageSharp/Memory/Buffer2D{T}.cs
index 21c19f5d5..b62c9beb5 100644
--- a/src/ImageSharp/Memory/Buffer2D{T}.cs
+++ b/src/ImageSharp/Memory/Buffer2D{T}.cs
@@ -116,6 +116,36 @@ namespace SixLabors.ImageSharp.Memory
: this.GetRowMemorySlow(y).Span;
}
+ internal bool TryGetPaddedRowSpan(int y, int padding, out Span paddedSpan)
+ {
+ DebugGuard.MustBeGreaterThanOrEqualTo(y, 0, nameof(y));
+ DebugGuard.MustBeLessThan(y, this.Height, nameof(y));
+
+ int stride = this.Width + padding;
+ if (this.cachedMemory.Length > 0)
+ {
+ paddedSpan = this.cachedMemory.Span.Slice(y * this.Width);
+ if (paddedSpan.Length < stride)
+ {
+ return false;
+ }
+
+ paddedSpan = paddedSpan.Slice(0, stride);
+ return true;
+ }
+
+ Memory memory = this.FastMemoryGroup.GetRemainingSliceOfBuffer(y * (long)this.Width);
+
+ if (memory.Length < stride)
+ {
+ paddedSpan = default;
+ return false;
+ }
+
+ paddedSpan = memory.Span.Slice(0, stride);
+ return true;
+ }
+
[MethodImpl(InliningOptions.ShortMethod)]
internal ref T GetElementUnsafe(int x, int y)
{
diff --git a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroupExtensions.cs b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroupExtensions.cs
index da42b30ad..8e6f38d14 100644
--- a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroupExtensions.cs
+++ b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroupExtensions.cs
@@ -39,12 +39,8 @@ namespace SixLabors.ImageSharp.Memory
int bufferIdx = (int)(start / group.BufferLength);
- if (bufferIdx < 0)
- {
- throw new ArgumentOutOfRangeException(nameof(start));
- }
-
- if (bufferIdx >= group.Count)
+ // if (bufferIdx < 0 || bufferIdx >= group.Count)
+ if ((uint)bufferIdx >= group.Count)
{
throw new ArgumentOutOfRangeException(nameof(start));
}
@@ -61,6 +57,31 @@ namespace SixLabors.ImageSharp.Memory
return memory.Slice(bufferStart, length);
}
+ ///
+ /// Returns the slice of the buffer starting at global index that goes until the end of the buffer.
+ ///
+ internal static Memory GetRemainingSliceOfBuffer(this IMemoryGroup group, long start)
+ where T : struct
+ {
+ Guard.NotNull(group, nameof(group));
+ Guard.IsTrue(group.IsValid, nameof(group), "Group must be valid!");
+ Guard.MustBeLessThan(start, group.TotalLength, nameof(start));
+
+ int bufferIdx = (int)(start / group.BufferLength);
+
+ // if (bufferIdx < 0 || bufferIdx >= group.Count)
+ if ((uint)bufferIdx >= group.Count)
+ {
+ throw new ArgumentOutOfRangeException(nameof(start));
+ }
+
+ int bufferStart = (int)(start % group.BufferLength);
+
+ Memory memory = group[bufferIdx];
+
+ return memory.Slice(bufferStart);
+ }
+
internal static void CopyTo(this IMemoryGroup source, Span target)
where T : struct
{
diff --git a/src/ImageSharp/Memory/TransformItemsDelegate{T}.cs b/src/ImageSharp/Memory/TransformItemsDelegate{TSource, TTarget}.cs
similarity index 56%
rename from src/ImageSharp/Memory/TransformItemsDelegate{T}.cs
rename to src/ImageSharp/Memory/TransformItemsDelegate{TSource, TTarget}.cs
index 722dde19a..3bf8cb1b8 100644
--- a/src/ImageSharp/Memory/TransformItemsDelegate{T}.cs
+++ b/src/ImageSharp/Memory/TransformItemsDelegate{TSource, TTarget}.cs
@@ -1,9 +1,11 @@
-// Copyright (c) Six Labors.
+// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
using System;
namespace SixLabors.ImageSharp.Memory
{
+#pragma warning disable SA1649 // File name should match first type name
internal delegate void TransformItemsDelegate(ReadOnlySpan source, Span target);
+#pragma warning restore SA1649 // File name should match first type name
}
diff --git a/src/ImageSharp/Metadata/FrameDecodingMode.cs b/src/ImageSharp/Metadata/FrameDecodingMode.cs
index e03af18bd..6164f939b 100644
--- a/src/ImageSharp/Metadata/FrameDecodingMode.cs
+++ b/src/ImageSharp/Metadata/FrameDecodingMode.cs
@@ -18,4 +18,4 @@ namespace SixLabors.ImageSharp.Metadata
///
First
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Metadata/Profiles/Exif/ExifProfile.cs b/src/ImageSharp/Metadata/Profiles/Exif/ExifProfile.cs
index 9265314ed..e0ab8ecf9 100644
--- a/src/ImageSharp/Metadata/Profiles/Exif/ExifProfile.cs
+++ b/src/ImageSharp/Metadata/Profiles/Exif/ExifProfile.cs
@@ -4,7 +4,6 @@
using System;
using System.Collections.Generic;
using System.IO;
-
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Metadata.Profiles.Exif
diff --git a/src/ImageSharp/Metadata/Profiles/ICC/Curves/IccCurveSegment.cs b/src/ImageSharp/Metadata/Profiles/ICC/Curves/IccCurveSegment.cs
index c68283914..8f2598a9a 100644
--- a/src/ImageSharp/Metadata/Profiles/ICC/Curves/IccCurveSegment.cs
+++ b/src/ImageSharp/Metadata/Profiles/ICC/Curves/IccCurveSegment.cs
@@ -40,4 +40,4 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Icc
return this.Signature == other.Signature;
}
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Metadata/Profiles/ICC/Curves/IccFormulaCurveElement.cs b/src/ImageSharp/Metadata/Profiles/ICC/Curves/IccFormulaCurveElement.cs
index 1ba521f1a..b756e1b09 100644
--- a/src/ImageSharp/Metadata/Profiles/ICC/Curves/IccFormulaCurveElement.cs
+++ b/src/ImageSharp/Metadata/Profiles/ICC/Curves/IccFormulaCurveElement.cs
@@ -90,4 +90,4 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Icc
return this.Equals((IccCurveSegment)other);
}
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Metadata/Profiles/ICC/Enums/IccDataType.cs b/src/ImageSharp/Metadata/Profiles/ICC/Enums/IccDataType.cs
index a0c1c3b2a..97a27a557 100644
--- a/src/ImageSharp/Metadata/Profiles/ICC/Enums/IccDataType.cs
+++ b/src/ImageSharp/Metadata/Profiles/ICC/Enums/IccDataType.cs
@@ -81,4 +81,4 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Icc
///
Ascii
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Metadata/Profiles/ICC/IccReader.cs b/src/ImageSharp/Metadata/Profiles/ICC/IccReader.cs
index dd1c72c8b..5d8b450f0 100644
--- a/src/ImageSharp/Metadata/Profiles/ICC/IccReader.cs
+++ b/src/ImageSharp/Metadata/Profiles/ICC/IccReader.cs
@@ -147,4 +147,4 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Icc
return table.ToArray();
}
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Metadata/Profiles/ICC/IccTagDataEntry.cs b/src/ImageSharp/Metadata/Profiles/ICC/IccTagDataEntry.cs
index b1783cfe4..77a647482 100644
--- a/src/ImageSharp/Metadata/Profiles/ICC/IccTagDataEntry.cs
+++ b/src/ImageSharp/Metadata/Profiles/ICC/IccTagDataEntry.cs
@@ -66,4 +66,4 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Icc
///
public override int GetHashCode() => this.Signature.GetHashCode();
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Metadata/Profiles/ICC/IccWriter.cs b/src/ImageSharp/Metadata/Profiles/ICC/IccWriter.cs
index 9cd0c1793..50ece5056 100644
--- a/src/ImageSharp/Metadata/Profiles/ICC/IccWriter.cs
+++ b/src/ImageSharp/Metadata/Profiles/ICC/IccWriter.cs
@@ -89,4 +89,4 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Icc
return table.ToArray();
}
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Metadata/Profiles/ICC/MultiProcessElements/IccCurveSetProcessElement.cs b/src/ImageSharp/Metadata/Profiles/ICC/MultiProcessElements/IccCurveSetProcessElement.cs
index 8270786ed..c21d7f001 100644
--- a/src/ImageSharp/Metadata/Profiles/ICC/MultiProcessElements/IccCurveSetProcessElement.cs
+++ b/src/ImageSharp/Metadata/Profiles/ICC/MultiProcessElements/IccCurveSetProcessElement.cs
@@ -37,4 +37,4 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Icc
///
public bool Equals(IccCurveSetProcessElement other) => this.Equals((IccMultiProcessElement)other);
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccChromaticityTagDataEntry.cs b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccChromaticityTagDataEntry.cs
index 508b3f9ad..cdadea77c 100644
--- a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccChromaticityTagDataEntry.cs
+++ b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccChromaticityTagDataEntry.cs
@@ -165,4 +165,4 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Icc
return true;
}
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccColorantOrderTagDataEntry.cs b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccColorantOrderTagDataEntry.cs
index df7c6b8e8..091aee367 100644
--- a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccColorantOrderTagDataEntry.cs
+++ b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccColorantOrderTagDataEntry.cs
@@ -73,4 +73,4 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Icc
return HashCode.Combine(this.Signature, this.ColorantNumber);
}
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccColorantTableTagDataEntry.cs b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccColorantTableTagDataEntry.cs
index 0e096f0cb..3c07372ae 100644
--- a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccColorantTableTagDataEntry.cs
+++ b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccColorantTableTagDataEntry.cs
@@ -65,4 +65,4 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Icc
///
public override int GetHashCode() => HashCode.Combine(this.Signature, this.ColorantData);
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccCurveTagDataEntry.cs b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccCurveTagDataEntry.cs
index 24e57ec8e..5a9691622 100644
--- a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccCurveTagDataEntry.cs
+++ b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccCurveTagDataEntry.cs
@@ -118,4 +118,4 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Icc
///
public override int GetHashCode() => HashCode.Combine(this.Signature, this.CurveData);
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccDataTagDataEntry.cs b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccDataTagDataEntry.cs
index 1b885c590..7d18faede 100644
--- a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccDataTagDataEntry.cs
+++ b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccDataTagDataEntry.cs
@@ -97,4 +97,4 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Icc
this.IsAscii);
}
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccDateTimeTagDataEntry.cs b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccDateTimeTagDataEntry.cs
index af837237e..55d445ef1 100644
--- a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccDateTimeTagDataEntry.cs
+++ b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccDateTimeTagDataEntry.cs
@@ -69,4 +69,4 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Icc
return HashCode.Combine(this.Signature, this.Value);
}
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccFix16ArrayTagDataEntry.cs b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccFix16ArrayTagDataEntry.cs
index 45d6865c3..005ab6753 100644
--- a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccFix16ArrayTagDataEntry.cs
+++ b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccFix16ArrayTagDataEntry.cs
@@ -66,4 +66,4 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Icc
///
public override int GetHashCode() => HashCode.Combine(this.Signature, this.Data);
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccMultiLocalizedUnicodeTagDataEntry.cs b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccMultiLocalizedUnicodeTagDataEntry.cs
index ca713b4ed..3f2dab80b 100644
--- a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccMultiLocalizedUnicodeTagDataEntry.cs
+++ b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccMultiLocalizedUnicodeTagDataEntry.cs
@@ -67,4 +67,4 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Icc
///
public override int GetHashCode() => HashCode.Combine(this.Signature, this.Texts);
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccMultiProcessElementsTagDataEntry.cs b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccMultiProcessElementsTagDataEntry.cs
index 3dd05ca42..5077b74cc 100644
--- a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccMultiProcessElementsTagDataEntry.cs
+++ b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccMultiProcessElementsTagDataEntry.cs
@@ -91,4 +91,4 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Icc
this.Data);
}
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccResponseCurveSet16TagDataEntry.cs b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccResponseCurveSet16TagDataEntry.cs
index 625566140..13ba0bbea 100644
--- a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccResponseCurveSet16TagDataEntry.cs
+++ b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccResponseCurveSet16TagDataEntry.cs
@@ -83,4 +83,4 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Icc
this.Curves);
}
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccTextTagDataEntry.cs b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccTextTagDataEntry.cs
index 2ee339a5f..b6f7edec1 100644
--- a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccTextTagDataEntry.cs
+++ b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccTextTagDataEntry.cs
@@ -66,4 +66,4 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Icc
///
public override int GetHashCode() => HashCode.Combine(this.Signature, this.Text);
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccUFix16ArrayTagDataEntry.cs b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccUFix16ArrayTagDataEntry.cs
index 2b8ec2c7e..b084787f7 100644
--- a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccUFix16ArrayTagDataEntry.cs
+++ b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccUFix16ArrayTagDataEntry.cs
@@ -66,4 +66,4 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Icc
///
public override int GetHashCode() => HashCode.Combine(this.Signature, this.Data);
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccUInt16ArrayTagDataEntry.cs b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccUInt16ArrayTagDataEntry.cs
index 9396bbc35..4a0ff8108 100644
--- a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccUInt16ArrayTagDataEntry.cs
+++ b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccUInt16ArrayTagDataEntry.cs
@@ -66,4 +66,4 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Icc
///
public override int GetHashCode() => HashCode.Combine(this.Signature, this.Data);
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccUInt32ArrayTagDataEntry.cs b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccUInt32ArrayTagDataEntry.cs
index 38b76fd34..6741bd538 100644
--- a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccUInt32ArrayTagDataEntry.cs
+++ b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccUInt32ArrayTagDataEntry.cs
@@ -66,4 +66,4 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Icc
///
public override int GetHashCode() => HashCode.Combine(this.Signature, this.Data);
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccUInt64ArrayTagDataEntry.cs b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccUInt64ArrayTagDataEntry.cs
index f1eb93c46..63f7ec4a5 100644
--- a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccUInt64ArrayTagDataEntry.cs
+++ b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccUInt64ArrayTagDataEntry.cs
@@ -57,4 +57,4 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Icc
///
public override int GetHashCode() => HashCode.Combine(this.Signature, this.Data);
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccUInt8ArrayTagDataEntry.cs b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccUInt8ArrayTagDataEntry.cs
index 1640999a3..eee1c2bd3 100644
--- a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccUInt8ArrayTagDataEntry.cs
+++ b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccUInt8ArrayTagDataEntry.cs
@@ -66,4 +66,4 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Icc
///
public override int GetHashCode() => HashCode.Combine(this.Signature, this.Data);
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccUcrBgTagDataEntry.cs b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccUcrBgTagDataEntry.cs
index 763425554..4a5989bf1 100644
--- a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccUcrBgTagDataEntry.cs
+++ b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccUcrBgTagDataEntry.cs
@@ -93,4 +93,4 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Icc
this.Description);
}
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccUnknownTagDataEntry.cs b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccUnknownTagDataEntry.cs
index f811af298..7a9d06e05 100644
--- a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccUnknownTagDataEntry.cs
+++ b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccUnknownTagDataEntry.cs
@@ -66,4 +66,4 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Icc
///
public override int GetHashCode() => HashCode.Combine(this.Signature, this.Data);
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Metadata/Profiles/ICC/Various/IccClut.cs b/src/ImageSharp/Metadata/Profiles/ICC/Various/IccClut.cs
index 0e37b0e2d..edee7a4c7 100644
--- a/src/ImageSharp/Metadata/Profiles/ICC/Various/IccClut.cs
+++ b/src/ImageSharp/Metadata/Profiles/ICC/Various/IccClut.cs
@@ -184,4 +184,4 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Icc
Guard.IsTrue(this.Values.Length == length, nameof(this.Values), "Length of values array does not match the grid points");
}
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Metadata/Profiles/ICC/Various/IccProfileId.cs b/src/ImageSharp/Metadata/Profiles/ICC/Various/IccProfileId.cs
index dcac6fa48..0bea1b9e1 100644
--- a/src/ImageSharp/Metadata/Profiles/ICC/Various/IccProfileId.cs
+++ b/src/ImageSharp/Metadata/Profiles/ICC/Various/IccProfileId.cs
@@ -110,4 +110,4 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Icc
private static string ToHex(uint value) => value.ToString("X").PadLeft(8, '0');
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Metadata/Profiles/ICC/Various/IccScreeningChannel.cs b/src/ImageSharp/Metadata/Profiles/ICC/Various/IccScreeningChannel.cs
index d8e360512..94d6b7662 100644
--- a/src/ImageSharp/Metadata/Profiles/ICC/Various/IccScreeningChannel.cs
+++ b/src/ImageSharp/Metadata/Profiles/ICC/Various/IccScreeningChannel.cs
@@ -91,4 +91,4 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Icc
///
public override string ToString() => $"{this.Frequency}Hz; {this.Angle}°; {this.SpotShape}";
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/PixelFormats/HalfTypeHelper.cs b/src/ImageSharp/PixelFormats/HalfTypeHelper.cs
index 534f60999..69f4d7813 100644
--- a/src/ImageSharp/PixelFormats/HalfTypeHelper.cs
+++ b/src/ImageSharp/PixelFormats/HalfTypeHelper.cs
@@ -142,4 +142,4 @@ namespace SixLabors.ImageSharp.PixelFormats
public uint U;
}
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/PixelFormats/IPackedVector{TPacked}.cs b/src/ImageSharp/PixelFormats/IPackedVector{TPacked}.cs
index 64560a572..f9dcbed71 100644
--- a/src/ImageSharp/PixelFormats/IPackedVector{TPacked}.cs
+++ b/src/ImageSharp/PixelFormats/IPackedVector{TPacked}.cs
@@ -18,4 +18,4 @@ namespace SixLabors.ImageSharp.PixelFormats
///
TPacked PackedValue { get; set; }
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/PixelFormats/PixelConversionModifiers.cs b/src/ImageSharp/PixelFormats/PixelConversionModifiers.cs
index 7a5a3dad6..51c223113 100644
--- a/src/ImageSharp/PixelFormats/PixelConversionModifiers.cs
+++ b/src/ImageSharp/PixelFormats/PixelConversionModifiers.cs
@@ -2,7 +2,6 @@
// Licensed under the Apache License, Version 2.0.
using System;
-
using SixLabors.ImageSharp.ColorSpaces.Companding;
namespace SixLabors.ImageSharp.PixelFormats
diff --git a/src/ImageSharp/PixelFormats/PixelConversionModifiersExtensions.cs b/src/ImageSharp/PixelFormats/PixelConversionModifiersExtensions.cs
index 9e8c97f81..5b1b44dd2 100644
--- a/src/ImageSharp/PixelFormats/PixelConversionModifiersExtensions.cs
+++ b/src/ImageSharp/PixelFormats/PixelConversionModifiersExtensions.cs
@@ -35,4 +35,4 @@ namespace SixLabors.ImageSharp.PixelFormats
? originalModifiers | PixelConversionModifiers.Scale | PixelConversionModifiers.SRgbCompand
: originalModifiers;
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/A8.cs b/src/ImageSharp/PixelFormats/PixelImplementations/A8.cs
index 77df2bc80..cca7ff7db 100644
--- a/src/ImageSharp/PixelFormats/PixelImplementations/A8.cs
+++ b/src/ImageSharp/PixelFormats/PixelImplementations/A8.cs
@@ -73,7 +73,7 @@ namespace SixLabors.ImageSharp.PixelFormats
///
[MethodImpl(InliningOptions.ShortMethod)]
- public readonly Vector4 ToVector4() => new Vector4(0, 0, 0, this.PackedValue / 255F);
+ public readonly Vector4 ToVector4() => new(0, 0, 0, this.PackedValue / 255F);
///
[MethodImpl(InliningOptions.ShortMethod)]
diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs
index 3ac9b523f..8c1b04ff1 100644
--- a/src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs
+++ b/src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs
@@ -44,12 +44,12 @@ namespace SixLabors.ImageSharp.PixelFormats
///
/// The maximum byte value.
///
- private static readonly Vector4 MaxBytes = new Vector4(255);
+ private static readonly Vector4 MaxBytes = new(255);
///
/// The half vector value.
///
- private static readonly Vector4 Half = new Vector4(0.5F);
+ private static readonly Vector4 Half = new(0.5F);
///
/// Initializes a new instance of the struct.
@@ -151,7 +151,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// The .
/// The .
[MethodImpl(InliningOptions.ShortMethod)]
- public static implicit operator Color(Argb32 source) => new Color(source);
+ public static implicit operator Color(Argb32 source) => new(source);
///
/// Converts a to .
diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Bgr24.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgr24.cs
index 6cff5fd77..22e983a65 100644
--- a/src/ImageSharp/PixelFormats/PixelImplementations/Bgr24.cs
+++ b/src/ImageSharp/PixelFormats/PixelImplementations/Bgr24.cs
@@ -56,7 +56,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// The .
/// The .
[MethodImpl(InliningOptions.ShortMethod)]
- public static implicit operator Color(Bgr24 source) => new Color(source);
+ public static implicit operator Color(Bgr24 source) => new(source);
///
/// Converts a to .
@@ -225,7 +225,7 @@ namespace SixLabors.ImageSharp.PixelFormats
public override readonly bool Equals(object obj) => obj is Bgr24 other && this.Equals(other);
///
- public override readonly string ToString() => $"Bgra({this.B}, {this.G}, {this.R})";
+ public override readonly string ToString() => $"Bgr24({this.B}, {this.G}, {this.R})";
///
[MethodImpl(InliningOptions.ShortMethod)]
diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Bgr565.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgr565.cs
index fd12b6837..5585310b9 100644
--- a/src/ImageSharp/PixelFormats/PixelImplementations/Bgr565.cs
+++ b/src/ImageSharp/PixelFormats/PixelImplementations/Bgr565.cs
@@ -81,7 +81,7 @@ namespace SixLabors.ImageSharp.PixelFormats
///
[MethodImpl(InliningOptions.ShortMethod)]
- public readonly Vector4 ToVector4() => new Vector4(this.ToVector3(), 1F);
+ public readonly Vector4 ToVector4() => new(this.ToVector3(), 1F);
///
[MethodImpl(InliningOptions.ShortMethod)]
@@ -125,10 +125,7 @@ namespace SixLabors.ImageSharp.PixelFormats
///
[MethodImpl(InliningOptions.ShortMethod)]
- public void ToRgba32(ref Rgba32 dest)
- {
- dest.FromScaledVector4(this.ToScaledVector4());
- }
+ public void ToRgba32(ref Rgba32 dest) => dest.FromScaledVector4(this.ToScaledVector4());
///
[MethodImpl(InliningOptions.ShortMethod)]
@@ -144,13 +141,10 @@ namespace SixLabors.ImageSharp.PixelFormats
///
/// The .
[MethodImpl(InliningOptions.ShortMethod)]
- public readonly Vector3 ToVector3()
- {
- return new Vector3(
+ public readonly Vector3 ToVector3() => new(
((this.PackedValue >> 11) & 0x1F) * (1F / 31F),
((this.PackedValue >> 5) & 0x3F) * (1F / 63F),
(this.PackedValue & 0x1F) * (1F / 31F));
- }
///
public override readonly bool Equals(object obj) => obj is Bgr565 other && this.Equals(other);
diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs
index 190345dda..be4e178c2 100644
--- a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs
+++ b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs
@@ -41,12 +41,12 @@ namespace SixLabors.ImageSharp.PixelFormats
///
/// The maximum byte value.
///
- private static readonly Vector4 MaxBytes = new Vector4(255);
+ private static readonly Vector4 MaxBytes = new(255);
///
/// The half vector value.
///
- private static readonly Vector4 Half = new Vector4(0.5F);
+ private static readonly Vector4 Half = new(0.5F);
///
/// Initializes a new instance of the struct.
@@ -104,7 +104,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// The .
/// The .
[MethodImpl(InliningOptions.ShortMethod)]
- public static implicit operator Color(Bgra32 source) => new Color(source);
+ public static implicit operator Color(Bgra32 source) => new(source);
///
/// Converts a to .
diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra4444.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra4444.cs
index 8fa5219d5..3578f1dd3 100644
--- a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra4444.cs
+++ b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra4444.cs
@@ -128,10 +128,7 @@ namespace SixLabors.ImageSharp.PixelFormats
///
[MethodImpl(InliningOptions.ShortMethod)]
- public void ToRgba32(ref Rgba32 dest)
- {
- dest.FromScaledVector4(this.ToScaledVector4());
- }
+ public void ToRgba32(ref Rgba32 dest) => dest.FromScaledVector4(this.ToScaledVector4());
///
[MethodImpl(InliningOptions.ShortMethod)]
diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra5551.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra5551.cs
index b3a0d0896..0254397c3 100644
--- a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra5551.cs
+++ b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra5551.cs
@@ -78,14 +78,11 @@ namespace SixLabors.ImageSharp.PixelFormats
///
[MethodImpl(InliningOptions.ShortMethod)]
- public readonly Vector4 ToVector4()
- {
- return new Vector4(
+ public readonly Vector4 ToVector4() => new(
((this.PackedValue >> 10) & 0x1F) / 31F,
((this.PackedValue >> 5) & 0x1F) / 31F,
((this.PackedValue >> 0) & 0x1F) / 31F,
(this.PackedValue >> 15) & 0x01);
- }
///
[MethodImpl(InliningOptions.ShortMethod)]
@@ -129,10 +126,7 @@ namespace SixLabors.ImageSharp.PixelFormats
///
[MethodImpl(InliningOptions.ShortMethod)]
- public void ToRgba32(ref Rgba32 dest)
- {
- dest.FromScaledVector4(this.ToScaledVector4());
- }
+ public void ToRgba32(ref Rgba32 dest) => dest.FromScaledVector4(this.ToScaledVector4());
///
[MethodImpl(InliningOptions.ShortMethod)]
diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Byte4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Byte4.cs
index e26121291..0995f8417 100644
--- a/src/ImageSharp/PixelFormats/PixelImplementations/Byte4.cs
+++ b/src/ImageSharp/PixelFormats/PixelImplementations/Byte4.cs
@@ -78,14 +78,11 @@ namespace SixLabors.ImageSharp.PixelFormats
///
[MethodImpl(InliningOptions.ShortMethod)]
- public readonly Vector4 ToVector4()
- {
- return new Vector4(
+ public readonly Vector4 ToVector4() => new(
this.PackedValue & 0xFF,
(this.PackedValue >> 0x8) & 0xFF,
(this.PackedValue >> 0x10) & 0xFF,
(this.PackedValue >> 0x18) & 0xFF);
- }
///
[MethodImpl(InliningOptions.ShortMethod)]
@@ -129,10 +126,7 @@ namespace SixLabors.ImageSharp.PixelFormats
///
[MethodImpl(InliningOptions.ShortMethod)]
- public void ToRgba32(ref Rgba32 dest)
- {
- dest.FromScaledVector4(this.ToScaledVector4());
- }
+ public void ToRgba32(ref Rgba32 dest) => dest.FromScaledVector4(this.ToScaledVector4());
///
[MethodImpl(InliningOptions.ShortMethod)]
diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/HalfSingle.cs b/src/ImageSharp/PixelFormats/PixelImplementations/HalfSingle.cs
index 5c4aa1cfb..b0ef0f6a9 100644
--- a/src/ImageSharp/PixelFormats/PixelImplementations/HalfSingle.cs
+++ b/src/ImageSharp/PixelFormats/PixelImplementations/HalfSingle.cs
@@ -74,7 +74,7 @@ namespace SixLabors.ImageSharp.PixelFormats
///
[MethodImpl(InliningOptions.ShortMethod)]
- public readonly Vector4 ToVector4() => new Vector4(this.ToSingle(), 0, 0, 1F);
+ public readonly Vector4 ToVector4() => new(this.ToSingle(), 0, 0, 1F);
///
[MethodImpl(InliningOptions.ShortMethod)]
@@ -118,10 +118,7 @@ namespace SixLabors.ImageSharp.PixelFormats
///
[MethodImpl(InliningOptions.ShortMethod)]
- public void ToRgba32(ref Rgba32 dest)
- {
- dest.FromScaledVector4(this.ToScaledVector4());
- }
+ public void ToRgba32(ref Rgba32 dest) => dest.FromScaledVector4(this.ToScaledVector4());
///
[MethodImpl(InliningOptions.ShortMethod)]
diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector2.cs b/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector2.cs
index 39cb6f799..8be826130 100644
--- a/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector2.cs
+++ b/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector2.cs
@@ -129,10 +129,7 @@ namespace SixLabors.ImageSharp.PixelFormats
///
[MethodImpl(InliningOptions.ShortMethod)]
- public void ToRgba32(ref Rgba32 dest)
- {
- dest.FromScaledVector4(this.ToScaledVector4());
- }
+ public void ToRgba32(ref Rgba32 dest) => dest.FromScaledVector4(this.ToScaledVector4());
///
[MethodImpl(InliningOptions.ShortMethod)]
diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector4.cs
index 9826d61a2..955b274ac 100644
--- a/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector4.cs
+++ b/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector4.cs
@@ -86,14 +86,11 @@ namespace SixLabors.ImageSharp.PixelFormats
///
[MethodImpl(InliningOptions.ShortMethod)]
- public readonly Vector4 ToVector4()
- {
- return new Vector4(
+ public readonly Vector4 ToVector4() => new(
HalfTypeHelper.Unpack((ushort)this.PackedValue),
HalfTypeHelper.Unpack((ushort)(this.PackedValue >> 0x10)),
HalfTypeHelper.Unpack((ushort)(this.PackedValue >> 0x20)),
HalfTypeHelper.Unpack((ushort)(this.PackedValue >> 0x30)));
- }
///
[MethodImpl(InliningOptions.ShortMethod)]
@@ -137,10 +134,7 @@ namespace SixLabors.ImageSharp.PixelFormats
///
[MethodImpl(InliningOptions.ShortMethod)]
- public void ToRgba32(ref Rgba32 dest)
- {
- dest.FromScaledVector4(this.ToScaledVector4());
- }
+ public void ToRgba32(ref Rgba32 dest) => dest.FromScaledVector4(this.ToScaledVector4());
///
[MethodImpl(InliningOptions.ShortMethod)]
diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/L16.cs b/src/ImageSharp/PixelFormats/PixelImplementations/L16.cs
index dd31aae2f..6d1128dd2 100644
--- a/src/ImageSharp/PixelFormats/PixelImplementations/L16.cs
+++ b/src/ImageSharp/PixelFormats/PixelImplementations/L16.cs
@@ -72,33 +72,24 @@ namespace SixLabors.ImageSharp.PixelFormats
///
[MethodImpl(InliningOptions.ShortMethod)]
- public void FromArgb32(Argb32 source)
- {
- this.PackedValue = ColorNumerics.Get16BitBT709Luminance(
+ public void FromArgb32(Argb32 source) => this.PackedValue = ColorNumerics.Get16BitBT709Luminance(
ColorNumerics.UpscaleFrom8BitTo16Bit(source.R),
ColorNumerics.UpscaleFrom8BitTo16Bit(source.G),
ColorNumerics.UpscaleFrom8BitTo16Bit(source.B));
- }
///
[MethodImpl(InliningOptions.ShortMethod)]
- public void FromBgr24(Bgr24 source)
- {
- this.PackedValue = ColorNumerics.Get16BitBT709Luminance(
+ public void FromBgr24(Bgr24 source) => this.PackedValue = ColorNumerics.Get16BitBT709Luminance(
ColorNumerics.UpscaleFrom8BitTo16Bit(source.R),
ColorNumerics.UpscaleFrom8BitTo16Bit(source.G),
ColorNumerics.UpscaleFrom8BitTo16Bit(source.B));
- }
///
[MethodImpl(InliningOptions.ShortMethod)]
- public void FromBgra32(Bgra32 source)
- {
- this.PackedValue = ColorNumerics.Get16BitBT709Luminance(
+ public void FromBgra32(Bgra32 source) => this.PackedValue = ColorNumerics.Get16BitBT709Luminance(
ColorNumerics.UpscaleFrom8BitTo16Bit(source.R),
ColorNumerics.UpscaleFrom8BitTo16Bit(source.G),
ColorNumerics.UpscaleFrom8BitTo16Bit(source.B));
- }
///
[MethodImpl(InliningOptions.ShortMethod)]
@@ -122,23 +113,17 @@ namespace SixLabors.ImageSharp.PixelFormats
///
[MethodImpl(InliningOptions.ShortMethod)]
- public void FromRgb24(Rgb24 source)
- {
- this.PackedValue = ColorNumerics.Get16BitBT709Luminance(
+ public void FromRgb24(Rgb24 source) => this.PackedValue = ColorNumerics.Get16BitBT709Luminance(
ColorNumerics.UpscaleFrom8BitTo16Bit(source.R),
ColorNumerics.UpscaleFrom8BitTo16Bit(source.G),
ColorNumerics.UpscaleFrom8BitTo16Bit(source.B));
- }
///
[MethodImpl(InliningOptions.ShortMethod)]
- public void FromRgba32(Rgba32 source)
- {
- this.PackedValue = ColorNumerics.Get16BitBT709Luminance(
+ public void FromRgba32(Rgba32 source) => this.PackedValue = ColorNumerics.Get16BitBT709Luminance(
ColorNumerics.UpscaleFrom8BitTo16Bit(source.R),
ColorNumerics.UpscaleFrom8BitTo16Bit(source.G),
ColorNumerics.UpscaleFrom8BitTo16Bit(source.B));
- }
///
[MethodImpl(InliningOptions.ShortMethod)]
diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/L8.cs b/src/ImageSharp/PixelFormats/PixelImplementations/L8.cs
index c570c33a1..ffff60be5 100644
--- a/src/ImageSharp/PixelFormats/PixelImplementations/L8.cs
+++ b/src/ImageSharp/PixelFormats/PixelImplementations/L8.cs
@@ -14,8 +14,8 @@ namespace SixLabors.ImageSharp.PixelFormats
///
public partial struct L8 : IPixel, IPackedVector
{
- private static readonly Vector4 MaxBytes = new Vector4(255F);
- private static readonly Vector4 Half = new Vector4(0.5F);
+ private static readonly Vector4 MaxBytes = new(255F);
+ private static readonly Vector4 Half = new(0.5F);
///
/// Initializes a new instance of the struct.
diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/La16.cs b/src/ImageSharp/PixelFormats/PixelImplementations/La16.cs
index 5a69431a1..877aaed81 100644
--- a/src/ImageSharp/PixelFormats/PixelImplementations/La16.cs
+++ b/src/ImageSharp/PixelFormats/PixelImplementations/La16.cs
@@ -16,8 +16,8 @@ namespace SixLabors.ImageSharp.PixelFormats
[StructLayout(LayoutKind.Explicit)]
public partial struct La16 : IPixel, IPackedVector
{
- private static readonly Vector4 MaxBytes = new Vector4(255F);
- private static readonly Vector4 Half = new Vector4(0.5F);
+ private static readonly Vector4 MaxBytes = new(255F);
+ private static readonly Vector4 Half = new(0.5F);
///
/// Gets or sets the luminance component.
@@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// Initializes a new instance of the struct.
///
/// The luminance component.
- /// The alpha componant.
+ /// The alpha component.
public La16(byte l, byte a)
{
this.L = l;
diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/La32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/La32.cs
index 66d0e38c7..f19f22813 100644
--- a/src/ImageSharp/PixelFormats/PixelImplementations/La32.cs
+++ b/src/ImageSharp/PixelFormats/PixelImplementations/La32.cs
@@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// Initializes a new instance of the struct.
///
/// The luminance component.
- /// The alpha componant.
+ /// The alpha component.
public La32(ushort l, ushort a)
{
this.L = l;
diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte2.cs b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte2.cs
index 8b244d391..62eaf949d 100644
--- a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte2.cs
+++ b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte2.cs
@@ -15,8 +15,10 @@ namespace SixLabors.ImageSharp.PixelFormats
///
public partial struct NormalizedByte2 : IPixel, IPackedVector
{
- private static readonly Vector2 Half = new Vector2(127);
- private static readonly Vector2 MinusOne = new Vector2(-1F);
+ private const float MaxPos = 127F;
+
+ private static readonly Vector2 Half = new(MaxPos);
+ private static readonly Vector2 MinusOne = new(-1F);
///
/// Initializes a new instance of the struct.
@@ -91,7 +93,7 @@ namespace SixLabors.ImageSharp.PixelFormats
///
[MethodImpl(InliningOptions.ShortMethod)]
- public readonly Vector4 ToVector4() => new Vector4(this.ToVector2(), 0F, 1F);
+ public readonly Vector4 ToVector4() => new(this.ToVector2(), 0F, 1F);
///
[MethodImpl(InliningOptions.ShortMethod)]
@@ -151,12 +153,9 @@ namespace SixLabors.ImageSharp.PixelFormats
///
/// The .
[MethodImpl(InliningOptions.ShortMethod)]
- public readonly Vector2 ToVector2()
- {
- return new Vector2(
- (sbyte)((this.PackedValue >> 0) & 0xFF) / 127F,
- (sbyte)((this.PackedValue >> 8) & 0xFF) / 127F);
- }
+ public readonly Vector2 ToVector2() => new(
+ (sbyte)((this.PackedValue >> 0) & 0xFF) / MaxPos,
+ (sbyte)((this.PackedValue >> 8) & 0xFF) / MaxPos);
///
public override readonly bool Equals(object obj) => obj is NormalizedByte2 other && this.Equals(other);
@@ -181,8 +180,8 @@ namespace SixLabors.ImageSharp.PixelFormats
{
vector = Vector2.Clamp(vector, MinusOne, Vector2.One) * Half;
- int byte2 = ((ushort)Math.Round(vector.X) & 0xFF) << 0;
- int byte1 = ((ushort)Math.Round(vector.Y) & 0xFF) << 8;
+ int byte2 = ((ushort)Convert.ToInt16(Math.Round(vector.X)) & 0xFF) << 0;
+ int byte1 = ((ushort)Convert.ToInt16(Math.Round(vector.Y)) & 0xFF) << 8;
return (ushort)(byte2 | byte1);
}
diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte4.cs
index 84f0bb022..2e81b3e2d 100644
--- a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte4.cs
+++ b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte4.cs
@@ -15,8 +15,10 @@ namespace SixLabors.ImageSharp.PixelFormats
///
public partial struct NormalizedByte4 : IPixel, IPackedVector
{
- private static readonly Vector4 Half = new Vector4(127);
- private static readonly Vector4 MinusOne = new Vector4(-1F);
+ private const float MaxPos = 127F;
+
+ private static readonly Vector4 Half = new(MaxPos);
+ private static readonly Vector4 MinusOne = new(-1F);
///
/// Initializes a new instance of the struct.
@@ -89,14 +91,11 @@ namespace SixLabors.ImageSharp.PixelFormats
///
[MethodImpl(InliningOptions.ShortMethod)]
- public readonly Vector4 ToVector4()
- {
- return new Vector4(
- (sbyte)((this.PackedValue >> 0) & 0xFF) / 127F,
- (sbyte)((this.PackedValue >> 8) & 0xFF) / 127F,
- (sbyte)((this.PackedValue >> 16) & 0xFF) / 127F,
- (sbyte)((this.PackedValue >> 24) & 0xFF) / 127F);
- }
+ public readonly Vector4 ToVector4() => new(
+ (sbyte)((this.PackedValue >> 0) & 0xFF) / MaxPos,
+ (sbyte)((this.PackedValue >> 8) & 0xFF) / MaxPos,
+ (sbyte)((this.PackedValue >> 16) & 0xFF) / MaxPos,
+ (sbyte)((this.PackedValue >> 24) & 0xFF) / MaxPos);
///
[MethodImpl(InliningOptions.ShortMethod)]
@@ -140,10 +139,7 @@ namespace SixLabors.ImageSharp.PixelFormats
///
[MethodImpl(InliningOptions.ShortMethod)]
- public void ToRgba32(ref Rgba32 dest)
- {
- dest.FromScaledVector4(this.ToScaledVector4());
- }
+ public void ToRgba32(ref Rgba32 dest) => dest.FromScaledVector4(this.ToScaledVector4());
///
[MethodImpl(InliningOptions.ShortMethod)]
@@ -176,10 +172,10 @@ namespace SixLabors.ImageSharp.PixelFormats
{
vector = Numerics.Clamp(vector, MinusOne, Vector4.One) * Half;
- uint byte4 = ((uint)MathF.Round(vector.X) & 0xFF) << 0;
- uint byte3 = ((uint)MathF.Round(vector.Y) & 0xFF) << 8;
- uint byte2 = ((uint)MathF.Round(vector.Z) & 0xFF) << 16;
- uint byte1 = ((uint)MathF.Round(vector.W) & 0xFF) << 24;
+ uint byte4 = ((uint)Convert.ToInt16(MathF.Round(vector.X)) & 0xFF) << 0;
+ uint byte3 = ((uint)Convert.ToInt16(MathF.Round(vector.Y)) & 0xFF) << 8;
+ uint byte2 = ((uint)Convert.ToInt16(MathF.Round(vector.Z)) & 0xFF) << 16;
+ uint byte1 = ((uint)Convert.ToInt16(MathF.Round(vector.W)) & 0xFF) << 24;
return byte4 | byte3 | byte2 | byte1;
}
diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort2.cs b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort2.cs
index 97bbc1206..b97aaacec 100644
--- a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort2.cs
+++ b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort2.cs
@@ -15,7 +15,10 @@ namespace SixLabors.ImageSharp.PixelFormats
///
public partial struct NormalizedShort2 : IPixel, IPackedVector
{
- private static readonly Vector2 Max = new Vector2(0x7FFF);
+ // Largest two byte positive number 0xFFFF >> 1;
+ private const float MaxPos = 0x7FFF;
+
+ private static readonly Vector2 Max = new(MaxPos);
private static readonly Vector2 Min = Vector2.Negate(Max);
///
@@ -135,10 +138,7 @@ namespace SixLabors.ImageSharp.PixelFormats
///
[MethodImpl(InliningOptions.ShortMethod)]
- public void ToRgba32(ref Rgba32 dest)
- {
- dest.FromScaledVector4(this.ToScaledVector4());
- }
+ public void ToRgba32(ref Rgba32 dest) => dest.FromScaledVector4(this.ToScaledVector4());
///
[MethodImpl(InliningOptions.ShortMethod)]
@@ -154,14 +154,9 @@ namespace SixLabors.ImageSharp.PixelFormats
///
/// The .
[MethodImpl(InliningOptions.ShortMethod)]
- public readonly Vector2 ToVector2()
- {
- const float MaxVal = 0x7FFF;
-
- return new Vector2(
- (short)(this.PackedValue & 0xFFFF) / MaxVal,
- (short)(this.PackedValue >> 0x10) / MaxVal);
- }
+ public readonly Vector2 ToVector2() => new(
+ (short)(this.PackedValue & 0xFFFF) / MaxPos,
+ (short)(this.PackedValue >> 0x10) / MaxPos);
///
public override readonly bool Equals(object obj) => obj is NormalizedShort2 other && this.Equals(other);
diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort4.cs
index a3fd8989c..f2e8aedd8 100644
--- a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort4.cs
+++ b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort4.cs
@@ -15,7 +15,10 @@ namespace SixLabors.ImageSharp.PixelFormats
///
public partial struct NormalizedShort4 : IPixel, IPackedVector
{
- private static readonly Vector4 Max = new Vector4(0x7FFF);
+ // Largest two byte positive number 0xFFFF >> 1;
+ private const float MaxPos = 0x7FFF;
+
+ private static readonly Vector4 Max = new(MaxPos);
private static readonly Vector4 Min = Vector4.Negate(Max);
///
@@ -89,16 +92,11 @@ namespace SixLabors.ImageSharp.PixelFormats
///
[MethodImpl(InliningOptions.ShortMethod)]
- public readonly Vector4 ToVector4()
- {
- const float MaxVal = 0x7FFF;
-
- return new Vector4(
- (short)((this.PackedValue >> 0x00) & 0xFFFF) / MaxVal,
- (short)((this.PackedValue >> 0x10) & 0xFFFF) / MaxVal,
- (short)((this.PackedValue >> 0x20) & 0xFFFF) / MaxVal,
- (short)((this.PackedValue >> 0x30) & 0xFFFF) / MaxVal);
- }
+ public readonly Vector4 ToVector4() => new(
+ (short)((this.PackedValue >> 0x00) & 0xFFFF) / MaxPos,
+ (short)((this.PackedValue >> 0x10) & 0xFFFF) / MaxPos,
+ (short)((this.PackedValue >> 0x20) & 0xFFFF) / MaxPos,
+ (short)((this.PackedValue >> 0x30) & 0xFFFF) / MaxPos);
///
[MethodImpl(InliningOptions.ShortMethod)]
@@ -142,10 +140,7 @@ namespace SixLabors.ImageSharp.PixelFormats
///
[MethodImpl(InliningOptions.ShortMethod)]
- public void ToRgba32(ref Rgba32 dest)
- {
- dest.FromScaledVector4(this.ToScaledVector4());
- }
+ public void ToRgba32(ref Rgba32 dest) => dest.FromScaledVector4(this.ToScaledVector4());
///
[MethodImpl(InliningOptions.ShortMethod)]
@@ -180,10 +175,10 @@ namespace SixLabors.ImageSharp.PixelFormats
vector = Numerics.Clamp(vector, Min, Max);
// Round rather than truncate.
- ulong word4 = ((ulong)MathF.Round(vector.X) & 0xFFFF) << 0x00;
- ulong word3 = ((ulong)MathF.Round(vector.Y) & 0xFFFF) << 0x10;
- ulong word2 = ((ulong)MathF.Round(vector.Z) & 0xFFFF) << 0x20;
- ulong word1 = ((ulong)MathF.Round(vector.W) & 0xFFFF) << 0x30;
+ ulong word4 = ((ulong)Convert.ToInt32(MathF.Round(vector.X)) & 0xFFFF) << 0x00;
+ ulong word3 = ((ulong)Convert.ToInt32(MathF.Round(vector.Y)) & 0xFFFF) << 0x10;
+ ulong word2 = ((ulong)Convert.ToInt32(MathF.Round(vector.Z)) & 0xFFFF) << 0x20;
+ ulong word1 = ((ulong)Convert.ToInt32(MathF.Round(vector.W)) & 0xFFFF) << 0x30;
return word4 | word3 | word2 | word1;
}
diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rgb24.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rgb24.PixelOperations.cs
index f345f58bc..0f1ea6b81 100644
--- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rgb24.PixelOperations.cs
+++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rgb24.PixelOperations.cs
@@ -32,9 +32,7 @@ namespace SixLabors.ImageSharp.PixelFormats
{
Guard.NotNull(configuration, nameof(configuration));
int count = redChannel.Length;
- Guard.IsTrue(greenChannel.Length == count, nameof(greenChannel), "Channels must be of same size!");
- Guard.IsTrue(blueChannel.Length == count, nameof(blueChannel), "Channels must be of same size!");
- Guard.IsTrue(destination.Length > count + 2, nameof(destination), "'destination' must contain a padding of 3 elements!");
+ GuardPackFromRgbPlanes(greenChannel, blueChannel, destination, count);
SimdUtils.PackFromRgbPlanes(configuration, redChannel, greenChannel, blueChannel, destination);
}
diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rgba32.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rgba32.PixelOperations.cs
index 963305977..d937da98f 100644
--- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rgba32.PixelOperations.cs
+++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rgba32.PixelOperations.cs
@@ -67,9 +67,7 @@ namespace SixLabors.ImageSharp.PixelFormats
{
Guard.NotNull(configuration, nameof(configuration));
int count = redChannel.Length;
- Guard.IsTrue(greenChannel.Length == count, nameof(greenChannel), "Channels must be of same size!");
- Guard.IsTrue(blueChannel.Length == count, nameof(blueChannel), "Channels must be of same size!");
- Guard.IsTrue(destination.Length > count, nameof(destination), "'destination' span should not be shorter than the source channels!");
+ GuardPackFromRgbPlanes(greenChannel, blueChannel, destination, count);
SimdUtils.PackFromRgbPlanes(configuration, redChannel, greenChannel, blueChannel, destination);
}
diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rg32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rg32.cs
index d7e6f53cf..12b6e153f 100644
--- a/src/ImageSharp/PixelFormats/PixelImplementations/Rg32.cs
+++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rg32.cs
@@ -15,7 +15,7 @@ namespace SixLabors.ImageSharp.PixelFormats
///
public partial struct Rg32 : IPixel, IPackedVector
{
- private static readonly Vector2 Max = new Vector2(ushort.MaxValue);
+ private static readonly Vector2 Max = new(ushort.MaxValue);
///
/// Initializes a new instance of the struct.
@@ -79,7 +79,7 @@ namespace SixLabors.ImageSharp.PixelFormats
///
[MethodImpl(InliningOptions.ShortMethod)]
- public readonly Vector4 ToVector4() => new Vector4(this.ToVector2(), 0F, 1F);
+ public readonly Vector4 ToVector4() => new(this.ToVector2(), 0F, 1F);
///
[MethodImpl(InliningOptions.ShortMethod)]
@@ -123,10 +123,7 @@ namespace SixLabors.ImageSharp.PixelFormats
///
[MethodImpl(InliningOptions.ShortMethod)]
- public void ToRgba32(ref Rgba32 dest)
- {
- dest.FromScaledVector4(this.ToScaledVector4());
- }
+ public void ToRgba32(ref Rgba32 dest) => dest.FromScaledVector4(this.ToScaledVector4());
///
[MethodImpl(InliningOptions.ShortMethod)]
diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgb24.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgb24.cs
index 7fd63c676..3b5bdb3d5 100644
--- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgb24.cs
+++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgb24.cs
@@ -36,8 +36,8 @@ namespace SixLabors.ImageSharp.PixelFormats
[FieldOffset(2)]
public byte B;
- private static readonly Vector4 MaxBytes = new Vector4(byte.MaxValue);
- private static readonly Vector4 Half = new Vector4(0.5F);
+ private static readonly Vector4 MaxBytes = new(byte.MaxValue);
+ private static readonly Vector4 Half = new(0.5F);
///
/// Initializes a new instance of the struct.
diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgb48.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgb48.cs
index e3738b70c..d16b7db7a 100644
--- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgb48.cs
+++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgb48.cs
@@ -93,7 +93,7 @@ namespace SixLabors.ImageSharp.PixelFormats
///
[MethodImpl(InliningOptions.ShortMethod)]
- public readonly Vector4 ToVector4() => new Vector4(this.R / Max, this.G / Max, this.B / Max, 1F);
+ public readonly Vector4 ToVector4() => new(this.R / Max, this.G / Max, this.B / Max, 1F);
///
[MethodImpl(InliningOptions.ShortMethod)]
diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba1010102.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba1010102.cs
index dee2f9fcb..e68726018 100644
--- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba1010102.cs
+++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba1010102.cs
@@ -16,7 +16,7 @@ namespace SixLabors.ImageSharp.PixelFormats
///
public partial struct Rgba1010102 : IPixel, IPackedVector
{
- private static readonly Vector4 Multiplier = new Vector4(1023F, 1023F, 1023F, 3F);
+ private static readonly Vector4 Multiplier = new(1023F, 1023F, 1023F, 3F);
///
/// Initializes a new instance of the struct.
@@ -78,14 +78,11 @@ namespace SixLabors.ImageSharp.PixelFormats
///
[MethodImpl(InliningOptions.ShortMethod)]
- public readonly Vector4 ToVector4()
- {
- return new Vector4(
+ public readonly Vector4 ToVector4() => new Vector4(
(this.PackedValue >> 0) & 0x03FF,
(this.PackedValue >> 10) & 0x03FF,
(this.PackedValue >> 20) & 0x03FF,
(this.PackedValue >> 30) & 0x03) / Multiplier;
- }
///
[MethodImpl(InliningOptions.ShortMethod)]
@@ -129,10 +126,7 @@ namespace SixLabors.ImageSharp.PixelFormats
///
[MethodImpl(InliningOptions.ShortMethod)]
- public void ToRgba32(ref Rgba32 dest)
- {
- dest.FromScaledVector4(this.ToScaledVector4());
- }
+ public void ToRgba32(ref Rgba32 dest) => dest.FromScaledVector4(this.ToScaledVector4());
///
[MethodImpl(InliningOptions.ShortMethod)]
diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs
index 868165e9c..3dc6490f1 100644
--- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs
+++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs
@@ -44,8 +44,8 @@ namespace SixLabors.ImageSharp.PixelFormats
///
public byte A;
- private static readonly Vector4 MaxBytes = new Vector4(byte.MaxValue);
- private static readonly Vector4 Half = new Vector4(0.5F);
+ private static readonly Vector4 MaxBytes = new(byte.MaxValue);
+ private static readonly Vector4 Half = new(0.5F);
///
/// Initializes a new instance of the struct.
@@ -137,7 +137,7 @@ namespace SixLabors.ImageSharp.PixelFormats
public Rgb24 Rgb
{
[MethodImpl(InliningOptions.ShortMethod)]
- readonly get => new Rgb24(this.R, this.G, this.B);
+ readonly get => new(this.R, this.G, this.B);
[MethodImpl(InliningOptions.ShortMethod)]
set
@@ -154,7 +154,7 @@ namespace SixLabors.ImageSharp.PixelFormats
public Bgr24 Bgr
{
[MethodImpl(InliningOptions.ShortMethod)]
- readonly get => new Bgr24(this.R, this.G, this.B);
+ readonly get => new(this.R, this.G, this.B);
[MethodImpl(InliningOptions.ShortMethod)]
set
@@ -181,7 +181,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// The .
/// The .
[MethodImpl(InliningOptions.ShortMethod)]
- public static implicit operator Color(Rgba32 source) => new Color(source);
+ public static implicit operator Color(Rgba32 source) => new(source);
///
/// Converts a to .
@@ -393,10 +393,7 @@ namespace SixLabors.ImageSharp.PixelFormats
///
[MethodImpl(InliningOptions.ShortMethod)]
- public void ToRgba32(ref Rgba32 dest)
- {
- dest = this;
- }
+ public void ToRgba32(ref Rgba32 dest) => dest = this;
///
[MethodImpl(InliningOptions.ShortMethod)]
@@ -424,7 +421,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// A hexadecimal string representation of the value.
public readonly string ToHex()
{
- uint hexOrder = (uint)(this.A << 0 | this.B << 8 | this.G << 16 | this.R << 24);
+ uint hexOrder = (uint)((this.A << 0) | (this.B << 8) | (this.G << 16) | (this.R << 24));
return hexOrder.ToString("X8");
}
@@ -523,7 +520,7 @@ namespace SixLabors.ImageSharp.PixelFormats
return hex + "FF";
}
- if (hex.Length < 3 || hex.Length > 4)
+ if (hex.Length is < 3 or > 4)
{
return null;
}
diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs
index 9add3d718..4cfa0bf97 100644
--- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs
+++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs
@@ -162,7 +162,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// The .
/// The .
[MethodImpl(InliningOptions.ShortMethod)]
- public static implicit operator Color(Rgba64 source) => new Color(source);
+ public static implicit operator Color(Rgba64 source) => new(source);
///
/// Converts a to .
diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.cs b/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.cs
index 97e103d0f..cd6f53c4e 100644
--- a/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.cs
+++ b/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.cs
@@ -43,8 +43,8 @@ namespace SixLabors.ImageSharp.PixelFormats
public float A;
private const float MaxBytes = byte.MaxValue;
- private static readonly Vector4 Max = new Vector4(MaxBytes);
- private static readonly Vector4 Half = new Vector4(0.5F);
+ private static readonly Vector4 Max = new(MaxBytes);
+ private static readonly Vector4 Half = new(0.5F);
///
/// Initializes a new instance of the struct.
@@ -120,7 +120,7 @@ namespace SixLabors.ImageSharp.PixelFormats
///
[MethodImpl(InliningOptions.ShortMethod)]
- public readonly Vector4 ToVector4() => new Vector4(this.R, this.G, this.B, this.A);
+ public readonly Vector4 ToVector4() => new(this.R, this.G, this.B, this.A);
///
[MethodImpl(InliningOptions.ShortMethod)]
@@ -183,7 +183,7 @@ namespace SixLabors.ImageSharp.PixelFormats
// Hex is RRGGBBAA
Vector4 vector = this.ToVector4() * Max;
vector += Half;
- uint hexOrder = (uint)((byte)vector.W | (byte)vector.Z << 8 | (byte)vector.Y << 16 | (byte)vector.X << 24);
+ uint hexOrder = (uint)((byte)vector.W | ((byte)vector.Z << 8) | ((byte)vector.Y << 16) | ((byte)vector.X << 24));
return hexOrder.ToString("X8");
}
@@ -199,10 +199,7 @@ namespace SixLabors.ImageSharp.PixelFormats
&& this.A.Equals(other.A);
///
- public override readonly string ToString()
- {
- return FormattableString.Invariant($"RgbaVector({this.R:#0.##}, {this.G:#0.##}, {this.B:#0.##}, {this.A:#0.##})");
- }
+ public override readonly string ToString() => FormattableString.Invariant($"RgbaVector({this.R:#0.##}, {this.G:#0.##}, {this.B:#0.##}, {this.A:#0.##})");
///
public override readonly int GetHashCode() => HashCode.Combine(this.R, this.G, this.B, this.A);
diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Short2.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Short2.cs
index f7a4f9994..24f6b4d1d 100644
--- a/src/ImageSharp/PixelFormats/PixelImplementations/Short2.cs
+++ b/src/ImageSharp/PixelFormats/PixelImplementations/Short2.cs
@@ -21,8 +21,8 @@ namespace SixLabors.ImageSharp.PixelFormats
// Two's complement
private const float MinNeg = ~(int)MaxPos;
- private static readonly Vector2 Max = new Vector2(MaxPos);
- private static readonly Vector2 Min = new Vector2(MinNeg);
+ private static readonly Vector2 Max = new(MaxPos);
+ private static readonly Vector2 Min = new(MinNeg);
///
/// Initializes a new instance of the struct.
@@ -97,7 +97,7 @@ namespace SixLabors.ImageSharp.PixelFormats
///
[MethodImpl(InliningOptions.ShortMethod)]
- public readonly Vector4 ToVector4() => new Vector4((short)(this.PackedValue & 0xFFFF), (short)(this.PackedValue >> 0x10), 0, 1);
+ public readonly Vector4 ToVector4() => new((short)(this.PackedValue & 0xFFFF), (short)(this.PackedValue >> 0x10), 0, 1);
///
[MethodImpl(InliningOptions.ShortMethod)]
@@ -157,7 +157,7 @@ namespace SixLabors.ImageSharp.PixelFormats
///
/// The .
[MethodImpl(InliningOptions.ShortMethod)]
- public readonly Vector2 ToVector2() => new Vector2((short)(this.PackedValue & 0xFFFF), (short)(this.PackedValue >> 0x10));
+ public readonly Vector2 ToVector2() => new((short)(this.PackedValue & 0xFFFF), (short)(this.PackedValue >> 0x10));
///
public override readonly bool Equals(object obj) => obj is Short2 other && this.Equals(other);
@@ -181,8 +181,8 @@ namespace SixLabors.ImageSharp.PixelFormats
private static uint Pack(Vector2 vector)
{
vector = Vector2.Clamp(vector, Min, Max);
- uint word2 = (uint)Math.Round(vector.X) & 0xFFFF;
- uint word1 = ((uint)Math.Round(vector.Y) & 0xFFFF) << 0x10;
+ uint word2 = (uint)Convert.ToInt32(Math.Round(vector.X)) & 0xFFFF;
+ uint word1 = ((uint)Convert.ToInt32(Math.Round(vector.Y)) & 0xFFFF) << 0x10;
return word2 | word1;
}
diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Short4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Short4.cs
index 409f46c72..86a519297 100644
--- a/src/ImageSharp/PixelFormats/PixelImplementations/Short4.cs
+++ b/src/ImageSharp/PixelFormats/PixelImplementations/Short4.cs
@@ -186,10 +186,10 @@ namespace SixLabors.ImageSharp.PixelFormats
vector = Numerics.Clamp(vector, Min, Max);
// Clamp the value between min and max values
- ulong word4 = ((ulong)Math.Round(vector.X) & 0xFFFF) << 0x00;
- ulong word3 = ((ulong)Math.Round(vector.Y) & 0xFFFF) << 0x10;
- ulong word2 = ((ulong)Math.Round(vector.Z) & 0xFFFF) << 0x20;
- ulong word1 = ((ulong)Math.Round(vector.W) & 0xFFFF) << 0x30;
+ ulong word4 = ((ulong)Convert.ToInt32(Math.Round(vector.X)) & 0xFFFF) << 0x00;
+ ulong word3 = ((ulong)Convert.ToInt32(Math.Round(vector.Y)) & 0xFFFF) << 0x10;
+ ulong word2 = ((ulong)Convert.ToInt32(Math.Round(vector.Z)) & 0xFFFF) << 0x20;
+ ulong word1 = ((ulong)Convert.ToInt32(Math.Round(vector.W)) & 0xFFFF) << 0x30;
return word4 | word3 | word2 | word1;
}
diff --git a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs
index c5450538e..f748a4b57 100644
--- a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs
+++ b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs
@@ -181,11 +181,7 @@ namespace SixLabors.ImageSharp.PixelFormats
Guard.NotNull(configuration, nameof(configuration));
int count = redChannel.Length;
- Guard.IsTrue(greenChannel.Length == count, nameof(greenChannel), "Channels must be of same size!");
- Guard.IsTrue(blueChannel.Length == count, nameof(blueChannel), "Channels must be of same size!");
- Guard.IsTrue(destination.Length > count + 2, nameof(destination), "'destination' must contain a padding of 3 elements!");
-
- Guard.DestinationShouldNotBeTooShort(redChannel, destination, nameof(destination));
+ GuardPackFromRgbPlanes(greenChannel, blueChannel, destination, count);
Rgb24 rgb24 = default;
ref byte r = ref MemoryMarshal.GetReference(redChannel);
@@ -201,5 +197,13 @@ namespace SixLabors.ImageSharp.PixelFormats
Unsafe.Add(ref d, i).FromRgb24(rgb24);
}
}
+
+ [MethodImpl(InliningOptions.ShortMethod)]
+ internal static void GuardPackFromRgbPlanes(ReadOnlySpan greenChannel, ReadOnlySpan blueChannel, Span destination, int count)
+ {
+ Guard.IsTrue(greenChannel.Length == count, nameof(greenChannel), "Channels must be of same size!");
+ Guard.IsTrue(blueChannel.Length == count, nameof(blueChannel), "Channels must be of same size!");
+ Guard.IsTrue(destination.Length > count + 2, nameof(destination), "'destination' must contain a padding of 3 elements!");
+ }
}
}
diff --git a/src/ImageSharp/PixelFormats/Utils/Vector4Converters.cs b/src/ImageSharp/PixelFormats/Utils/Vector4Converters.cs
index 7af266276..8df7f2c03 100644
--- a/src/ImageSharp/PixelFormats/Utils/Vector4Converters.cs
+++ b/src/ImageSharp/PixelFormats/Utils/Vector4Converters.cs
@@ -4,7 +4,6 @@
using System;
using System.Numerics;
using System.Runtime.CompilerServices;
-
using SixLabors.ImageSharp.ColorSpaces.Companding;
namespace SixLabors.ImageSharp.PixelFormats.Utils
@@ -14,7 +13,7 @@ namespace SixLabors.ImageSharp.PixelFormats.Utils
///
/// Apply modifiers used requested by ToVector4() conversion.
///
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ [MethodImpl(InliningOptions.ShortMethod)]
internal static void ApplyForwardConversionModifiers(Span vectors, PixelConversionModifiers modifiers)
{
if (modifiers.IsDefined(PixelConversionModifiers.SRgbCompand))
@@ -31,7 +30,7 @@ namespace SixLabors.ImageSharp.PixelFormats.Utils
///
/// Apply modifiers used requested by FromVector4() conversion.
///
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ [MethodImpl(InliningOptions.ShortMethod)]
internal static void ApplyBackwardConversionModifiers(Span vectors, PixelConversionModifiers modifiers)
{
if (modifiers.IsDefined(PixelConversionModifiers.Premultiply))
diff --git a/src/ImageSharp/Primitives/LongRational.cs b/src/ImageSharp/Primitives/LongRational.cs
index 9f8eb9a1a..ec49a5b0f 100644
--- a/src/ImageSharp/Primitives/LongRational.cs
+++ b/src/ImageSharp/Primitives/LongRational.cs
@@ -223,4 +223,4 @@ namespace SixLabors.ImageSharp
return this;
}
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Primitives/Point.cs b/src/ImageSharp/Primitives/Point.cs
index 653ec1fe3..3e097d5fa 100644
--- a/src/ImageSharp/Primitives/Point.cs
+++ b/src/ImageSharp/Primitives/Point.cs
@@ -285,4 +285,4 @@ namespace SixLabors.ImageSharp
private static short LowInt16(int n) => unchecked((short)(n & 0xffff));
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Primitives/PointF.cs b/src/ImageSharp/Primitives/PointF.cs
index 848bfce4a..7c5703696 100644
--- a/src/ImageSharp/Primitives/PointF.cs
+++ b/src/ImageSharp/Primitives/PointF.cs
@@ -290,4 +290,4 @@ namespace SixLabors.ImageSharp
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(PointF other) => this.X.Equals(other.X) && this.Y.Equals(other.Y);
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Primitives/Rational.cs b/src/ImageSharp/Primitives/Rational.cs
index b6f83e277..b14681c69 100644
--- a/src/ImageSharp/Primitives/Rational.cs
+++ b/src/ImageSharp/Primitives/Rational.cs
@@ -43,7 +43,7 @@ namespace SixLabors.ImageSharp
{
if (simplify)
{
- var rational = new LongRational(numerator, denominator).Simplify();
+ LongRational rational = new LongRational(numerator, denominator).Simplify();
this.Numerator = (uint)rational.Numerator;
this.Denominator = (uint)rational.Denominator;
@@ -93,10 +93,7 @@ namespace SixLabors.ImageSharp
/// The first to compare.
/// The second to compare.
/// The
- public static bool operator ==(Rational left, Rational right)
- {
- return left.Equals(right);
- }
+ public static bool operator ==(Rational left, Rational right) => left.Equals(right);
///
/// Determines whether the specified instances are not considered equal.
@@ -104,10 +101,7 @@ namespace SixLabors.ImageSharp
/// The first to compare.
/// The second to compare.
/// The
- public static bool operator !=(Rational left, Rational right)
- {
- return !left.Equals(right);
- }
+ public static bool operator !=(Rational left, Rational right) => !left.Equals(right);
///
/// Converts the specified to an instance of this type.
@@ -116,10 +110,7 @@ namespace SixLabors.ImageSharp
///
/// The .
///
- public static Rational FromDouble(double value)
- {
- return new Rational(value, false);
- }
+ public static Rational FromDouble(double value) => new Rational(value, false);
///
/// Converts the specified to an instance of this type.
@@ -129,16 +120,10 @@ namespace SixLabors.ImageSharp
///
/// The .
///
- public static Rational FromDouble(double value, bool bestPrecision)
- {
- return new Rational(value, bestPrecision);
- }
+ public static Rational FromDouble(double value, bool bestPrecision) => new Rational(value, bestPrecision);
///
- public override bool Equals(object obj)
- {
- return obj is Rational other && this.Equals(other);
- }
+ public override bool Equals(object obj) => obj is Rational other && this.Equals(other);
///
public bool Equals(Rational other)
@@ -162,16 +147,18 @@ namespace SixLabors.ImageSharp
///
/// The .
///
- public double ToDouble()
- {
- return this.Numerator / (double)this.Denominator;
- }
+ public double ToDouble() => this.Numerator / (double)this.Denominator;
+
+ ///
+ /// Converts a rational number to the nearest .
+ ///
+ ///
+ /// The .
+ ///
+ public float ToSingle() => this.Numerator / (float)this.Denominator;
///
- public override string ToString()
- {
- return this.ToString(CultureInfo.InvariantCulture);
- }
+ public override string ToString() => this.ToString(CultureInfo.InvariantCulture);
///
/// Converts the numeric value of this instance to its equivalent string representation using
diff --git a/src/ImageSharp/Primitives/RectangleF.cs b/src/ImageSharp/Primitives/RectangleF.cs
index d050c5139..6cda81423 100644
--- a/src/ImageSharp/Primitives/RectangleF.cs
+++ b/src/ImageSharp/Primitives/RectangleF.cs
@@ -393,4 +393,4 @@ namespace SixLabors.ImageSharp
this.Width.Equals(other.Width) &&
this.Height.Equals(other.Height);
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Primitives/Size.cs b/src/ImageSharp/Primitives/Size.cs
index 0790a3dbd..adc78ca10 100644
--- a/src/ImageSharp/Primitives/Size.cs
+++ b/src/ImageSharp/Primitives/Size.cs
@@ -293,4 +293,4 @@ namespace SixLabors.ImageSharp
private static SizeF Multiply(Size size, float multiplier) =>
new SizeF(size.Width * multiplier, size.Height * multiplier);
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Primitives/SizeF.cs b/src/ImageSharp/Primitives/SizeF.cs
index b62aa8b0d..a35b6eea6 100644
--- a/src/ImageSharp/Primitives/SizeF.cs
+++ b/src/ImageSharp/Primitives/SizeF.cs
@@ -230,4 +230,4 @@ namespace SixLabors.ImageSharp
private static SizeF Multiply(SizeF size, float multiplier) =>
new SizeF(size.Width * multiplier, size.Height * multiplier);
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Primitives/ValueSize.cs b/src/ImageSharp/Primitives/ValueSize.cs
index 86d54e26d..ee173aba3 100644
--- a/src/ImageSharp/Primitives/ValueSize.cs
+++ b/src/ImageSharp/Primitives/ValueSize.cs
@@ -130,4 +130,4 @@ namespace SixLabors.ImageSharp
///
public override int GetHashCode() => HashCode.Combine(this.Value, this.Type);
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Processing/Extensions/Convolution/BoxBlurExtensions.cs b/src/ImageSharp/Processing/Extensions/Convolution/BoxBlurExtensions.cs
index 1f75838ab..f891ffa97 100644
--- a/src/ImageSharp/Processing/Extensions/Convolution/BoxBlurExtensions.cs
+++ b/src/ImageSharp/Processing/Extensions/Convolution/BoxBlurExtensions.cs
@@ -40,4 +40,4 @@ namespace SixLabors.ImageSharp.Processing
public static IImageProcessingContext BoxBlur(this IImageProcessingContext source, int radius, Rectangle rectangle)
=> source.ApplyProcessor(new BoxBlurProcessor(radius), rectangle);
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Processing/Extensions/Convolution/GaussianBlurExtensions.cs b/src/ImageSharp/Processing/Extensions/Convolution/GaussianBlurExtensions.cs
index 824094935..bd4fb716d 100644
--- a/src/ImageSharp/Processing/Extensions/Convolution/GaussianBlurExtensions.cs
+++ b/src/ImageSharp/Processing/Extensions/Convolution/GaussianBlurExtensions.cs
@@ -40,4 +40,4 @@ namespace SixLabors.ImageSharp.Processing
public static IImageProcessingContext GaussianBlur(this IImageProcessingContext source, float sigma, Rectangle rectangle)
=> source.ApplyProcessor(new GaussianBlurProcessor(sigma), rectangle);
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Processing/Extensions/Convolution/GaussianSharpenExtensions.cs b/src/ImageSharp/Processing/Extensions/Convolution/GaussianSharpenExtensions.cs
index 78044e958..f5b8798f4 100644
--- a/src/ImageSharp/Processing/Extensions/Convolution/GaussianSharpenExtensions.cs
+++ b/src/ImageSharp/Processing/Extensions/Convolution/GaussianSharpenExtensions.cs
@@ -43,4 +43,4 @@ namespace SixLabors.ImageSharp.Processing
Rectangle rectangle) =>
source.ApplyProcessor(new GaussianSharpenProcessor(sigma), rectangle);
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Processing/Extensions/Effects/OilPaintExtensions.cs b/src/ImageSharp/Processing/Extensions/Effects/OilPaintExtensions.cs
index 13d9bc349..3e2b744de 100644
--- a/src/ImageSharp/Processing/Extensions/Effects/OilPaintExtensions.cs
+++ b/src/ImageSharp/Processing/Extensions/Effects/OilPaintExtensions.cs
@@ -59,4 +59,4 @@ namespace SixLabors.ImageSharp.Processing
Rectangle rectangle) =>
source.ApplyProcessor(new OilPaintingProcessor(levels, brushSize), rectangle);
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Processing/Extensions/Effects/PixelateExtensions.cs b/src/ImageSharp/Processing/Extensions/Effects/PixelateExtensions.cs
index 5316c46cf..f00203382 100644
--- a/src/ImageSharp/Processing/Extensions/Effects/PixelateExtensions.cs
+++ b/src/ImageSharp/Processing/Extensions/Effects/PixelateExtensions.cs
@@ -42,4 +42,4 @@ namespace SixLabors.ImageSharp.Processing
Rectangle rectangle) =>
source.ApplyProcessor(new PixelateProcessor(size), rectangle);
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Processing/Extensions/Filters/BlackWhiteExtensions.cs b/src/ImageSharp/Processing/Extensions/Filters/BlackWhiteExtensions.cs
index 76861af1a..7fe784fde 100644
--- a/src/ImageSharp/Processing/Extensions/Filters/BlackWhiteExtensions.cs
+++ b/src/ImageSharp/Processing/Extensions/Filters/BlackWhiteExtensions.cs
@@ -30,4 +30,4 @@ namespace SixLabors.ImageSharp.Processing
public static IImageProcessingContext BlackWhite(this IImageProcessingContext source, Rectangle rectangle)
=> source.ApplyProcessor(new BlackWhiteProcessor(), rectangle);
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Processing/Extensions/Filters/ColorBlindnessExtensions.cs b/src/ImageSharp/Processing/Extensions/Filters/ColorBlindnessExtensions.cs
index d46e3b284..ccbc2d9ef 100644
--- a/src/ImageSharp/Processing/Extensions/Filters/ColorBlindnessExtensions.cs
+++ b/src/ImageSharp/Processing/Extensions/Filters/ColorBlindnessExtensions.cs
@@ -56,4 +56,4 @@ namespace SixLabors.ImageSharp.Processing
}
}
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Processing/Extensions/Filters/ContrastExtensions.cs b/src/ImageSharp/Processing/Extensions/Filters/ContrastExtensions.cs
index 01a346aac..a3896df67 100644
--- a/src/ImageSharp/Processing/Extensions/Filters/ContrastExtensions.cs
+++ b/src/ImageSharp/Processing/Extensions/Filters/ContrastExtensions.cs
@@ -40,4 +40,4 @@ namespace SixLabors.ImageSharp.Processing
public static IImageProcessingContext Contrast(this IImageProcessingContext source, float amount, Rectangle rectangle)
=> source.ApplyProcessor(new ContrastProcessor(amount), rectangle);
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Processing/Extensions/Filters/HueExtensions.cs b/src/ImageSharp/Processing/Extensions/Filters/HueExtensions.cs
index 59a46852d..9e62c3610 100644
--- a/src/ImageSharp/Processing/Extensions/Filters/HueExtensions.cs
+++ b/src/ImageSharp/Processing/Extensions/Filters/HueExtensions.cs
@@ -32,4 +32,4 @@ namespace SixLabors.ImageSharp.Processing
public static IImageProcessingContext Hue(this IImageProcessingContext source, float degrees, Rectangle rectangle)
=> source.ApplyProcessor(new HueProcessor(degrees), rectangle);
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Processing/Extensions/Filters/InvertExtensions.cs b/src/ImageSharp/Processing/Extensions/Filters/InvertExtensions.cs
index 03bfb2fa8..be7beea18 100644
--- a/src/ImageSharp/Processing/Extensions/Filters/InvertExtensions.cs
+++ b/src/ImageSharp/Processing/Extensions/Filters/InvertExtensions.cs
@@ -30,4 +30,4 @@ namespace SixLabors.ImageSharp.Processing
public static IImageProcessingContext Invert(this IImageProcessingContext source, Rectangle rectangle)
=> source.ApplyProcessor(new InvertProcessor(1F), rectangle);
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Processing/Extensions/Filters/OpacityExtensions.cs b/src/ImageSharp/Processing/Extensions/Filters/OpacityExtensions.cs
index 80d7d0c8a..44440e9c0 100644
--- a/src/ImageSharp/Processing/Extensions/Filters/OpacityExtensions.cs
+++ b/src/ImageSharp/Processing/Extensions/Filters/OpacityExtensions.cs
@@ -32,4 +32,4 @@ namespace SixLabors.ImageSharp.Processing
public static IImageProcessingContext Opacity(this IImageProcessingContext source, float amount, Rectangle rectangle)
=> source.ApplyProcessor(new OpacityProcessor(amount), rectangle);
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Processing/Extensions/Filters/SaturateExtensions.cs b/src/ImageSharp/Processing/Extensions/Filters/SaturateExtensions.cs
index b7d520be8..98eaf0d2f 100644
--- a/src/ImageSharp/Processing/Extensions/Filters/SaturateExtensions.cs
+++ b/src/ImageSharp/Processing/Extensions/Filters/SaturateExtensions.cs
@@ -40,4 +40,4 @@ namespace SixLabors.ImageSharp.Processing
public static IImageProcessingContext Saturate(this IImageProcessingContext source, float amount, Rectangle rectangle)
=> source.ApplyProcessor(new SaturateProcessor(amount), rectangle);
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Processing/Extensions/Filters/SepiaExtensions.cs b/src/ImageSharp/Processing/Extensions/Filters/SepiaExtensions.cs
index 8d818cb0b..759373cc0 100644
--- a/src/ImageSharp/Processing/Extensions/Filters/SepiaExtensions.cs
+++ b/src/ImageSharp/Processing/Extensions/Filters/SepiaExtensions.cs
@@ -51,4 +51,4 @@ namespace SixLabors.ImageSharp.Processing
public static IImageProcessingContext Sepia(this IImageProcessingContext source, float amount, Rectangle rectangle)
=> source.ApplyProcessor(new SepiaProcessor(amount), rectangle);
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Processing/Extensions/Normalization/HistogramEqualizationExtensions.cs b/src/ImageSharp/Processing/Extensions/Normalization/HistogramEqualizationExtensions.cs
index 175c7648a..a8ac3376a 100644
--- a/src/ImageSharp/Processing/Extensions/Normalization/HistogramEqualizationExtensions.cs
+++ b/src/ImageSharp/Processing/Extensions/Normalization/HistogramEqualizationExtensions.cs
@@ -29,4 +29,4 @@ namespace SixLabors.ImageSharp.Processing
HistogramEqualizationOptions options) =>
source.ApplyProcessor(HistogramEqualizationProcessor.FromOptions(options));
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Processing/Extensions/ProcessingExtensions.cs b/src/ImageSharp/Processing/Extensions/ProcessingExtensions.cs
index ac14d8423..1a005368e 100644
--- a/src/ImageSharp/Processing/Extensions/ProcessingExtensions.cs
+++ b/src/ImageSharp/Processing/Extensions/ProcessingExtensions.cs
@@ -2,7 +2,6 @@
// Licensed under the Apache License, Version 2.0.
using System;
-
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Processors;
diff --git a/src/ImageSharp/Processing/Extensions/Transforms/AutoOrientExtensions.cs b/src/ImageSharp/Processing/Extensions/Transforms/AutoOrientExtensions.cs
index 0011101e6..e67cb5617 100644
--- a/src/ImageSharp/Processing/Extensions/Transforms/AutoOrientExtensions.cs
+++ b/src/ImageSharp/Processing/Extensions/Transforms/AutoOrientExtensions.cs
@@ -19,4 +19,4 @@ namespace SixLabors.ImageSharp.Processing
public static IImageProcessingContext AutoOrient(this IImageProcessingContext source)
=> source.ApplyProcessor(new AutoOrientProcessor());
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Processing/Extensions/Transforms/CropExtensions.cs b/src/ImageSharp/Processing/Extensions/Transforms/CropExtensions.cs
index 5b62b226d..28f37308f 100644
--- a/src/ImageSharp/Processing/Extensions/Transforms/CropExtensions.cs
+++ b/src/ImageSharp/Processing/Extensions/Transforms/CropExtensions.cs
@@ -32,4 +32,4 @@ namespace SixLabors.ImageSharp.Processing
public static IImageProcessingContext Crop(this IImageProcessingContext source, Rectangle cropRectangle) =>
source.ApplyProcessor(new CropProcessor(cropRectangle, source.GetCurrentSize()));
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Processing/Extensions/Transforms/EntropyCropExtensions.cs b/src/ImageSharp/Processing/Extensions/Transforms/EntropyCropExtensions.cs
index 9324a6977..476a09f58 100644
--- a/src/ImageSharp/Processing/Extensions/Transforms/EntropyCropExtensions.cs
+++ b/src/ImageSharp/Processing/Extensions/Transforms/EntropyCropExtensions.cs
@@ -28,4 +28,4 @@ namespace SixLabors.ImageSharp.Processing
public static IImageProcessingContext EntropyCrop(this IImageProcessingContext source, float threshold) =>
source.ApplyProcessor(new EntropyCropProcessor(threshold));
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Processing/Extensions/Transforms/FlipExtensions.cs b/src/ImageSharp/Processing/Extensions/Transforms/FlipExtensions.cs
index 9f08ecaaf..6ab758120 100644
--- a/src/ImageSharp/Processing/Extensions/Transforms/FlipExtensions.cs
+++ b/src/ImageSharp/Processing/Extensions/Transforms/FlipExtensions.cs
@@ -20,4 +20,4 @@ namespace SixLabors.ImageSharp.Processing
public static IImageProcessingContext Flip(this IImageProcessingContext source, FlipMode flipMode)
=> source.ApplyProcessor(new FlipProcessor(flipMode));
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Processing/Extensions/Transforms/PadExtensions.cs b/src/ImageSharp/Processing/Extensions/Transforms/PadExtensions.cs
index 5b0614e79..8c3edcadf 100644
--- a/src/ImageSharp/Processing/Extensions/Transforms/PadExtensions.cs
+++ b/src/ImageSharp/Processing/Extensions/Transforms/PadExtensions.cs
@@ -39,4 +39,4 @@ namespace SixLabors.ImageSharp.Processing
return color.Equals(default) ? source.Resize(options) : source.Resize(options).BackgroundColor(color);
}
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Processing/Extensions/Transforms/RotateExtensions.cs b/src/ImageSharp/Processing/Extensions/Transforms/RotateExtensions.cs
index 4b2ee8144..359aadd82 100644
--- a/src/ImageSharp/Processing/Extensions/Transforms/RotateExtensions.cs
+++ b/src/ImageSharp/Processing/Extensions/Transforms/RotateExtensions.cs
@@ -42,4 +42,4 @@ namespace SixLabors.ImageSharp.Processing
IResampler sampler) =>
source.ApplyProcessor(new RotateProcessor(degrees, sampler, source.GetCurrentSize()));
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Processing/Extensions/Transforms/RotateFlipExtensions.cs b/src/ImageSharp/Processing/Extensions/Transforms/RotateFlipExtensions.cs
index f1e3823a0..4259a7578 100644
--- a/src/ImageSharp/Processing/Extensions/Transforms/RotateFlipExtensions.cs
+++ b/src/ImageSharp/Processing/Extensions/Transforms/RotateFlipExtensions.cs
@@ -19,4 +19,4 @@ namespace SixLabors.ImageSharp.Processing
public static IImageProcessingContext RotateFlip(this IImageProcessingContext source, RotateMode rotateMode, FlipMode flipMode)
=> source.Rotate(rotateMode).Flip(flipMode);
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Processing/Extensions/Transforms/SkewExtensions.cs b/src/ImageSharp/Processing/Extensions/Transforms/SkewExtensions.cs
index b3fc43dde..3a7df8d6c 100644
--- a/src/ImageSharp/Processing/Extensions/Transforms/SkewExtensions.cs
+++ b/src/ImageSharp/Processing/Extensions/Transforms/SkewExtensions.cs
@@ -37,4 +37,4 @@ namespace SixLabors.ImageSharp.Processing
IResampler sampler) =>
source.ApplyProcessor(new SkewProcessor(degreesX, degreesY, sampler, source.GetCurrentSize()));
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Processing/Extensions/Transforms/TransformExtensions.cs b/src/ImageSharp/Processing/Extensions/Transforms/TransformExtensions.cs
index 57acf78ee..56036edd0 100644
--- a/src/ImageSharp/Processing/Extensions/Transforms/TransformExtensions.cs
+++ b/src/ImageSharp/Processing/Extensions/Transforms/TransformExtensions.cs
@@ -2,7 +2,6 @@
// Licensed under the Apache License, Version 2.0.
using System.Numerics;
-
using SixLabors.ImageSharp.Processing.Processors.Transforms;
namespace SixLabors.ImageSharp.Processing
@@ -141,4 +140,4 @@ namespace SixLabors.ImageSharp.Processing
sourceRectangle);
}
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Processing/FlipMode.cs b/src/ImageSharp/Processing/FlipMode.cs
index 59e7e8a9c..2803d1b4d 100644
--- a/src/ImageSharp/Processing/FlipMode.cs
+++ b/src/ImageSharp/Processing/FlipMode.cs
@@ -23,4 +23,4 @@ namespace SixLabors.ImageSharp.Processing
///
Vertical,
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Processing/GrayscaleMode.cs b/src/ImageSharp/Processing/GrayscaleMode.cs
index 27b190d23..1a73afc82 100644
--- a/src/ImageSharp/Processing/GrayscaleMode.cs
+++ b/src/ImageSharp/Processing/GrayscaleMode.cs
@@ -18,4 +18,4 @@ namespace SixLabors.ImageSharp.Processing
///
Bt601
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Processing/KnownQuantizers.cs b/src/ImageSharp/Processing/KnownQuantizers.cs
index 9fc8cf543..28b77a455 100644
--- a/src/ImageSharp/Processing/KnownQuantizers.cs
+++ b/src/ImageSharp/Processing/KnownQuantizers.cs
@@ -31,4 +31,4 @@ namespace SixLabors.ImageSharp.Processing
///
public static IQuantizer Werner { get; } = new WernerPaletteQuantizer();
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Processing/Processors/Binarization/AdaptiveThresholdProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Binarization/AdaptiveThresholdProcessor{TPixel}.cs
index 6d95d51b3..254ba5a7e 100644
--- a/src/ImageSharp/Processing/Processors/Binarization/AdaptiveThresholdProcessor{TPixel}.cs
+++ b/src/ImageSharp/Processing/Processors/Binarization/AdaptiveThresholdProcessor{TPixel}.cs
@@ -4,7 +4,6 @@
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
-
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
diff --git a/src/ImageSharp/Processing/Processors/Convolution/Kernels/Implementation/LaplacianKernelFactory.cs b/src/ImageSharp/Processing/Processors/Convolution/Kernels/Implementation/LaplacianKernelFactory.cs
index 960ff30eb..286dcb326 100644
--- a/src/ImageSharp/Processing/Processors/Convolution/Kernels/Implementation/LaplacianKernelFactory.cs
+++ b/src/ImageSharp/Processing/Processors/Convolution/Kernels/Implementation/LaplacianKernelFactory.cs
@@ -28,4 +28,4 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
return kernel;
}
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Processing/Processors/Convolution/Kernels/Implementation/PrewittKernels.cs b/src/ImageSharp/Processing/Processors/Convolution/Kernels/Implementation/PrewittKernels.cs
index 67e52a8f1..108c66543 100644
--- a/src/ImageSharp/Processing/Processors/Convolution/Kernels/Implementation/PrewittKernels.cs
+++ b/src/ImageSharp/Processing/Processors/Convolution/Kernels/Implementation/PrewittKernels.cs
@@ -30,4 +30,4 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
{ -1, -1, -1 }
};
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Processing/Processors/Convolution/Kernels/Implementation/RobertsCrossKernels.cs b/src/ImageSharp/Processing/Processors/Convolution/Kernels/Implementation/RobertsCrossKernels.cs
index 40c811ca6..2fcdd31de 100644
--- a/src/ImageSharp/Processing/Processors/Convolution/Kernels/Implementation/RobertsCrossKernels.cs
+++ b/src/ImageSharp/Processing/Processors/Convolution/Kernels/Implementation/RobertsCrossKernels.cs
@@ -28,4 +28,4 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
{ -1, 0 }
};
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Processing/Processors/Convolution/Kernels/Implementation/ScharrKernels.cs b/src/ImageSharp/Processing/Processors/Convolution/Kernels/Implementation/ScharrKernels.cs
index 72c48b273..ff4f5902c 100644
--- a/src/ImageSharp/Processing/Processors/Convolution/Kernels/Implementation/ScharrKernels.cs
+++ b/src/ImageSharp/Processing/Processors/Convolution/Kernels/Implementation/ScharrKernels.cs
@@ -30,4 +30,4 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
{ -3, -10, -3 }
};
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Processing/Processors/Convolution/Kernels/Implementation/SobelKernels.cs b/src/ImageSharp/Processing/Processors/Convolution/Kernels/Implementation/SobelKernels.cs
index 333b275ba..6810a2ee3 100644
--- a/src/ImageSharp/Processing/Processors/Convolution/Kernels/Implementation/SobelKernels.cs
+++ b/src/ImageSharp/Processing/Processors/Convolution/Kernels/Implementation/SobelKernels.cs
@@ -30,4 +30,4 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
{ 1, 2, 1 }
};
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Processing/Processors/Dithering/ErrorDither.cs b/src/ImageSharp/Processing/Processors/Dithering/ErrorDither.cs
index 1a107c2cf..0fe2d4b2c 100644
--- a/src/ImageSharp/Processing/Processors/Dithering/ErrorDither.cs
+++ b/src/ImageSharp/Processing/Processors/Dithering/ErrorDither.cs
@@ -27,6 +27,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering
[MethodImpl(InliningOptions.ShortMethod)]
public ErrorDither(in DenseMatrix matrix, int offset)
{
+ Guard.MustBeGreaterThan(offset, 0, nameof(offset));
+
this.matrix = matrix;
this.offset = offset;
}
@@ -95,6 +97,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering
where TFrameQuantizer : struct, IQuantizer
where TPixel : unmanaged, IPixel
{
+ if (this == default)
+ {
+ ThrowDefaultInstance();
+ }
+
int offsetY = bounds.Top;
int offsetX = bounds.Left;
float scale = quantizer.Options.DitherScale;
@@ -122,6 +129,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering
where TPaletteDitherImageProcessor : struct, IPaletteDitherImageProcessor
where TPixel : unmanaged, IPixel
{
+ if (this == default)
+ {
+ ThrowDefaultInstance();
+ }
+
float scale = processor.DitherScale;
for (int y = bounds.Top; y < bounds.Bottom; y++)
{
@@ -210,5 +222,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering
///
public override int GetHashCode()
=> HashCode.Combine(this.offset, this.matrix);
+
+ [MethodImpl(InliningOptions.ColdPath)]
+ private static void ThrowDefaultInstance()
+ => throw new ImageProcessingException("Cannot use the default value type instance to dither.");
}
}
diff --git a/src/ImageSharp/Processing/Processors/Dithering/OrderedDither.cs b/src/ImageSharp/Processing/Processors/Dithering/OrderedDither.cs
index c317ddf02..2f5a5cf85 100644
--- a/src/ImageSharp/Processing/Processors/Dithering/OrderedDither.cs
+++ b/src/ImageSharp/Processing/Processors/Dithering/OrderedDither.cs
@@ -24,6 +24,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering
[MethodImpl(InliningOptions.ShortMethod)]
public OrderedDither(uint length)
{
+ Guard.MustBeGreaterThan(length, 0, nameof(length));
+
DenseMatrix ditherMatrix = OrderedDitherFactory.CreateDitherMatrix(length);
// Create a new matrix to run against, that pre-thresholds the values.
@@ -109,6 +111,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering
where TFrameQuantizer : struct, IQuantizer
where TPixel : unmanaged, IPixel
{
+ if (this == default)
+ {
+ ThrowDefaultInstance();
+ }
+
int spread = CalculatePaletteSpread(destination.Palette.Length);
float scale = quantizer.Options.DitherScale;
@@ -134,6 +141,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering
where TPaletteDitherImageProcessor : struct, IPaletteDitherImageProcessor
where TPixel : unmanaged, IPixel
{
+ if (this == default)
+ {
+ ThrowDefaultInstance();
+ }
+
int spread = CalculatePaletteSpread(processor.Palette.Length);
float scale = processor.DitherScale;
@@ -201,5 +213,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering
[MethodImpl(InliningOptions.ShortMethod)]
public override int GetHashCode()
=> HashCode.Combine(this.thresholdMatrix, this.modulusX, this.modulusY);
+
+ [MethodImpl(InliningOptions.ColdPath)]
+ private static void ThrowDefaultInstance()
+ => throw new ImageProcessingException("Cannot use the default value type instance to dither.");
}
}
diff --git a/src/ImageSharp/Processing/Processors/Filters/AchromatomalyProcessor.cs b/src/ImageSharp/Processing/Processors/Filters/AchromatomalyProcessor.cs
index 63326d299..74d926eac 100644
--- a/src/ImageSharp/Processing/Processors/Filters/AchromatomalyProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/Filters/AchromatomalyProcessor.cs
@@ -16,4 +16,4 @@ namespace SixLabors.ImageSharp.Processing.Processors.Filters
{
}
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Processing/Processors/Filters/BlackWhiteProcessor.cs b/src/ImageSharp/Processing/Processors/Filters/BlackWhiteProcessor.cs
index e5e556dc2..c3cc4ac50 100644
--- a/src/ImageSharp/Processing/Processors/Filters/BlackWhiteProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/Filters/BlackWhiteProcessor.cs
@@ -16,4 +16,4 @@ namespace SixLabors.ImageSharp.Processing.Processors.Filters
{
}
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Processing/Processors/Filters/BrightnessProcessor.cs b/src/ImageSharp/Processing/Processors/Filters/BrightnessProcessor.cs
index bc424e462..1bc1acc8e 100644
--- a/src/ImageSharp/Processing/Processors/Filters/BrightnessProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/Filters/BrightnessProcessor.cs
@@ -27,4 +27,4 @@ namespace SixLabors.ImageSharp.Processing.Processors.Filters
///
public float Amount { get; }
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Processing/Processors/Filters/ContrastProcessor.cs b/src/ImageSharp/Processing/Processors/Filters/ContrastProcessor.cs
index cc7385d4b..150cd35a4 100644
--- a/src/ImageSharp/Processing/Processors/Filters/ContrastProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/Filters/ContrastProcessor.cs
@@ -27,4 +27,4 @@ namespace SixLabors.ImageSharp.Processing.Processors.Filters
///
public float Amount { get; }
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Processing/Processors/Filters/DeuteranomalyProcessor.cs b/src/ImageSharp/Processing/Processors/Filters/DeuteranomalyProcessor.cs
index 3afef7b7e..5c1928484 100644
--- a/src/ImageSharp/Processing/Processors/Filters/DeuteranomalyProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/Filters/DeuteranomalyProcessor.cs
@@ -16,4 +16,4 @@ namespace SixLabors.ImageSharp.Processing.Processors.Filters
{
}
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Processing/Processors/Filters/DeuteranopiaProcessor.cs b/src/ImageSharp/Processing/Processors/Filters/DeuteranopiaProcessor.cs
index 9bd7f449b..eb25cfe8c 100644
--- a/src/ImageSharp/Processing/Processors/Filters/DeuteranopiaProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/Filters/DeuteranopiaProcessor.cs
@@ -16,4 +16,4 @@ namespace SixLabors.ImageSharp.Processing.Processors.Filters
{
}
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Processing/Processors/Filters/GrayscaleBt601Processor.cs b/src/ImageSharp/Processing/Processors/Filters/GrayscaleBt601Processor.cs
index f2c5e023d..b4b601cfc 100644
--- a/src/ImageSharp/Processing/Processors/Filters/GrayscaleBt601Processor.cs
+++ b/src/ImageSharp/Processing/Processors/Filters/GrayscaleBt601Processor.cs
@@ -23,4 +23,4 @@ namespace SixLabors.ImageSharp.Processing.Processors.Filters
///
public float Amount { get; }
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Processing/Processors/Filters/GrayscaleBt709Processor.cs b/src/ImageSharp/Processing/Processors/Filters/GrayscaleBt709Processor.cs
index ace25f1fb..8ef5219f3 100644
--- a/src/ImageSharp/Processing/Processors/Filters/GrayscaleBt709Processor.cs
+++ b/src/ImageSharp/Processing/Processors/Filters/GrayscaleBt709Processor.cs
@@ -23,4 +23,4 @@ namespace SixLabors.ImageSharp.Processing.Processors.Filters
///
public float Amount { get; }
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Processing/Processors/Filters/HueProcessor.cs b/src/ImageSharp/Processing/Processors/Filters/HueProcessor.cs
index 2ff99009a..d8bc2a2d8 100644
--- a/src/ImageSharp/Processing/Processors/Filters/HueProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/Filters/HueProcessor.cs
@@ -23,4 +23,4 @@ namespace SixLabors.ImageSharp.Processing.Processors.Filters
///
public float Degrees { get; }
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Processing/Processors/Filters/InvertProcessor.cs b/src/ImageSharp/Processing/Processors/Filters/InvertProcessor.cs
index 95937e5b3..a47be636c 100644
--- a/src/ImageSharp/Processing/Processors/Filters/InvertProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/Filters/InvertProcessor.cs
@@ -23,4 +23,4 @@ namespace SixLabors.ImageSharp.Processing.Processors.Filters
///
public float Amount { get; }
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Processing/Processors/Filters/KodachromeProcessor.cs b/src/ImageSharp/Processing/Processors/Filters/KodachromeProcessor.cs
index fa9cc0874..c5be144c7 100644
--- a/src/ImageSharp/Processing/Processors/Filters/KodachromeProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/Filters/KodachromeProcessor.cs
@@ -16,4 +16,4 @@ namespace SixLabors.ImageSharp.Processing.Processors.Filters
{
}
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Processing/Processors/Filters/OpacityProcessor.cs b/src/ImageSharp/Processing/Processors/Filters/OpacityProcessor.cs
index 0ccdfafbd..260699bc2 100644
--- a/src/ImageSharp/Processing/Processors/Filters/OpacityProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/Filters/OpacityProcessor.cs
@@ -23,4 +23,4 @@ namespace SixLabors.ImageSharp.Processing.Processors.Filters
///
public float Amount { get; }
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Processing/Processors/Filters/ProtanomalyProcessor.cs b/src/ImageSharp/Processing/Processors/Filters/ProtanomalyProcessor.cs
index 0e8f571f5..e2faf9433 100644
--- a/src/ImageSharp/Processing/Processors/Filters/ProtanomalyProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/Filters/ProtanomalyProcessor.cs
@@ -16,4 +16,4 @@ namespace SixLabors.ImageSharp.Processing.Processors.Filters
{
}
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Processing/Processors/Filters/ProtanopiaProcessor.cs b/src/ImageSharp/Processing/Processors/Filters/ProtanopiaProcessor.cs
index 59735a28c..2d63f6626 100644
--- a/src/ImageSharp/Processing/Processors/Filters/ProtanopiaProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/Filters/ProtanopiaProcessor.cs
@@ -16,4 +16,4 @@ namespace SixLabors.ImageSharp.Processing.Processors.Filters
{
}
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Processing/Processors/Filters/SaturateProcessor.cs b/src/ImageSharp/Processing/Processors/Filters/SaturateProcessor.cs
index 051c4ca6b..1ac381884 100644
--- a/src/ImageSharp/Processing/Processors/Filters/SaturateProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/Filters/SaturateProcessor.cs
@@ -27,4 +27,4 @@ namespace SixLabors.ImageSharp.Processing.Processors.Filters
///
public float Amount { get; }
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Processing/Processors/Filters/SepiaProcessor.cs b/src/ImageSharp/Processing/Processors/Filters/SepiaProcessor.cs
index 8a0780e46..dec0b8dfe 100644
--- a/src/ImageSharp/Processing/Processors/Filters/SepiaProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/Filters/SepiaProcessor.cs
@@ -23,4 +23,4 @@ namespace SixLabors.ImageSharp.Processing.Processors.Filters
///
public float Amount { get; }
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Processing/Processors/Filters/TritanomalyProcessor.cs b/src/ImageSharp/Processing/Processors/Filters/TritanomalyProcessor.cs
index bb031d0ef..22c274ac3 100644
--- a/src/ImageSharp/Processing/Processors/Filters/TritanomalyProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/Filters/TritanomalyProcessor.cs
@@ -16,4 +16,4 @@ namespace SixLabors.ImageSharp.Processing.Processors.Filters
{
}
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Processing/Processors/Filters/TritanopiaProcessor.cs b/src/ImageSharp/Processing/Processors/Filters/TritanopiaProcessor.cs
index 926fd70c5..1dbc3d3f4 100644
--- a/src/ImageSharp/Processing/Processors/Filters/TritanopiaProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/Filters/TritanopiaProcessor.cs
@@ -16,4 +16,4 @@ namespace SixLabors.ImageSharp.Processing.Processors.Filters
{
}
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistogramEqualizationProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistogramEqualizationProcessor{TPixel}.cs
index 91ed9f5de..883f85be3 100644
--- a/src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistogramEqualizationProcessor{TPixel}.cs
+++ b/src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistogramEqualizationProcessor{TPixel}.cs
@@ -70,7 +70,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization
{
cdfData.CalculateLookupTables(source, this);
- var tileYStartPositions = new List<(int y, int cdfY)>();
+ var tileYStartPositions = new List<(int Y, int CdfY)>();
int cdfY = 0;
int yStart = halfTileHeight;
for (int tile = 0; tile < tileCount - 1; tile++)
@@ -367,7 +367,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization
private readonly struct RowIntervalOperation : IRowIntervalOperation
{
private readonly CdfTileData cdfData;
- private readonly List<(int y, int cdfY)> tileYStartPositions;
+ private readonly List<(int Y, int CdfY)> tileYStartPositions;
private readonly int tileWidth;
private readonly int tileHeight;
private readonly int tileCount;
@@ -380,7 +380,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization
[MethodImpl(InliningOptions.ShortMethod)]
public RowIntervalOperation(
CdfTileData cdfData,
- List<(int y, int cdfY)> tileYStartPositions,
+ List<(int Y, int CdfY)> tileYStartPositions,
int tileWidth,
int tileHeight,
int tileCount,
@@ -406,9 +406,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization
{
for (int index = rows.Min; index < rows.Max; index++)
{
- (int y, int cdfY) tileYStartPosition = this.tileYStartPositions[index];
- int y = tileYStartPosition.y;
- int cdfYY = tileYStartPosition.cdfY;
+ (int Y, int CdfY) tileYStartPosition = this.tileYStartPositions[index];
+ int y = tileYStartPosition.Y;
+ int cdfYY = tileYStartPosition.CdfY;
int cdfX = 0;
int x = this.halfTileWidth;
@@ -473,7 +473,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization
private readonly int tileWidth;
private readonly int tileHeight;
private readonly int luminanceLevels;
- private readonly List<(int y, int cdfY)> tileYStartPositions;
+ private readonly List<(int Y, int CdfY)> tileYStartPositions;
public CdfTileData(
Configuration configuration,
@@ -496,7 +496,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization
this.pixelsInTile = tileWidth * tileHeight;
// Calculate the start positions and rent buffers.
- this.tileYStartPositions = new List<(int y, int cdfY)>();
+ this.tileYStartPositions = new List<(int Y, int CdfY)>();
int cdfY = 0;
for (int y = 0; y < sourceHeight; y += tileHeight)
{
@@ -556,7 +556,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization
private readonly MemoryAllocator allocator;
private readonly Buffer2D cdfMinBuffer2D;
private readonly Buffer2D cdfLutBuffer2D;
- private readonly List<(int y, int cdfY)> tileYStartPositions;
+ private readonly List<(int Y, int CdfY)> tileYStartPositions;
private readonly int tileWidth;
private readonly int tileHeight;
private readonly int luminanceLevels;
@@ -570,7 +570,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization
MemoryAllocator allocator,
Buffer2D cdfMinBuffer2D,
Buffer2D cdfLutBuffer2D,
- List<(int y, int cdfY)> tileYStartPositions,
+ List<(int Y, int CdfY)> tileYStartPositions,
int tileWidth,
int tileHeight,
int luminanceLevels,
@@ -596,8 +596,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization
for (int index = rows.Min; index < rows.Max; index++)
{
int cdfX = 0;
- int cdfY = this.tileYStartPositions[index].cdfY;
- int y = this.tileYStartPositions[index].y;
+ int cdfY = this.tileYStartPositions[index].CdfY;
+ int y = this.tileYStartPositions[index].Y;
int endY = Math.Min(y + this.tileHeight, this.sourceHeight);
Span cdfMinSpan = this.cdfMinBuffer2D.GetRowSpan(cdfY);
cdfMinSpan.Clear();
diff --git a/src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistogramEqualizationSlidingWindowProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistogramEqualizationSlidingWindowProcessor{TPixel}.cs
index b9383e331..f17e0d1e4 100644
--- a/src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistogramEqualizationSlidingWindowProcessor{TPixel}.cs
+++ b/src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistogramEqualizationSlidingWindowProcessor{TPixel}.cs
@@ -7,7 +7,6 @@ using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
-
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
@@ -257,7 +256,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization
[MethodImpl(InliningOptions.ShortMethod)]
private void AddPixelsToHistogram(ref Vector4 greyValuesBase, ref int histogramBase, int luminanceLevels, int length)
{
- for (int idx = 0; idx < length; idx++)
+ for (nint idx = 0; idx < length; idx++)
{
int luminance = ColorNumerics.GetBT709Luminance(ref Unsafe.Add(ref greyValuesBase, idx), luminanceLevels);
Unsafe.Add(ref histogramBase, luminance)++;
diff --git a/src/ImageSharp/Processing/Processors/Normalization/HistogramEqualizationProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Normalization/HistogramEqualizationProcessor{TPixel}.cs
index 9227cb0c0..92d36b412 100644
--- a/src/ImageSharp/Processing/Processors/Normalization/HistogramEqualizationProcessor{TPixel}.cs
+++ b/src/ImageSharp/Processing/Processors/Normalization/HistogramEqualizationProcessor{TPixel}.cs
@@ -4,7 +4,6 @@
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
-
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Processing.Processors.Normalization
diff --git a/src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer.cs b/src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer.cs
index 861697594..c1b695f65 100644
--- a/src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer.cs
+++ b/src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer.cs
@@ -11,14 +11,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
///
public class OctreeQuantizer : IQuantizer
{
- private static readonly QuantizerOptions DefaultOptions = new QuantizerOptions();
-
///
/// Initializes a new instance of the class
/// using the default .
///
public OctreeQuantizer()
- : this(DefaultOptions)
+ : this(new QuantizerOptions())
{
}
diff --git a/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer.cs b/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer.cs
index 4f73f4ac8..5da674cc9 100644
--- a/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer.cs
+++ b/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer.cs
@@ -11,7 +11,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
///
public class PaletteQuantizer : IQuantizer
{
- private static readonly QuantizerOptions DefaultOptions = new QuantizerOptions();
private readonly ReadOnlyMemory colorPalette;
///
@@ -19,7 +18,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
///
/// The color palette.
public PaletteQuantizer(ReadOnlyMemory palette)
- : this(palette, DefaultOptions)
+ : this(palette, new QuantizerOptions())
{
}
diff --git a/src/ImageSharp/Processing/Processors/Quantization/WebSafePaletteQuantizer.cs b/src/ImageSharp/Processing/Processors/Quantization/WebSafePaletteQuantizer.cs
index 5dda17dc6..e717152f9 100644
--- a/src/ImageSharp/Processing/Processors/Quantization/WebSafePaletteQuantizer.cs
+++ b/src/ImageSharp/Processing/Processors/Quantization/WebSafePaletteQuantizer.cs
@@ -1,8 +1,6 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
-using SixLabors.ImageSharp.Processing.Processors.Dithering;
-
namespace SixLabors.ImageSharp.Processing.Processors.Quantization
{
///
@@ -10,13 +8,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
///
public class WebSafePaletteQuantizer : PaletteQuantizer
{
- private static readonly QuantizerOptions DefaultOptions = new QuantizerOptions();
-
///
/// Initializes a new instance of the class.
///
public WebSafePaletteQuantizer()
- : this(DefaultOptions)
+ : this(new QuantizerOptions())
{
}
diff --git a/src/ImageSharp/Processing/Processors/Quantization/WernerPaletteQuantizer.cs b/src/ImageSharp/Processing/Processors/Quantization/WernerPaletteQuantizer.cs
index 6675263df..8a96f8ecc 100644
--- a/src/ImageSharp/Processing/Processors/Quantization/WernerPaletteQuantizer.cs
+++ b/src/ImageSharp/Processing/Processors/Quantization/WernerPaletteQuantizer.cs
@@ -9,13 +9,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
///
public class WernerPaletteQuantizer : PaletteQuantizer
{
- private static readonly QuantizerOptions DefaultOptions = new QuantizerOptions();
-
///
/// Initializes a new instance of the class.
///
public WernerPaletteQuantizer()
- : this(DefaultOptions)
+ : this(new QuantizerOptions())
{
}
diff --git a/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer.cs b/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer.cs
index 95adb7e5d..337948bef 100644
--- a/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer.cs
+++ b/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer.cs
@@ -10,14 +10,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
///
public class WuQuantizer : IQuantizer
{
- private static readonly QuantizerOptions DefaultOptions = new QuantizerOptions();
-
///
/// Initializes a new instance of the class
/// using the default .
///
public WuQuantizer()
- : this(DefaultOptions)
+ : this(new QuantizerOptions())
{
}
diff --git a/src/ImageSharp/Processing/Processors/Transforms/Linear/AutoOrientProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Transforms/Linear/AutoOrientProcessor{TPixel}.cs
index 3a06f5c2c..6c5219b3a 100644
--- a/src/ImageSharp/Processing/Processors/Transforms/Linear/AutoOrientProcessor{TPixel}.cs
+++ b/src/ImageSharp/Processing/Processors/Transforms/Linear/AutoOrientProcessor{TPixel}.cs
@@ -2,7 +2,6 @@
// Licensed under the Apache License, Version 2.0.
using System;
-
using SixLabors.ImageSharp.Metadata.Profiles.Exif;
using SixLabors.ImageSharp.PixelFormats;
diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeHelper.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeHelper.cs
index 5ff82a096..9a540559f 100644
--- a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeHelper.cs
+++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeHelper.cs
@@ -30,7 +30,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
///
/// The tuple representing the location and the bounds
///
- public static (Size, Rectangle) CalculateTargetLocationAndBounds(Size sourceSize, ResizeOptions options)
+ public static (Size Size, Rectangle Rectangle) CalculateTargetLocationAndBounds(Size sourceSize, ResizeOptions options)
{
int width = options.Size.Width;
int height = options.Size.Height;
@@ -76,7 +76,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
}
}
- private static (Size, Rectangle) CalculateBoxPadRectangle(
+ private static (Size Size, Rectangle Rectangle) CalculateBoxPadRectangle(
Size source,
ResizeOptions options,
int width,
@@ -150,7 +150,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
return CalculatePadRectangle(source, options, width, height);
}
- private static (Size, Rectangle) CalculateCropRectangle(
+ private static (Size Size, Rectangle Rectangle) CalculateCropRectangle(
Size source,
ResizeOptions options,
int width,
@@ -256,7 +256,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
return (new Size(Sanitize(width), Sanitize(height)), new Rectangle(targetX, targetY, Sanitize(targetWidth), Sanitize(targetHeight)));
}
- private static (Size, Rectangle) CalculateMaxRectangle(
+ private static (Size Size, Rectangle Rectangle) CalculateMaxRectangle(
Size source,
int width,
int height)
@@ -285,7 +285,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
return (new Size(Sanitize(targetWidth), Sanitize(targetHeight)), new Rectangle(0, 0, Sanitize(targetWidth), Sanitize(targetHeight)));
}
- private static (Size, Rectangle) CalculateMinRectangle(
+ private static (Size Size, Rectangle Rectangle) CalculateMinRectangle(
Size source,
int width,
int height)
@@ -333,7 +333,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
return (new Size(Sanitize(targetWidth), Sanitize(targetHeight)), new Rectangle(0, 0, Sanitize(targetWidth), Sanitize(targetHeight)));
}
- private static (Size, Rectangle) CalculatePadRectangle(
+ private static (Size Size, Rectangle Rectangle) CalculatePadRectangle(
Size sourceSize,
ResizeOptions options,
int width,
@@ -401,7 +401,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
return (new Size(Sanitize(width), Sanitize(height)), new Rectangle(targetX, targetY, Sanitize(targetWidth), Sanitize(targetHeight)));
}
- private static (Size, Rectangle) CalculateManualRectangle(
+ private static (Size Size, Rectangle Rectangle) CalculateManualRectangle(
ResizeOptions options,
int width,
int height)
diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs
index a58c20f68..9cc468060 100644
--- a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs
+++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs
@@ -216,7 +216,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
ResizeKernel kernel = this.CreateKernel(dataRowIndex, left, right);
- Span kernelValues = this.tempValues.AsSpan().Slice(0, kernel.Length);
+ Span kernelValues = this.tempValues.AsSpan(0, kernel.Length);
double sum = 0;
for (int j = left; j <= right; j++)
diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor{TPixel}.cs
index ec238608e..1b93d01a1 100644
--- a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor{TPixel}.cs
+++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor{TPixel}.cs
@@ -4,6 +4,7 @@
using System;
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Advanced;
+using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
@@ -187,6 +188,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
bool compand,
bool premultiplyAlpha)
{
+ PixelAlphaRepresentation? alphaRepresentation = PixelOperations.Instance.GetPixelTypeInfo()?.AlphaRepresentation;
+
+ // Premultiply only if alpha representation is unknown or Unassociated:
+ bool needsPremultiplication = alphaRepresentation == null || alphaRepresentation.Value == PixelAlphaRepresentation.Unassociated;
+ premultiplyAlpha &= needsPremultiplication;
PixelConversionModifiers conversionModifiers = GetModifiers(compand, premultiplyAlpha);
Buffer2DRegion sourceRegion = source.PixelBuffer.GetRegion(sourceRectangle);
diff --git a/src/ImageSharp/Processing/RotateMode.cs b/src/ImageSharp/Processing/RotateMode.cs
index 9a738d990..66fbc1a85 100644
--- a/src/ImageSharp/Processing/RotateMode.cs
+++ b/src/ImageSharp/Processing/RotateMode.cs
@@ -28,4 +28,4 @@ namespace SixLabors.ImageSharp.Processing
///
Rotate270 = 270
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Processing/TaperCorner.cs b/src/ImageSharp/Processing/TaperCorner.cs
index b44fcadbe..07e4957d4 100644
--- a/src/ImageSharp/Processing/TaperCorner.cs
+++ b/src/ImageSharp/Processing/TaperCorner.cs
@@ -23,4 +23,4 @@ namespace SixLabors.ImageSharp.Processing
///
Both
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Processing/TaperSide.cs b/src/ImageSharp/Processing/TaperSide.cs
index 209f5bf6d..47fe9858e 100644
--- a/src/ImageSharp/Processing/TaperSide.cs
+++ b/src/ImageSharp/Processing/TaperSide.cs
@@ -28,4 +28,4 @@ namespace SixLabors.ImageSharp.Processing
///
Bottom
}
-}
\ No newline at end of file
+}
diff --git a/tests/ImageSharp.Benchmarks/Codecs/DecodeTiff.cs b/tests/ImageSharp.Benchmarks/Codecs/DecodeTiff.cs
index e77bb8b3e..db94fb121 100644
--- a/tests/ImageSharp.Benchmarks/Codecs/DecodeTiff.cs
+++ b/tests/ImageSharp.Benchmarks/Codecs/DecodeTiff.cs
@@ -6,12 +6,9 @@
//// #define BIG_TESTS
using System.IO;
-
using BenchmarkDotNet.Attributes;
-
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Tests;
-
using SDImage = System.Drawing.Image;
using SDSize = System.Drawing.Size;
@@ -26,8 +23,6 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs
private byte[] data;
- private Configuration configuration;
-
#if BIG_TESTS
private static readonly int BufferSize = 1024 * 68;
@@ -61,16 +56,6 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs
public string TestImage { get; set; }
#endif
- [GlobalSetup]
- public void Config()
- {
- if (this.configuration == null)
- {
- this.configuration = new Configuration();
- this.configuration.StreamProcessingBufferSize = BufferSize;
- }
- }
-
[IterationSetup]
public void ReadImages()
{
@@ -95,7 +80,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs
public Size TiffCore()
{
using (var ms = new MemoryStream(this.data))
- using (var image = Image.Load(this.configuration, ms))
+ using (var image = Image.Load(ms))
{
return image.Size();
}
diff --git a/tests/ImageSharp.Benchmarks/Codecs/DecodeWebp.cs b/tests/ImageSharp.Benchmarks/Codecs/DecodeWebp.cs
new file mode 100644
index 000000000..878929823
--- /dev/null
+++ b/tests/ImageSharp.Benchmarks/Codecs/DecodeWebp.cs
@@ -0,0 +1,104 @@
+// Copyright (c) Six Labors.
+// Licensed under the Apache License, Version 2.0.
+
+using System.IO;
+using BenchmarkDotNet.Attributes;
+
+using ImageMagick;
+using SixLabors.ImageSharp.Formats.Webp;
+using SixLabors.ImageSharp.PixelFormats;
+using SixLabors.ImageSharp.Tests;
+
+namespace SixLabors.ImageSharp.Benchmarks.Codecs
+{
+ [MarkdownExporter]
+ [HtmlExporter]
+ [Config(typeof(Config.ShortMultiFramework))]
+ public class DecodeWebp
+ {
+ private Configuration configuration;
+
+ private byte[] webpLossyBytes;
+
+ private byte[] webpLosslessBytes;
+
+ private string TestImageLossyFullPath => Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, this.TestImageLossy);
+
+ private string TestImageLosslessFullPath => Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, this.TestImageLossless);
+
+ [Params(TestImages.Webp.Lossy.Earth)]
+ public string TestImageLossy { get; set; }
+
+ [Params(TestImages.Webp.Lossless.Earth)]
+ public string TestImageLossless { get; set; }
+
+ [GlobalSetup]
+ public void ReadImages()
+ {
+ this.configuration = Configuration.CreateDefaultInstance();
+ new WebpConfigurationModule().Configure(this.configuration);
+
+ this.webpLossyBytes ??= File.ReadAllBytes(this.TestImageLossyFullPath);
+ this.webpLosslessBytes ??= File.ReadAllBytes(this.TestImageLosslessFullPath);
+ }
+
+ [Benchmark(Description = "Magick Lossy Webp")]
+ public int WebpLossyMagick()
+ {
+ var settings = new MagickReadSettings { Format = MagickFormat.WebP };
+ using var memoryStream = new MemoryStream(this.webpLossyBytes);
+ using var image = new MagickImage(memoryStream, settings);
+ return image.Width;
+ }
+
+ [Benchmark(Description = "ImageSharp Lossy Webp")]
+ public int WebpLossy()
+ {
+ using var memoryStream = new MemoryStream(this.webpLossyBytes);
+ using var image = Image.Load(this.configuration, memoryStream);
+ return image.Height;
+ }
+
+ [Benchmark(Description = "Magick Lossless Webp")]
+ public int WebpLosslessMagick()
+ {
+ var settings = new MagickReadSettings { Format = MagickFormat.WebP };
+ using var memoryStream = new MemoryStream(this.webpLossyBytes);
+ using var image = new MagickImage(memoryStream, settings);
+ return image.Width;
+ }
+
+ [Benchmark(Description = "ImageSharp Lossless Webp")]
+ public int WebpLossless()
+ {
+ using var memoryStream = new MemoryStream(this.webpLosslessBytes);
+ using var image = Image.Load(this.configuration, memoryStream);
+ return image.Height;
+ }
+
+ /* Results 04.11.2021
+ * BenchmarkDotNet=v0.13.0, OS=Windows 10.0.19043.1320 (21H1/May2021Update)
+ Intel Core i7-6700K CPU 4.00GHz (Skylake), 1 CPU, 8 logical and 4 physical cores
+ .NET SDK=6.0.100-rc.2.21505.57
+ [Host] : .NET 5.0.11 (5.0.1121.47308), X64 RyuJIT
+ Job-WQLXJO : .NET 5.0.11 (5.0.1121.47308), X64 RyuJIT
+ Job-OJJAMD : .NET Core 3.1.20 (CoreCLR 4.700.21.47003, CoreFX 4.700.21.47101), X64 RyuJIT
+ Job-OMFOAS : .NET Framework 4.8 (4.8.4420.0), X64 RyuJIT
+
+ | Method | Job | Runtime | Arguments | TestImageLossy | TestImageLossless | Mean | Error | StdDev | Gen 0 | Gen 1 | Gen 2 | Allocated |
+ |--------------------------- |----------- |--------------------- |---------------------- |---------------------- |------------------------- |-----------:|----------:|--------:|---------:|------:|------:|----------:|
+ | 'Magick Lossy Webp' | Job-HLWZLL | .NET 5.0 | /p:DebugType=portable | Webp/earth_lossy.webp | Webp/earth_lossless.webp | 107.9 ms | 28.91 ms | 1.58 ms | - | - | - | 25 KB |
+ | 'ImageSharp Lossy Webp' | Job-HLWZLL | .NET 5.0 | /p:DebugType=portable | Webp/earth_lossy.webp | Webp/earth_lossless.webp | 282.3 ms | 25.40 ms | 1.39 ms | 500.0000 | - | - | 2,428 KB |
+ | 'Magick Lossless Webp' | Job-HLWZLL | .NET 5.0 | /p:DebugType=portable | Webp/earth_lossy.webp | Webp/earth_lossless.webp | 106.3 ms | 11.99 ms | 0.66 ms | - | - | - | 16 KB |
+ | 'ImageSharp Lossless Webp' | Job-HLWZLL | .NET 5.0 | /p:DebugType=portable | Webp/earth_lossy.webp | Webp/earth_lossless.webp | 280.2 ms | 6.21 ms | 0.34 ms | - | - | - | 2,092 KB |
+ | 'Magick Lossy Webp' | Job-ALQPDS | .NET Core 3.1 | Default | Webp/earth_lossy.webp | Webp/earth_lossless.webp | 106.2 ms | 9.32 ms | 0.51 ms | - | - | - | 15 KB |
+ | 'ImageSharp Lossy Webp' | Job-ALQPDS | .NET Core 3.1 | Default | Webp/earth_lossy.webp | Webp/earth_lossless.webp | 295.8 ms | 21.25 ms | 1.16 ms | 500.0000 | - | - | 2,427 KB |
+ | 'Magick Lossless Webp' | Job-ALQPDS | .NET Core 3.1 | Default | Webp/earth_lossy.webp | Webp/earth_lossless.webp | 106.5 ms | 4.07 ms | 0.22 ms | - | - | - | 15 KB |
+ | 'ImageSharp Lossless Webp' | Job-ALQPDS | .NET Core 3.1 | Default | Webp/earth_lossy.webp | Webp/earth_lossless.webp | 464.0 ms | 55.70 ms | 3.05 ms | - | - | - | 2,090 KB |
+ | 'Magick Lossy Webp' | Job-RYVVNN | .NET Framework 4.7.2 | Default | Webp/earth_lossy.webp | Webp/earth_lossless.webp | 108.0 ms | 29.60 ms | 1.62 ms | - | - | - | 32 KB |
+ | 'ImageSharp Lossy Webp' | Job-RYVVNN | .NET Framework 4.7.2 | Default | Webp/earth_lossy.webp | Webp/earth_lossless.webp | 564.9 ms | 29.69 ms | 1.63 ms | - | - | - | 2,436 KB |
+ | 'Magick Lossless Webp' | Job-RYVVNN | .NET Framework 4.7.2 | Default | Webp/earth_lossy.webp | Webp/earth_lossless.webp | 106.2 ms | 4.74 ms | 0.26 ms | - | - | - | 18 KB |
+ | 'ImageSharp Lossless Webp' | Job-RYVVNN | .NET Framework 4.7.2 | Default | Webp/earth_lossy.webp | Webp/earth_lossless.webp | 1,767.5 ms | 106.33 ms | 5.83 ms | - | - | - | 9,729 KB |
+ */
+ }
+}
diff --git a/tests/ImageSharp.Benchmarks/Codecs/EncodeTga.cs b/tests/ImageSharp.Benchmarks/Codecs/EncodeTga.cs
index 0e320e4a7..e7b102547 100644
--- a/tests/ImageSharp.Benchmarks/Codecs/EncodeTga.cs
+++ b/tests/ImageSharp.Benchmarks/Codecs/EncodeTga.cs
@@ -13,7 +13,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs
public class EncodeTga
{
private MagickImage tgaMagick;
- private Image tgaCore;
+ private Image tga;
private string TestImageFullPath
=> Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, this.TestImage);
@@ -24,9 +24,9 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs
[GlobalSetup]
public void ReadImages()
{
- if (this.tgaCore == null)
+ if (this.tga == null)
{
- this.tgaCore = Image.Load(this.TestImageFullPath);
+ this.tga = Image.Load(this.TestImageFullPath);
this.tgaMagick = new MagickImage(this.TestImageFullPath);
}
}
@@ -34,23 +34,23 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs
[GlobalCleanup]
public void Cleanup()
{
- this.tgaCore.Dispose();
- this.tgaCore = null;
+ this.tga.Dispose();
+ this.tga = null;
this.tgaMagick.Dispose();
}
[Benchmark(Baseline = true, Description = "Magick Tga")]
- public void TgaMagick()
+ public void MagickTga()
{
using var memoryStream = new MemoryStream();
this.tgaMagick.Write(memoryStream, MagickFormat.Tga);
}
[Benchmark(Description = "ImageSharp Tga")]
- public void TgaImageSharp()
+ public void ImageSharpTga()
{
using var memoryStream = new MemoryStream();
- this.tgaCore.SaveAsTga(memoryStream);
+ this.tga.SaveAsTga(memoryStream);
}
}
}
diff --git a/tests/ImageSharp.Benchmarks/Codecs/EncodeTiff.cs b/tests/ImageSharp.Benchmarks/Codecs/EncodeTiff.cs
index 025412adc..e9c61e729 100644
--- a/tests/ImageSharp.Benchmarks/Codecs/EncodeTiff.cs
+++ b/tests/ImageSharp.Benchmarks/Codecs/EncodeTiff.cs
@@ -3,7 +3,6 @@
using System.Drawing.Imaging;
using System.IO;
-
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.Formats.Tiff;
@@ -73,12 +72,6 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs
{
TiffPhotometricInterpretation photometricInterpretation = TiffPhotometricInterpretation.Rgb;
- // Workaround for 1-bit bug
- if (this.Compression == TiffCompression.CcittGroup3Fax || this.Compression == TiffCompression.Ccitt1D)
- {
- photometricInterpretation = TiffPhotometricInterpretation.WhiteIsZero;
- }
-
var encoder = new TiffEncoder() { Compression = this.Compression, PhotometricInterpretation = photometricInterpretation };
using var memoryStream = new MemoryStream();
this.core.SaveAsTiff(memoryStream, encoder);
diff --git a/tests/ImageSharp.Benchmarks/Codecs/EncodeWebp.cs b/tests/ImageSharp.Benchmarks/Codecs/EncodeWebp.cs
new file mode 100644
index 000000000..43d8c464c
--- /dev/null
+++ b/tests/ImageSharp.Benchmarks/Codecs/EncodeWebp.cs
@@ -0,0 +1,143 @@
+// Copyright (c) Six Labors.
+// Licensed under the Apache License, Version 2.0.
+
+using System.IO;
+using BenchmarkDotNet.Attributes;
+using ImageMagick;
+using ImageMagick.Formats;
+using SixLabors.ImageSharp.Formats.Webp;
+using SixLabors.ImageSharp.PixelFormats;
+using SixLabors.ImageSharp.Tests;
+
+namespace SixLabors.ImageSharp.Benchmarks.Codecs
+{
+ [MarkdownExporter]
+ [HtmlExporter]
+ [Config(typeof(Config.ShortMultiFramework))]
+ public class EncodeWebp
+ {
+ private MagickImage webpMagick;
+ private Image webp;
+
+ private string TestImageFullPath => Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, this.TestImage);
+
+ [Params(TestImages.Png.Bike)] // The bike image will have all 3 transforms as lossless webp.
+ public string TestImage { get; set; }
+
+ [GlobalSetup]
+ public void ReadImages()
+ {
+ if (this.webp == null)
+ {
+ this.webp = Image.Load(this.TestImageFullPath);
+ this.webpMagick = new MagickImage(this.TestImageFullPath);
+ }
+ }
+
+ [GlobalCleanup]
+ public void Cleanup()
+ {
+ this.webp.Dispose();
+ this.webpMagick.Dispose();
+ }
+
+ [Benchmark(Description = "Magick Webp Lossy")]
+ public void MagickWebpLossy()
+ {
+ using var memoryStream = new MemoryStream();
+
+ var defines = new WebPWriteDefines
+ {
+ Lossless = false,
+ Method = 4,
+ AlphaCompression = WebPAlphaCompression.None,
+ FilterStrength = 60,
+ SnsStrength = 50,
+ Pass = 1,
+
+ // 100 means off.
+ NearLossless = 100
+ };
+
+ this.webpMagick.Quality = 75;
+ this.webpMagick.Write(memoryStream, defines);
+ }
+
+ [Benchmark(Description = "ImageSharp Webp Lossy")]
+ public void ImageSharpWebpLossy()
+ {
+ using var memoryStream = new MemoryStream();
+ this.webp.Save(memoryStream, new WebpEncoder()
+ {
+ FileFormat = WebpFileFormatType.Lossy,
+ Method = WebpEncodingMethod.Level4,
+ UseAlphaCompression = false,
+ FilterStrength = 60,
+ SpatialNoiseShaping = 50,
+ EntropyPasses = 1
+ });
+ }
+
+ [Benchmark(Baseline = true, Description = "Magick Webp Lossless")]
+ public void MagickWebpLossless()
+ {
+ using var memoryStream = new MemoryStream();
+ var defines = new WebPWriteDefines
+ {
+ Lossless = true,
+ Method = 4,
+
+ // 100 means off.
+ NearLossless = 100
+ };
+
+ this.webpMagick.Quality = 75;
+ this.webpMagick.Write(memoryStream, defines);
+ }
+
+ [Benchmark(Description = "ImageSharp Webp Lossless")]
+ public void ImageSharpWebpLossless()
+ {
+ using var memoryStream = new MemoryStream();
+ this.webp.Save(memoryStream, new WebpEncoder()
+ {
+ FileFormat = WebpFileFormatType.Lossless,
+ Method = WebpEncodingMethod.Level4,
+ NearLossless = false,
+
+ // This is equal to exact = false in libwebp, which is the default.
+ TransparentColorMode = WebpTransparentColorMode.Clear
+ });
+ }
+
+ /* Results 04.11.2021
+ * Summary *
+ BenchmarkDotNet=v0.13.0, OS=Windows 10.0.19043.1320 (21H1/May2021Update)
+ Intel Core i7-6700K CPU 4.00GHz (Skylake), 1 CPU, 8 logical and 4 physical cores
+ .NET SDK=6.0.100-rc.2.21505.57
+ [Host] : .NET 5.0.11 (5.0.1121.47308), X64 RyuJIT
+ Job-WQLXJO : .NET 5.0.11 (5.0.1121.47308), X64 RyuJIT
+ Job-OJJAMD : .NET Core 3.1.20 (CoreCLR 4.700.21.47003, CoreFX 4.700.21.47101), X64 RyuJIT
+ Job-OMFOAS : .NET Framework 4.8 (4.8.4420.0), X64 RyuJIT
+
+ IterationCount=3 LaunchCount=1 WarmupCount=3
+
+ | Method | Job | Runtime | Arguments | TestImage | Mean | Error | StdDev | Ratio | RatioSD | Gen 0 | Gen 1 | Gen 2 | Allocated |
+ |--------------------------- |----------- |--------------------- |---------------------- |------------- |----------:|----------:|---------:|------:|--------:|------------:|----------:|----------:|-----------:|
+ | 'Magick Webp Lossy' | Job-WQLXJO | .NET 5.0 | /p:DebugType=portable | Png/Bike.png | 23.33 ms | 1.491 ms | 0.082 ms | 0.15 | 0.00 | - | - | - | 67 KB |
+ | 'ImageSharp Webp Lossy' | Job-WQLXJO | .NET 5.0 | /p:DebugType=portable | Png/Bike.png | 245.80 ms | 24.288 ms | 1.331 ms | 1.53 | 0.01 | 135000.0000 | - | - | 552,713 KB |
+ | 'Magick Webp Lossless' | Job-WQLXJO | .NET 5.0 | /p:DebugType=portable | Png/Bike.png | 160.36 ms | 11.131 ms | 0.610 ms | 1.00 | 0.00 | - | - | - | 518 KB |
+ | 'ImageSharp Webp Lossless' | Job-WQLXJO | .NET 5.0 | /p:DebugType=portable | Png/Bike.png | 313.93 ms | 45.605 ms | 2.500 ms | 1.96 | 0.01 | 34000.0000 | 5000.0000 | 2000.0000 | 161,670 KB |
+ | | | | | | | | | | | | | | |
+ | 'Magick Webp Lossy' | Job-OJJAMD | .NET Core 3.1 | Default | Png/Bike.png | 23.36 ms | 2.289 ms | 0.125 ms | 0.15 | 0.00 | - | - | - | 67 KB |
+ | 'ImageSharp Webp Lossy' | Job-OJJAMD | .NET Core 3.1 | Default | Png/Bike.png | 254.64 ms | 19.620 ms | 1.075 ms | 1.59 | 0.00 | 135000.0000 | - | - | 552,713 KB |
+ | 'Magick Webp Lossless' | Job-OJJAMD | .NET Core 3.1 | Default | Png/Bike.png | 160.30 ms | 9.549 ms | 0.523 ms | 1.00 | 0.00 | - | - | - | 518 KB |
+ | 'ImageSharp Webp Lossless' | Job-OJJAMD | .NET Core 3.1 | Default | Png/Bike.png | 320.35 ms | 22.924 ms | 1.257 ms | 2.00 | 0.01 | 34000.0000 | 5000.0000 | 2000.0000 | 161,669 KB |
+ | | | | | | | | | | | | | | |
+ | 'Magick Webp Lossy' | Job-OMFOAS | .NET Framework 4.7.2 | Default | Png/Bike.png | 23.37 ms | 0.908 ms | 0.050 ms | 0.15 | 0.00 | - | - | - | 68 KB |
+ | 'ImageSharp Webp Lossy' | Job-OMFOAS | .NET Framework 4.7.2 | Default | Png/Bike.png | 378.67 ms | 25.540 ms | 1.400 ms | 2.36 | 0.01 | 135000.0000 | - | - | 554,351 KB |
+ | 'Magick Webp Lossless' | Job-OMFOAS | .NET Framework 4.7.2 | Default | Png/Bike.png | 160.13 ms | 5.115 ms | 0.280 ms | 1.00 | 0.00 | - | - | - | 520 KB |
+ | 'ImageSharp Webp Lossless' | Job-OMFOAS | .NET Framework 4.7.2 | Default | Png/Bike.png | 379.01 ms | 71.192 ms | 3.902 ms | 2.37 | 0.02 | 34000.0000 | 5000.0000 | 2000.0000 | 162,119 KB |
+ */
+ }
+}
diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo1x1.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo1x1.cs
index bb7d08e22..1bd7329f6 100644
--- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo1x1.cs
+++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo1x1.cs
@@ -5,14 +5,11 @@ 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;
#endif
-
using BenchmarkDotNet.Attributes;
-
using SixLabors.ImageSharp.Formats.Jpeg.Components;
// ReSharper disable InconsistentNaming
@@ -319,26 +316,28 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg.BlockOperations
{
int stride = Width;
fixed (float* d = this.unpinnedBuffer)
- fixed (Block8x8F* ss = &this.block)
{
- var s = (float*)ss;
- Vector256 v0 = Avx.LoadVector256(s);
- Vector256 v1 = Avx.LoadVector256(s + 8);
- Vector256 v2 = Avx.LoadVector256(s + (8 * 2));
- Vector256 v3 = Avx.LoadVector256(s + (8 * 3));
- Avx.Store(d, v0);
- Avx.Store(d + stride, v1);
- Avx.Store(d + (stride * 2), v2);
- Avx.Store(d + (stride * 3), v3);
-
- v0 = Avx.LoadVector256(s + (8 * 4));
- v1 = Avx.LoadVector256(s + (8 * 5));
- v2 = Avx.LoadVector256(s + (8 * 6));
- v3 = Avx.LoadVector256(s + (8 * 7));
- Avx.Store(d + (stride * 4), v0);
- Avx.Store(d + (stride * 5), v1);
- Avx.Store(d + (stride * 6), v2);
- Avx.Store(d + (stride * 7), v3);
+ fixed (Block8x8F* ss = &this.block)
+ {
+ var s = (float*)ss;
+ Vector256 v0 = Avx.LoadVector256(s);
+ Vector256 v1 = Avx.LoadVector256(s + 8);
+ Vector256 v2 = Avx.LoadVector256(s + (8 * 2));
+ Vector256 v3 = Avx.LoadVector256(s + (8 * 3));
+ Avx.Store(d, v0);
+ Avx.Store(d + stride, v1);
+ Avx.Store(d + (stride * 2), v2);
+ Avx.Store(d + (stride * 3), v3);
+
+ v0 = Avx.LoadVector256(s + (8 * 4));
+ v1 = Avx.LoadVector256(s + (8 * 5));
+ v2 = Avx.LoadVector256(s + (8 * 6));
+ v3 = Avx.LoadVector256(s + (8 * 7));
+ Avx.Store(d + (stride * 4), v0);
+ Avx.Store(d + (stride * 5), v1);
+ Avx.Store(d + (stride * 6), v2);
+ Avx.Store(d + (stride * 7), v3);
+ }
}
}
diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo2x2.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo2x2.cs
index d915cbef0..5398eb6ac 100644
--- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo2x2.cs
+++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo2x2.cs
@@ -3,7 +3,6 @@
using System.Numerics;
using System.Runtime.CompilerServices;
-
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.Formats.Jpeg.Components;
diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_DivideRound.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_DivideRound.cs
index 574a08000..80388069f 100644
--- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_DivideRound.cs
+++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_DivideRound.cs
@@ -3,7 +3,6 @@
using System.Numerics;
using System.Runtime.CompilerServices;
-
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.Formats.Jpeg.Components;
diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_LoadFromInt16.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_LoadFromInt16.cs
index 167e93691..3ee63cdcf 100644
--- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_LoadFromInt16.cs
+++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_LoadFromInt16.cs
@@ -3,7 +3,6 @@
using System;
using System.Numerics;
-
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.Formats.Jpeg.Components;
diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_Quantize.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_Quantize.cs
new file mode 100644
index 000000000..898bbdb45
--- /dev/null
+++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_Quantize.cs
@@ -0,0 +1,50 @@
+// Copyright (c) Six Labors.
+// Licensed under the Apache License, Version 2.0.
+
+using BenchmarkDotNet.Attributes;
+using SixLabors.ImageSharp.Formats.Jpeg.Components;
+
+namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg.BlockOperations
+{
+ [Config(typeof(Config.HwIntrinsics_SSE_AVX))]
+ public class Block8x8F_Quantize
+ {
+ private Block8x8F block = CreateFromScalar(1);
+ private Block8x8F quant = CreateFromScalar(1);
+ private Block8x8 result = default;
+
+ [Benchmark]
+ public short Quantize()
+ {
+ Block8x8F.Quantize(ref this.block, ref this.result, ref this.quant);
+ return this.result[0];
+ }
+
+ private static Block8x8F CreateFromScalar(float scalar)
+ {
+ Block8x8F block = default;
+ for (int i = 0; i < 64; i++)
+ {
+ block[i] = scalar;
+ }
+
+ return block;
+ }
+ }
+}
+
+/*
+BenchmarkDotNet=v0.13.0, OS=Windows 10.0.19042.1165 (20H2/October2020Update)
+Intel Core i7-6700K CPU 4.00GHz (Skylake), 1 CPU, 8 logical and 4 physical cores
+.NET SDK=6.0.100-preview.3.21202.5
+ [Host] : .NET Core 3.1.18 (CoreCLR 4.700.21.35901, CoreFX 4.700.21.36305), X64 RyuJIT
+ 1. No HwIntrinsics : .NET Core 3.1.18 (CoreCLR 4.700.21.35901, CoreFX 4.700.21.36305), X64 RyuJIT
+ 2. SSE : .NET Core 3.1.18 (CoreCLR 4.700.21.35901, CoreFX 4.700.21.36305), X64 RyuJIT
+ 3. AVX : .NET Core 3.1.18 (CoreCLR 4.700.21.35901, CoreFX 4.700.21.36305), X64 RyuJIT
+
+| Method | Job | Mean | Error | StdDev | Ratio |
+|--------- |-----------------|---------:|---------:|---------:|------:|
+| Quantize | No HwIntrinsics | 73.34 ns | 1.081 ns | 1.011 ns | 1.00 |
+| Quantize | SSE | 24.11 ns | 0.298 ns | 0.279 ns | 0.33 |
+| Quantize | AVX | 15.90 ns | 0.074 ns | 0.065 ns | 0.22 |
+ */
diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_Round.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_Round.cs
index 0a6a1d97e..6ce1242a5 100644
--- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_Round.cs
+++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_Round.cs
@@ -5,12 +5,10 @@ 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;
#endif
-
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.Formats.Jpeg.Components;
diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_Transpose.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_Transpose.cs
index 1d103cd1a..c2efb517a 100644
--- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_Transpose.cs
+++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_Transpose.cs
@@ -9,29 +9,44 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg.BlockOperations
[Config(typeof(Config.HwIntrinsics_SSE_AVX))]
public class Block8x8F_Transpose
{
- private static readonly Block8x8F Source = Create8x8FloatData();
+ private Block8x8F source = Create8x8FloatData();
[Benchmark]
- public void TransposeInto()
+ public float TransposeInplace()
{
- var dest = default(Block8x8F);
- Source.TransposeInto(ref dest);
+ this.source.TransposeInplace();
+ return this.source[0];
}
private static Block8x8F Create8x8FloatData()
{
- var result = new float[64];
+ Block8x8F block = default;
for (int i = 0; i < 8; i++)
{
for (int j = 0; j < 8; j++)
{
- result[(i * 8) + j] = (i * 10) + j;
+ block[(i * 8) + j] = (i * 10) + j;
}
}
- var source = default(Block8x8F);
- source.LoadFrom(result);
- return source;
+ return block;
}
}
}
+
+/*
+BenchmarkDotNet=v0.13.0, OS=Windows 10.0.19042.1237 (20H2/October2020Update)
+Intel Core i7-6700K CPU 4.00GHz (Skylake), 1 CPU, 8 logical and 4 physical cores
+.NET SDK=6.0.100-preview.3.21202.5
+ [Host] : .NET Core 3.1.18 (CoreCLR 4.700.21.35901, CoreFX 4.700.21.36305), X64 RyuJIT
+ 1. No HwIntrinsics : .NET Core 3.1.18 (CoreCLR 4.700.21.35901, CoreFX 4.700.21.36305), X64 RyuJIT
+ 2. SSE : .NET Core 3.1.18 (CoreCLR 4.700.21.35901, CoreFX 4.700.21.36305), X64 RyuJIT
+ 3. AVX : .NET Core 3.1.18 (CoreCLR 4.700.21.35901, CoreFX 4.700.21.36305), X64 RyuJIT
+
+Runtime=.NET Core 3.1
+
+| Method | Job | Mean | Error | StdDev | Ratio |
+|----------------- |----------------:|----------:|----------:|----------:|------:|
+| TransposeInplace | No HwIntrinsics | 12.531 ns | 0.0637 ns | 0.0565 ns | 1.00 |
+| TransposeInplace | AVX | 5.767 ns | 0.0529 ns | 0.0495 ns | 0.46 |
+*/
diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/CmykColorConversion.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/CmykColorConversion.cs
index d17882adf..490beec6f 100644
--- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/CmykColorConversion.cs
+++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/CmykColorConversion.cs
@@ -19,7 +19,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg
{
var values = new JpegColorConverter.ComponentValues(this.Input, 0);
- new JpegColorConverter.FromCmykBasic(8).ConvertToRgba(values, this.Output);
+ new JpegColorConverter.FromCmykBasic(8).ConvertToRgbInplace(values);
}
[Benchmark]
@@ -27,7 +27,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg
{
var values = new JpegColorConverter.ComponentValues(this.Input, 0);
- new JpegColorConverter.FromCmykVector8(8).ConvertToRgba(values, this.Output);
+ new JpegColorConverter.FromCmykVector8(8).ConvertToRgbInplace(values);
}
[Benchmark]
@@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg
{
var values = new JpegColorConverter.ComponentValues(this.Input, 0);
- new JpegColorConverter.FromCmykAvx2(8).ConvertToRgba(values, this.Output);
+ new JpegColorConverter.FromCmykAvx2(8).ConvertToRgbInplace(values);
}
}
}
diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversionBenchmark.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversionBenchmark.cs
index e93ad474b..caed0e4e5 100644
--- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversionBenchmark.cs
+++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversionBenchmark.cs
@@ -19,13 +19,10 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg
protected Buffer2D[] Input { get; private set; }
- protected Vector4[] Output { get; private set; }
-
[GlobalSetup]
public void Setup()
{
this.Input = CreateRandomValues(this.componentCount, Count);
- this.Output = new Vector4[Count];
}
[GlobalCleanup]
diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpegParseStreamOnly.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpegParseStreamOnly.cs
index 68a102e3c..9db666c37 100644
--- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpegParseStreamOnly.cs
+++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpegParseStreamOnly.cs
@@ -4,6 +4,7 @@
using System.IO;
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.Formats.Jpeg;
+using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder;
using SixLabors.ImageSharp.IO;
using SixLabors.ImageSharp.Tests;
using SDSize = System.Drawing.Size;
@@ -39,21 +40,46 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg
using var bufferedStream = new BufferedReadStream(Configuration.Default, memoryStream);
var decoder = new JpegDecoderCore(Configuration.Default, new JpegDecoder { IgnoreMetadata = true });
- decoder.ParseStream(bufferedStream);
+ var scanDecoder = new HuffmanScanDecoder(bufferedStream, new NoopSpectralConverter(), cancellationToken: default);
+ decoder.ParseStream(bufferedStream, scanDecoder, cancellationToken: default);
decoder.Dispose();
}
- }
- /*
- | Method | Job | Runtime | TestImage | Mean | Error | StdDev | Ratio | Gen 0 | Gen 1 | Gen 2 | Allocated |
- |---------------------------- |----------- |-------------- |--------------------- |---------:|----------:|----------:|------:|--------:|------:|------:|----------:|
- | 'System.Drawing FULL' | Job-HITJFX | .NET 4.7.2 | Jpg/b(...)e.jpg [21] | 5.828 ms | 0.9885 ms | 0.0542 ms | 1.00 | 46.8750 | - | - | 211566 B |
- | JpegDecoderCore.ParseStream | Job-HITJFX | .NET 4.7.2 | Jpg/b(...)e.jpg [21] | 5.833 ms | 0.2923 ms | 0.0160 ms | 1.00 | - | - | - | 12416 B |
- | | | | | | | | | | | | |
- | 'System.Drawing FULL' | Job-WPSKZD | .NET Core 2.1 | Jpg/b(...)e.jpg [21] | 6.018 ms | 2.1374 ms | 0.1172 ms | 1.00 | 46.8750 | - | - | 210768 B |
- | JpegDecoderCore.ParseStream | Job-WPSKZD | .NET Core 2.1 | Jpg/b(...)e.jpg [21] | 4.382 ms | 0.9009 ms | 0.0494 ms | 0.73 | - | - | - | 12360 B |
- | | | | | | | | | | | | |
- | 'System.Drawing FULL' | Job-ZLSNRP | .NET Core 3.1 | Jpg/b(...)e.jpg [21] | 5.714 ms | 0.4078 ms | 0.0224 ms | 1.00 | - | - | - | 176 B |
- | JpegDecoderCore.ParseStream | Job-ZLSNRP | .NET Core 3.1 | Jpg/b(...)e.jpg [21] | 4.239 ms | 1.0943 ms | 0.0600 ms | 0.74 | - | - | - | 12406 B |
- */
+ // We want to test only stream parsing and scan decoding, we don't need to convert spectral data to actual pixels
+ // Nor we need to allocate final pixel buffer
+ // Note: this still introduces virtual method call overhead for baseline interleaved images
+ // There's no way to eliminate it as spectral conversion is built into the scan decoding loop for memory footprint reduction
+ private class NoopSpectralConverter : SpectralConverter
+ {
+ public override void ConvertStrideBaseline()
+ {
+ }
+
+ public override void InjectFrameData(JpegFrame frame, IRawJpegData jpegData)
+ {
+ }
+ }
+ }
}
+
+/*
+BenchmarkDotNet=v0.13.0, OS=Windows 10.0.19042.1083 (20H2/October2020Update)
+Intel Core i7-6700K CPU 4.00GHz (Skylake), 1 CPU, 8 logical and 4 physical cores
+.NET SDK=6.0.100-preview.3.21202.5
+ [Host] : .NET Core 3.1.13 (CoreCLR 4.700.21.11102, CoreFX 4.700.21.11602), X64 RyuJIT
+ Job-VAJCIU : .NET Core 2.1.26 (CoreCLR 4.6.29812.02, CoreFX 4.6.29812.01), X64 RyuJIT
+ Job-INPXCR : .NET Core 3.1.13 (CoreCLR 4.700.21.11102, CoreFX 4.700.21.11602), X64 RyuJIT
+ Job-JRCLOJ : .NET Framework 4.8 (4.8.4390.0), X64 RyuJIT
+
+IterationCount=3 LaunchCount=1 WarmupCount=3
+| Method | Job | Runtime | TestImage | Mean | Error | StdDev | Ratio | Gen 0 | Gen 1 | Gen 2 | Allocated |
+|---------------------------- |----------- |--------------------- |---------------------- |---------:|----------:|----------:|------:|--------:|------:|------:|----------:|
+| 'System.Drawing FULL' | Job-VAJCIU | .NET Core 2.1 | Jpg/baseline/Lake.jpg | 5.196 ms | 0.7520 ms | 0.0412 ms | 1.00 | 46.8750 | - | - | 210,768 B |
+| JpegDecoderCore.ParseStream | Job-VAJCIU | .NET Core 2.1 | Jpg/baseline/Lake.jpg | 3.467 ms | 0.0784 ms | 0.0043 ms | 0.67 | - | - | - | 12,416 B |
+| | | | | | | | | | | | |
+| 'System.Drawing FULL' | Job-INPXCR | .NET Core 3.1 | Jpg/baseline/Lake.jpg | 5.201 ms | 0.4105 ms | 0.0225 ms | 1.00 | - | - | - | 183 B |
+| JpegDecoderCore.ParseStream | Job-INPXCR | .NET Core 3.1 | Jpg/baseline/Lake.jpg | 3.349 ms | 0.0468 ms | 0.0026 ms | 0.64 | - | - | - | 12,408 B |
+| | | | | | | | | | | | |
+| 'System.Drawing FULL' | Job-JRCLOJ | .NET Framework 4.7.2 | Jpg/baseline/Lake.jpg | 5.164 ms | 0.6524 ms | 0.0358 ms | 1.00 | 46.8750 | - | - | 211,571 B |
+| JpegDecoderCore.ParseStream | Job-JRCLOJ | .NET Framework 4.7.2 | Jpg/baseline/Lake.jpg | 4.548 ms | 0.3357 ms | 0.0184 ms | 0.88 | - | - | - | 12,480 B |
+*/
diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs
index b0ac1c0fc..da2c81f86 100644
--- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs
+++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs
@@ -44,8 +44,8 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg
}
}
- [Benchmark(Baseline = true, Description = "Decode Jpeg - System.Drawing")]
- public SDSize JpegSystemDrawing()
+ [Benchmark(Baseline = true)]
+ public SDSize SystemDrawing()
{
using (var memoryStream = new MemoryStream(this.jpegBytes))
{
@@ -56,12 +56,12 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg
}
}
- [Benchmark(Description = "Decode Jpeg - ImageSharp")]
- public Size JpegImageSharp()
+ [Benchmark]
+ public Size ImageSharp()
{
using (var memoryStream = new MemoryStream(this.jpegBytes))
{
- using (var image = Image.Load(memoryStream, new JpegDecoder { IgnoreMetadata = true }))
+ using (var image = Image.Load(memoryStream, new JpegDecoder { IgnoreMetadata = true }))
{
return new Size(image.Width, image.Height);
}
diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/EncodeJpeg.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/EncodeJpeg.cs
index 87170e8d2..0e9bed1d9 100644
--- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/EncodeJpeg.cs
+++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/EncodeJpeg.cs
@@ -40,8 +40,8 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg
this.bmpCore = Image.Load(this.bmpStream);
this.bmpCore.Metadata.ExifProfile = null;
- this.encoder420 = new JpegEncoder { Quality = this.Quality, Subsample = JpegSubsample.Ratio420 };
- this.encoder444 = new JpegEncoder { Quality = this.Quality, Subsample = JpegSubsample.Ratio444 };
+ this.encoder420 = new JpegEncoder { Quality = this.Quality, ColorType = JpegColorType.YCbCrRatio420 };
+ this.encoder444 = new JpegEncoder { Quality = this.Quality, ColorType = JpegColorType.YCbCrRatio444 };
this.bmpStream.Position = 0;
this.bmpDrawing = SDImage.FromStream(this.bmpStream);
@@ -111,24 +111,24 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg
}
/*
-BenchmarkDotNet=v0.12.1, OS=Windows 10.0.19042
+BenchmarkDotNet=v0.13.0, OS=Windows 10.0.19042
Intel Core i7-6700K CPU 4.00GHz (Skylake), 1 CPU, 8 logical and 4 physical cores
-.NET Core SDK=6.0.100-preview.3.21202.5
- [Host] : .NET Core 3.1.13 (CoreCLR 4.700.21.11102, CoreFX 4.700.21.11602), X64 RyuJIT
- DefaultJob : .NET Core 3.1.13 (CoreCLR 4.700.21.11102, CoreFX 4.700.21.11602), X64 RyuJIT
+.NET SDK=6.0.100-preview.3.21202.5
+ [Host] : .NET Core 3.1.18 (CoreCLR 4.700.21.35901, CoreFX 4.700.21.36305), X64 RyuJIT
+ DefaultJob : .NET Core 3.1.18 (CoreCLR 4.700.21.35901, CoreFX 4.700.21.36305), X64 RyuJIT
| Method | Quality | Mean | Error | StdDev | Ratio |
|---------------------------- |-------- |---------:|---------:|---------:|------:|
-| 'System.Drawing Jpeg 4:2:0' | 75 | 29.41 ms | 0.108 ms | 0.096 ms | 1.00 |
-| 'ImageSharp Jpeg 4:2:0' | 75 | 26.30 ms | 0.131 ms | 0.109 ms | 0.89 |
-| 'ImageSharp Jpeg 4:4:4' | 75 | 36.70 ms | 0.303 ms | 0.269 ms | 1.25 |
+| 'System.Drawing Jpeg 4:2:0' | 75 | 30.04 ms | 0.540 ms | 0.479 ms | 1.00 |
+| 'ImageSharp Jpeg 4:2:0' | 75 | 19.32 ms | 0.290 ms | 0.257 ms | 0.64 |
+| 'ImageSharp Jpeg 4:4:4' | 75 | 26.76 ms | 0.332 ms | 0.294 ms | 0.89 |
| | | | | | |
-| 'System.Drawing Jpeg 4:2:0' | 90 | 32.67 ms | 0.226 ms | 0.211 ms | 1.00 |
-| 'ImageSharp Jpeg 4:2:0' | 90 | 33.56 ms | 0.237 ms | 0.222 ms | 1.03 |
-| 'ImageSharp Jpeg 4:4:4' | 90 | 44.82 ms | 0.250 ms | 0.234 ms | 1.37 |
+| 'System.Drawing Jpeg 4:2:0' | 90 | 32.82 ms | 0.184 ms | 0.163 ms | 1.00 |
+| 'ImageSharp Jpeg 4:2:0' | 90 | 25.00 ms | 0.408 ms | 0.361 ms | 0.76 |
+| 'ImageSharp Jpeg 4:4:4' | 90 | 31.83 ms | 0.636 ms | 0.595 ms | 0.97 |
| | | | | | |
-| 'System.Drawing Jpeg 4:2:0' | 100 | 39.06 ms | 0.233 ms | 0.218 ms | 1.00 |
-| 'ImageSharp Jpeg 4:2:0' | 100 | 40.23 ms | 0.225 ms | 0.277 ms | 1.03 |
-| 'ImageSharp Jpeg 4:4:4' | 100 | 63.35 ms | 0.486 ms | 0.431 ms | 1.62 |
+| 'System.Drawing Jpeg 4:2:0' | 100 | 39.30 ms | 0.359 ms | 0.318 ms | 1.00 |
+| 'ImageSharp Jpeg 4:2:0' | 100 | 34.49 ms | 0.265 ms | 0.235 ms | 0.88 |
+| 'ImageSharp Jpeg 4:4:4' | 100 | 56.40 ms | 0.565 ms | 0.501 ms | 1.44 |
*/
diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/GrayscaleColorConversion.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/GrayscaleColorConversion.cs
index 1eba1571d..7b62e1434 100644
--- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/GrayscaleColorConversion.cs
+++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/GrayscaleColorConversion.cs
@@ -19,7 +19,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg
{
var values = new JpegColorConverter.ComponentValues(this.Input, 0);
- new JpegColorConverter.FromGrayscaleBasic(8).ConvertToRgba(values, this.Output);
+ new JpegColorConverter.FromGrayscaleBasic(8).ConvertToRgbInplace(values);
}
[Benchmark]
@@ -27,7 +27,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg
{
var values = new JpegColorConverter.ComponentValues(this.Input, 0);
- new JpegColorConverter.FromGrayscaleAvx2(8).ConvertToRgba(values, this.Output);
+ new JpegColorConverter.FromGrayscaleAvx2(8).ConvertToRgbInplace(values);
}
}
}
diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/RgbColorConversion.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/RgbColorConversion.cs
index c1598be04..af03b31e5 100644
--- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/RgbColorConversion.cs
+++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/RgbColorConversion.cs
@@ -19,7 +19,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg
{
var values = new JpegColorConverter.ComponentValues(this.Input, 0);
- new JpegColorConverter.FromRgbBasic(8).ConvertToRgba(values, this.Output);
+ new JpegColorConverter.FromRgbBasic(8).ConvertToRgbInplace(values);
}
[Benchmark]
@@ -27,7 +27,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg
{
var values = new JpegColorConverter.ComponentValues(this.Input, 0);
- new JpegColorConverter.FromRgbVector8(8).ConvertToRgba(values, this.Output);
+ new JpegColorConverter.FromRgbVector8(8).ConvertToRgbInplace(values);
}
[Benchmark]
@@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg
{
var values = new JpegColorConverter.ComponentValues(this.Input, 0);
- new JpegColorConverter.FromRgbAvx2(8).ConvertToRgba(values, this.Output);
+ new JpegColorConverter.FromRgbAvx2(8).ConvertToRgbInplace(values);
}
}
}
diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/YCbCrColorConversion.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/YCbCrColorConversion.cs
index 6c5732c99..18daa364c 100644
--- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/YCbCrColorConversion.cs
+++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/YCbCrColorConversion.cs
@@ -19,7 +19,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg
{
var values = new JpegColorConverter.ComponentValues(this.Input, 0);
- new JpegColorConverter.FromYCbCrBasic(8).ConvertToRgba(values, this.Output);
+ new JpegColorConverter.FromYCbCrBasic(8).ConvertToRgbInplace(values);
}
[Benchmark(Baseline = true)]
@@ -27,7 +27,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg
{
var values = new JpegColorConverter.ComponentValues(this.Input, 0);
- new JpegColorConverter.FromYCbCrVector4(8).ConvertToRgba(values, this.Output);
+ new JpegColorConverter.FromYCbCrVector4(8).ConvertToRgbInplace(values);
}
[Benchmark]
@@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg
{
var values = new JpegColorConverter.ComponentValues(this.Input, 0);
- new JpegColorConverter.FromYCbCrVector8(8).ConvertToRgba(values, this.Output);
+ new JpegColorConverter.FromYCbCrVector8(8).ConvertToRgbInplace(values);
}
[Benchmark]
@@ -43,7 +43,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg
{
var values = new JpegColorConverter.ComponentValues(this.Input, 0);
- new JpegColorConverter.FromYCbCrAvx2(8).ConvertToRgba(values, this.Output);
+ new JpegColorConverter.FromYCbCrAvx2(8).ConvertToRgbInplace(values);
}
}
}
diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/YccKColorConverter.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/YccKColorConverter.cs
index 0a9bdb8fd..08e5e50d1 100644
--- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/YccKColorConverter.cs
+++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/YccKColorConverter.cs
@@ -19,7 +19,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg
{
var values = new JpegColorConverter.ComponentValues(this.Input, 0);
- new JpegColorConverter.FromYccKBasic(8).ConvertToRgba(values, this.Output);
+ new JpegColorConverter.FromYccKBasic(8).ConvertToRgbInplace(values);
}
[Benchmark]
@@ -27,7 +27,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg
{
var values = new JpegColorConverter.ComponentValues(this.Input, 0);
- new JpegColorConverter.FromYccKVector8(8).ConvertToRgba(values, this.Output);
+ new JpegColorConverter.FromYccKVector8(8).ConvertToRgbInplace(values);
}
[Benchmark]
@@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg
{
var values = new JpegColorConverter.ComponentValues(this.Input, 0);
- new JpegColorConverter.FromYccKAvx2(8).ConvertToRgba(values, this.Output);
+ new JpegColorConverter.FromYccKAvx2(8).ConvertToRgbInplace(values);
}
}
}
diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/FromVector4.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/FromVector4.cs
index 04ca8cd65..03e29b8e8 100644
--- a/tests/ImageSharp.Benchmarks/Color/Bulk/FromVector4.cs
+++ b/tests/ImageSharp.Benchmarks/Color/Bulk/FromVector4.cs
@@ -6,12 +6,10 @@ using System.Buffers;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
-
#if SUPPORTS_RUNTIME_INTRINSICS
using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.X86;
#endif
-
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4_Rgba32.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4_Rgba32.cs
index 9ae3b073d..ddeae5c2a 100644
--- a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4_Rgba32.cs
+++ b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4_Rgba32.cs
@@ -5,7 +5,6 @@ using System;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
-
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.Memory;
diff --git a/tests/ImageSharp.Benchmarks/Color/RgbToYCbCr.cs b/tests/ImageSharp.Benchmarks/Color/RgbToYCbCr.cs
index f4f944333..d231b706b 100644
--- a/tests/ImageSharp.Benchmarks/Color/RgbToYCbCr.cs
+++ b/tests/ImageSharp.Benchmarks/Color/RgbToYCbCr.cs
@@ -3,7 +3,6 @@
using System.Numerics;
using System.Runtime.CompilerServices;
-
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.Formats.Jpeg.Components;
diff --git a/tests/ImageSharp.Benchmarks/Config.HwIntrinsics.cs b/tests/ImageSharp.Benchmarks/Config.HwIntrinsics.cs
index 5ceb4c8a0..ffe0f4c02 100644
--- a/tests/ImageSharp.Benchmarks/Config.HwIntrinsics.cs
+++ b/tests/ImageSharp.Benchmarks/Config.HwIntrinsics.cs
@@ -65,17 +65,17 @@ namespace SixLabors.ImageSharp.Benchmarks
.WithId("1. No HwIntrinsics").AsBaseline());
#if SUPPORTS_RUNTIME_INTRINSICS
- if (Avx.IsSupported)
+ if (Sse.IsSupported)
{
this.AddJob(Job.Default.WithRuntime(CoreRuntime.Core31)
- .WithId("2. AVX"));
+ .WithEnvironmentVariables(new EnvironmentVariable(EnableAVX, Off))
+ .WithId("2. SSE"));
}
- if (Sse.IsSupported)
+ if (Avx.IsSupported)
{
this.AddJob(Job.Default.WithRuntime(CoreRuntime.Core31)
- .WithEnvironmentVariables(new EnvironmentVariable(EnableAVX, Off))
- .WithId("3. SSE"));
+ .WithId("3. AVX"));
}
#endif
}
diff --git a/tests/ImageSharp.Benchmarks/Config.cs b/tests/ImageSharp.Benchmarks/Config.cs
index 63064eec5..299784821 100644
--- a/tests/ImageSharp.Benchmarks/Config.cs
+++ b/tests/ImageSharp.Benchmarks/Config.cs
@@ -33,16 +33,16 @@ namespace SixLabors.ImageSharp.Benchmarks
{
public MultiFramework() => this.AddJob(
Job.Default.WithRuntime(ClrRuntime.Net472),
- Job.Default.WithRuntime(CoreRuntime.Core21),
- Job.Default.WithRuntime(CoreRuntime.Core31));
+ Job.Default.WithRuntime(CoreRuntime.Core31),
+ Job.Default.WithRuntime(CoreRuntime.Core50).With(new Argument[] { new MsBuildArgument("/p:DebugType=portable") }));
}
public class ShortMultiFramework : Config
{
public ShortMultiFramework() => this.AddJob(
Job.Default.WithRuntime(ClrRuntime.Net472).WithLaunchCount(1).WithWarmupCount(3).WithIterationCount(3),
- Job.Default.WithRuntime(CoreRuntime.Core21).WithLaunchCount(1).WithWarmupCount(3).WithIterationCount(3),
- Job.Default.WithRuntime(CoreRuntime.Core31).WithLaunchCount(1).WithWarmupCount(3).WithIterationCount(3));
+ Job.Default.WithRuntime(CoreRuntime.Core31).WithLaunchCount(1).WithWarmupCount(3).WithIterationCount(3),
+ Job.Default.WithRuntime(CoreRuntime.Core50).WithLaunchCount(1).WithWarmupCount(3).WithIterationCount(3).With(new Argument[] { new MsBuildArgument("/p:DebugType=portable") }));
}
public class ShortCore31 : Config
diff --git a/tests/ImageSharp.Benchmarks/General/Array2D.cs b/tests/ImageSharp.Benchmarks/General/Array2D.cs
index 16cbb5991..cd4eec0d4 100644
--- a/tests/ImageSharp.Benchmarks/General/Array2D.cs
+++ b/tests/ImageSharp.Benchmarks/General/Array2D.cs
@@ -2,7 +2,6 @@
// Licensed under the Apache License, Version 2.0.
using System;
-
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp;
diff --git a/tests/ImageSharp.Benchmarks/General/ArrayReverse.cs b/tests/ImageSharp.Benchmarks/General/ArrayReverse.cs
index cd3fc5a06..b9ba80c15 100644
--- a/tests/ImageSharp.Benchmarks/General/ArrayReverse.cs
+++ b/tests/ImageSharp.Benchmarks/General/ArrayReverse.cs
@@ -2,7 +2,6 @@
// Licensed under the Apache License, Version 2.0.
using System;
-
using BenchmarkDotNet.Attributes;
namespace SixLabors.ImageSharp.Benchmarks.General
diff --git a/tests/ImageSharp.Benchmarks/General/BasicMath/Abs.cs b/tests/ImageSharp.Benchmarks/General/BasicMath/Abs.cs
index b6cdcf5f5..0abaac207 100644
--- a/tests/ImageSharp.Benchmarks/General/BasicMath/Abs.cs
+++ b/tests/ImageSharp.Benchmarks/General/BasicMath/Abs.cs
@@ -2,7 +2,6 @@
// Licensed under the Apache License, Version 2.0.
using System;
-
using BenchmarkDotNet.Attributes;
namespace SixLabors.ImageSharp.Benchmarks.General.BasicMath
diff --git a/tests/ImageSharp.Benchmarks/General/BasicMath/ClampFloat.cs b/tests/ImageSharp.Benchmarks/General/BasicMath/ClampFloat.cs
index 516c187e3..2f4120bb3 100644
--- a/tests/ImageSharp.Benchmarks/General/BasicMath/ClampFloat.cs
+++ b/tests/ImageSharp.Benchmarks/General/BasicMath/ClampFloat.cs
@@ -3,7 +3,6 @@
using System;
using System.Runtime.CompilerServices;
-
using BenchmarkDotNet.Attributes;
namespace SixLabors.ImageSharp.Benchmarks.General.BasicMath
diff --git a/tests/ImageSharp.Benchmarks/General/BasicMath/ClampInt32IntoByte.cs b/tests/ImageSharp.Benchmarks/General/BasicMath/ClampInt32IntoByte.cs
index 1c58636df..bfa468f13 100644
--- a/tests/ImageSharp.Benchmarks/General/BasicMath/ClampInt32IntoByte.cs
+++ b/tests/ImageSharp.Benchmarks/General/BasicMath/ClampInt32IntoByte.cs
@@ -3,7 +3,6 @@
using System;
using System.Runtime.CompilerServices;
-
using BenchmarkDotNet.Attributes;
namespace SixLabors.ImageSharp.Benchmarks.General.BasicMath
diff --git a/tests/ImageSharp.Benchmarks/General/BasicMath/ClampVector4.cs b/tests/ImageSharp.Benchmarks/General/BasicMath/ClampVector4.cs
index 0b5f31ee4..c1dab7024 100644
--- a/tests/ImageSharp.Benchmarks/General/BasicMath/ClampVector4.cs
+++ b/tests/ImageSharp.Benchmarks/General/BasicMath/ClampVector4.cs
@@ -3,7 +3,6 @@
using System.Numerics;
using System.Runtime.CompilerServices;
-
using BenchmarkDotNet.Attributes;
namespace SixLabors.ImageSharp.Benchmarks.General.BasicMath
diff --git a/tests/ImageSharp.Benchmarks/General/BasicMath/Pow.cs b/tests/ImageSharp.Benchmarks/General/BasicMath/Pow.cs
index ad8f8746c..899a21cc1 100644
--- a/tests/ImageSharp.Benchmarks/General/BasicMath/Pow.cs
+++ b/tests/ImageSharp.Benchmarks/General/BasicMath/Pow.cs
@@ -2,7 +2,6 @@
// Licensed under the Apache License, Version 2.0.
using System;
-
using BenchmarkDotNet.Attributes;
namespace SixLabors.ImageSharp.Benchmarks.General.BasicMath
diff --git a/tests/ImageSharp.Benchmarks/General/CopyBuffers.cs b/tests/ImageSharp.Benchmarks/General/CopyBuffers.cs
index d21e44a1c..db8887580 100644
--- a/tests/ImageSharp.Benchmarks/General/CopyBuffers.cs
+++ b/tests/ImageSharp.Benchmarks/General/CopyBuffers.cs
@@ -5,7 +5,6 @@ using System;
using System.Buffers;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
-
using BenchmarkDotNet.Attributes;
namespace SixLabors.ImageSharp.Benchmarks.General
diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/ITestPixel.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/ITestPixel.cs
index 12ebbcf4b..c10000f0a 100644
--- a/tests/ImageSharp.Benchmarks/General/PixelConversion/ITestPixel.cs
+++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/ITestPixel.cs
@@ -2,7 +2,6 @@
// Licensed under the Apache License, Version 2.0.
using System.Numerics;
-
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion
diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromRgba32.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromRgba32.cs
index a933f890f..e0aa7023c 100644
--- a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromRgba32.cs
+++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromRgba32.cs
@@ -4,7 +4,6 @@
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
-
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.PixelFormats;
diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromVector4.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromVector4.cs
index 6bb3f38be..5a9421fe7 100644
--- a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromVector4.cs
+++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromVector4.cs
@@ -4,7 +4,6 @@
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
-
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.PixelFormats;
diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToRgba32.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToRgba32.cs
index f922559f7..07f697e91 100644
--- a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToRgba32.cs
+++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToRgba32.cs
@@ -2,7 +2,6 @@
// Licensed under the Apache License, Version 2.0.
using System.Runtime.CompilerServices;
-
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.PixelFormats;
diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToRgba32_AsPartOfCompositeOperation.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToRgba32_AsPartOfCompositeOperation.cs
index 1a228e3bf..5df8daa04 100644
--- a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToRgba32_AsPartOfCompositeOperation.cs
+++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToRgba32_AsPartOfCompositeOperation.cs
@@ -2,7 +2,6 @@
// Licensed under the Apache License, Version 2.0.
using System.Runtime.CompilerServices;
-
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.PixelFormats;
diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToVector4.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToVector4.cs
index dc7dea504..798995c3d 100644
--- a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToVector4.cs
+++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToVector4.cs
@@ -3,7 +3,6 @@
using System.Numerics;
using System.Runtime.CompilerServices;
-
using BenchmarkDotNet.Attributes;
namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion
diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToVector4_AsPartOfCompositeOperation.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToVector4_AsPartOfCompositeOperation.cs
index c1c4d6e0d..d029cd90d 100644
--- a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToVector4_AsPartOfCompositeOperation.cs
+++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToVector4_AsPartOfCompositeOperation.cs
@@ -3,7 +3,6 @@
using System.Numerics;
using System.Runtime.CompilerServices;
-
using BenchmarkDotNet.Attributes;
namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion
diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_PackFromRgbPlanes.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_PackFromRgbPlanes.cs
index eade8e0c4..8900894b4 100644
--- a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_PackFromRgbPlanes.cs
+++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_PackFromRgbPlanes.cs
@@ -50,16 +50,22 @@ namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion
public void Rgb24_Scalar_PerElement_Pinned()
{
fixed (byte* r = &this.rBuf[0])
- fixed (byte* g = &this.gBuf[0])
- fixed (byte* b = &this.bBuf[0])
- fixed (Rgb24* rgb = &this.rgbBuf[0])
{
- for (int i = 0; i < this.Count; i++)
+ fixed (byte* g = &this.gBuf[0])
{
- Rgb24* d = rgb + i;
- d->R = r[i];
- d->G = g[i];
- d->B = b[i];
+ fixed (byte* b = &this.bBuf[0])
+ {
+ fixed (Rgb24* rgb = &this.rgbBuf[0])
+ {
+ for (int i = 0; i < this.Count; i++)
+ {
+ Rgb24* d = rgb + i;
+ d->R = r[i];
+ d->G = g[i];
+ d->B = b[i];
+ }
+ }
+ }
}
}
}
@@ -283,4 +289,4 @@ namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion
// | Rgb24_Avx2_Bytes | 1024 | 243.3 ns | 1.56 ns | 1.30 ns | 0.47 | 0.00 |
// | Rgba32_Avx2_Bytes | 1024 | 146.0 ns | 2.48 ns | 2.32 ns | 0.28 | 0.01 |
}
-}
\ No newline at end of file
+}
diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_Rgba32_To_Argb32.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_Rgba32_To_Argb32.cs
index 7c51e0547..6ab1982aa 100644
--- a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_Rgba32_To_Argb32.cs
+++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_Rgba32_To_Argb32.cs
@@ -4,7 +4,6 @@
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
-
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.PixelFormats;
diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_Rgba32_To_Bgra32.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_Rgba32_To_Bgra32.cs
index 8cb9fb984..580ae7afb 100644
--- a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_Rgba32_To_Bgra32.cs
+++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_Rgba32_To_Bgra32.cs
@@ -5,7 +5,6 @@ using System;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
-
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.PixelFormats;
diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/TestArgb.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/TestArgb.cs
index 958495c3c..6c74fc3bc 100644
--- a/tests/ImageSharp.Benchmarks/General/PixelConversion/TestArgb.cs
+++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/TestArgb.cs
@@ -4,7 +4,6 @@
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
-
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion
diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/TestRgba.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/TestRgba.cs
index ff11585e7..e01bfa011 100644
--- a/tests/ImageSharp.Benchmarks/General/PixelConversion/TestRgba.cs
+++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/TestRgba.cs
@@ -4,7 +4,6 @@
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
-
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion
diff --git a/tests/ImageSharp.Benchmarks/General/Vector4Constants.cs b/tests/ImageSharp.Benchmarks/General/Vector4Constants.cs
index ef1b3c98d..fa3f1e9dd 100644
--- a/tests/ImageSharp.Benchmarks/General/Vector4Constants.cs
+++ b/tests/ImageSharp.Benchmarks/General/Vector4Constants.cs
@@ -3,7 +3,6 @@
using System;
using System.Numerics;
-
using BenchmarkDotNet.Attributes;
namespace SixLabors.ImageSharp.Benchmarks.General
diff --git a/tests/ImageSharp.Benchmarks/General/Vectorization/BitwiseOrUint32.cs b/tests/ImageSharp.Benchmarks/General/Vectorization/BitwiseOrUint32.cs
index 651ca51ba..3cf9f0555 100644
--- a/tests/ImageSharp.Benchmarks/General/Vectorization/BitwiseOrUint32.cs
+++ b/tests/ImageSharp.Benchmarks/General/Vectorization/BitwiseOrUint32.cs
@@ -2,7 +2,6 @@
// Licensed under the Apache License, Version 2.0.
using System.Numerics;
-
using BenchmarkDotNet.Attributes;
namespace SixLabors.ImageSharp.Benchmarks.General.Vectorization
diff --git a/tests/ImageSharp.Benchmarks/General/Vectorization/DivFloat.cs b/tests/ImageSharp.Benchmarks/General/Vectorization/DivFloat.cs
index 4c981bf5c..85d4a93a3 100644
--- a/tests/ImageSharp.Benchmarks/General/Vectorization/DivFloat.cs
+++ b/tests/ImageSharp.Benchmarks/General/Vectorization/DivFloat.cs
@@ -2,7 +2,6 @@
// Licensed under the Apache License, Version 2.0.
using System.Numerics;
-
using BenchmarkDotNet.Attributes;
namespace SixLabors.ImageSharp.Benchmarks.General.Vectorization
diff --git a/tests/ImageSharp.Benchmarks/General/Vectorization/DivUInt32.cs b/tests/ImageSharp.Benchmarks/General/Vectorization/DivUInt32.cs
index 36a45a482..2555d7b8f 100644
--- a/tests/ImageSharp.Benchmarks/General/Vectorization/DivUInt32.cs
+++ b/tests/ImageSharp.Benchmarks/General/Vectorization/DivUInt32.cs
@@ -2,7 +2,6 @@
// Licensed under the Apache License, Version 2.0.
using System.Numerics;
-
using BenchmarkDotNet.Attributes;
namespace SixLabors.ImageSharp.Benchmarks.General.Vectorization
diff --git a/tests/ImageSharp.Benchmarks/General/Vectorization/Divide.cs b/tests/ImageSharp.Benchmarks/General/Vectorization/Divide.cs
index 09d14963b..11889127c 100644
--- a/tests/ImageSharp.Benchmarks/General/Vectorization/Divide.cs
+++ b/tests/ImageSharp.Benchmarks/General/Vectorization/Divide.cs
@@ -2,7 +2,6 @@
// Licensed under the Apache License, Version 2.0.
using System.Numerics;
-
using BenchmarkDotNet.Attributes;
namespace ImageSharp.Benchmarks.General.Vectorization
diff --git a/tests/ImageSharp.Benchmarks/General/Vectorization/MulFloat.cs b/tests/ImageSharp.Benchmarks/General/Vectorization/MulFloat.cs
index 595df8a59..99afc90de 100644
--- a/tests/ImageSharp.Benchmarks/General/Vectorization/MulFloat.cs
+++ b/tests/ImageSharp.Benchmarks/General/Vectorization/MulFloat.cs
@@ -2,7 +2,6 @@
// Licensed under the Apache License, Version 2.0.
using System.Numerics;
-
using BenchmarkDotNet.Attributes;
namespace SixLabors.ImageSharp.Benchmarks.General.Vectorization
diff --git a/tests/ImageSharp.Benchmarks/General/Vectorization/MulUInt32.cs b/tests/ImageSharp.Benchmarks/General/Vectorization/MulUInt32.cs
index a405f0953..2b41904f8 100644
--- a/tests/ImageSharp.Benchmarks/General/Vectorization/MulUInt32.cs
+++ b/tests/ImageSharp.Benchmarks/General/Vectorization/MulUInt32.cs
@@ -2,7 +2,6 @@
// Licensed under the Apache License, Version 2.0.
using System.Numerics;
-
using BenchmarkDotNet.Attributes;
namespace SixLabors.ImageSharp.Benchmarks.General.Vectorization
diff --git a/tests/ImageSharp.Benchmarks/General/Vectorization/ReinterpretUInt32AsFloat.cs b/tests/ImageSharp.Benchmarks/General/Vectorization/ReinterpretUInt32AsFloat.cs
index cdf8ad04f..d4da75cdf 100644
--- a/tests/ImageSharp.Benchmarks/General/Vectorization/ReinterpretUInt32AsFloat.cs
+++ b/tests/ImageSharp.Benchmarks/General/Vectorization/ReinterpretUInt32AsFloat.cs
@@ -3,7 +3,6 @@
using System.Numerics;
using System.Runtime.InteropServices;
-
using BenchmarkDotNet.Attributes;
namespace SixLabors.ImageSharp.Benchmarks.General.Vectorization
diff --git a/tests/ImageSharp.Benchmarks/General/Vectorization/SIMDBenchmarkBase.cs b/tests/ImageSharp.Benchmarks/General/Vectorization/SIMDBenchmarkBase.cs
index 8a61f49c4..0a666d0c6 100644
--- a/tests/ImageSharp.Benchmarks/General/Vectorization/SIMDBenchmarkBase.cs
+++ b/tests/ImageSharp.Benchmarks/General/Vectorization/SIMDBenchmarkBase.cs
@@ -3,7 +3,6 @@
using System.Numerics;
using System.Runtime.CompilerServices;
-
using BenchmarkDotNet.Attributes;
namespace ImageSharp.Benchmarks.General.Vectorization
diff --git a/tests/ImageSharp.Benchmarks/General/Vectorization/UInt32ToSingle.cs b/tests/ImageSharp.Benchmarks/General/Vectorization/UInt32ToSingle.cs
index 5ec5f1d18..21114c510 100644
--- a/tests/ImageSharp.Benchmarks/General/Vectorization/UInt32ToSingle.cs
+++ b/tests/ImageSharp.Benchmarks/General/Vectorization/UInt32ToSingle.cs
@@ -3,7 +3,6 @@
using System.Numerics;
using System.Runtime.CompilerServices;
-
using BenchmarkDotNet.Attributes;
namespace SixLabors.ImageSharp.Benchmarks.General.Vectorization
diff --git a/tests/ImageSharp.Benchmarks/General/Vectorization/WidenBytesToUInt32.cs b/tests/ImageSharp.Benchmarks/General/Vectorization/WidenBytesToUInt32.cs
index 20d3bd9d6..661eb844e 100644
--- a/tests/ImageSharp.Benchmarks/General/Vectorization/WidenBytesToUInt32.cs
+++ b/tests/ImageSharp.Benchmarks/General/Vectorization/WidenBytesToUInt32.cs
@@ -3,7 +3,6 @@
using System.Numerics;
using System.Runtime.CompilerServices;
-
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.Tuples;
diff --git a/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj b/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj
index 84b83ee14..8f0b4a86f 100644
--- a/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj
+++ b/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj
@@ -6,15 +6,20 @@
Exe
SixLabors.ImageSharp.Benchmarks
false
+ portable
false
Debug;Release;Debug-InnerLoop;Release-InnerLoop
- 9
+
+
+ net6.0;net5.0;netcoreapp3.1;netcoreapp2.1;net472
+
+
netcoreapp3.1
diff --git a/tests/ImageSharp.Benchmarks/LoadResizeSave/LoadResizeSaveStressBenchmarks.cs b/tests/ImageSharp.Benchmarks/LoadResizeSave/LoadResizeSaveStressBenchmarks.cs
index f1f7de3dc..b7ec95c4b 100644
--- a/tests/ImageSharp.Benchmarks/LoadResizeSave/LoadResizeSaveStressBenchmarks.cs
+++ b/tests/ImageSharp.Benchmarks/LoadResizeSave/LoadResizeSaveStressBenchmarks.cs
@@ -42,11 +42,11 @@ namespace SixLabors.ImageSharp.Benchmarks.LoadResizeSave
1
};
- [Benchmark(Baseline = true)]
+ [Benchmark]
[ArgumentsSource(nameof(ParallelismValues))]
public void SystemDrawing(int maxDegreeOfParallelism) => this.ForEachImage(this.runner.SystemDrawingResize, maxDegreeOfParallelism);
- [Benchmark]
+ [Benchmark(Baseline = true)]
[ArgumentsSource(nameof(ParallelismValues))]
public void ImageSharp(int maxDegreeOfParallelism) => this.ForEachImage(this.runner.ImageSharpResize, maxDegreeOfParallelism);
@@ -62,6 +62,10 @@ namespace SixLabors.ImageSharp.Benchmarks.LoadResizeSave
[ArgumentsSource(nameof(ParallelismValues))]
public void SkiaBitmap(int maxDegreeOfParallelism) => this.ForEachImage(this.runner.SkiaBitmapResize, maxDegreeOfParallelism);
+ [Benchmark]
+ [ArgumentsSource(nameof(ParallelismValues))]
+ public void SkiaBitmapDecodeToTargetSize(int maxDegreeOfParallelism) => this.ForEachImage(this.runner.SkiaBitmapDecodeToTargetSize, maxDegreeOfParallelism);
+
[Benchmark]
[ArgumentsSource(nameof(ParallelismValues))]
public void NetVips(int maxDegreeOfParallelism) => this.ForEachImage(this.runner.NetVipsResize, maxDegreeOfParallelism);
diff --git a/tests/ImageSharp.Benchmarks/LoadResizeSave/LoadResizeSaveStressRunner.cs b/tests/ImageSharp.Benchmarks/LoadResizeSave/LoadResizeSaveStressRunner.cs
index c15f641b4..7c57d691a 100644
--- a/tests/ImageSharp.Benchmarks/LoadResizeSave/LoadResizeSaveStressRunner.cs
+++ b/tests/ImageSharp.Benchmarks/LoadResizeSave/LoadResizeSaveStressRunner.cs
@@ -7,6 +7,7 @@ using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
+using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using ImageMagick;
@@ -31,18 +32,10 @@ namespace SixLabors.ImageSharp.Benchmarks.LoadResizeSave
public class LoadResizeSaveStressRunner
{
- private const int ThumbnailSize = 150;
private const int Quality = 75;
- private const string ImageSharp = nameof(ImageSharp);
- private const string SystemDrawing = nameof(SystemDrawing);
- private const string MagickNET = nameof(MagickNET);
- private const string NetVips = nameof(NetVips);
- private const string MagicScaler = nameof(MagicScaler);
- private const string SkiaSharpCanvas = nameof(SkiaSharpCanvas);
- private const string SkiaSharpBitmap = nameof(SkiaSharpBitmap);
// Set the quality for ImagSharp
- private readonly JpegEncoder imageSharpJpegEncoder = new () { Quality = Quality };
+ private readonly JpegEncoder imageSharpJpegEncoder = new() { Quality = Quality };
private readonly ImageCodecInfo systemDrawingJpegCodec =
ImageCodecInfo.GetImageEncoders().First(codec => codec.FormatID == ImageFormat.Jpeg.Guid);
@@ -58,6 +51,8 @@ namespace SixLabors.ImageSharp.Benchmarks.LoadResizeSave
public JpegKind Filter { get; set; }
+ public int ThumbnailSize { get; set; } = 150;
+
private static readonly string[] ProgressiveFiles =
{
"ancyloscelis-apiformis-m-paraguay-face_2014-08-08-095255-zs-pmax_15046500892_o.jpg",
@@ -132,12 +127,12 @@ namespace SixLabors.ImageSharp.Benchmarks.LoadResizeSave
this.TotalProcessedMegapixels += pixels / 1_000_000.0;
}
- private string OutputPath(string inputPath, string postfix) =>
+ private string OutputPath(string inputPath, [CallerMemberName]string postfix = null) =>
Path.Combine(
this.outputDirectory,
Path.GetFileNameWithoutExtension(inputPath) + "-" + postfix + Path.GetExtension(inputPath));
- private (int width, int height) ScaledSize(int inWidth, int inHeight, int outSize)
+ private (int Width, int Height) ScaledSize(int inWidth, int inHeight, int outSize)
{
int width, height;
if (inWidth > inHeight)
@@ -159,8 +154,8 @@ namespace SixLabors.ImageSharp.Benchmarks.LoadResizeSave
using var image = SystemDrawingImage.FromFile(input, true);
this.IncreaseTotalMegapixels(image.Width, image.Height);
- (int width, int height) scaled = this.ScaledSize(image.Width, image.Height, ThumbnailSize);
- var resized = new Bitmap(scaled.width, scaled.height);
+ (int Width, int Height) scaled = this.ScaledSize(image.Width, image.Height, this.ThumbnailSize);
+ var resized = new Bitmap(scaled.Width, scaled.Height);
using var graphics = Graphics.FromImage(resized);
using var attributes = new ImageAttributes();
attributes.SetWrapMode(WrapMode.TileFlipXY);
@@ -174,12 +169,12 @@ namespace SixLabors.ImageSharp.Benchmarks.LoadResizeSave
using var encoderParams = new EncoderParameters(1);
using var qualityParam = new EncoderParameter(Encoder.Quality, (long)Quality);
encoderParams.Param[0] = qualityParam;
- resized.Save(this.OutputPath(input, SystemDrawing), this.systemDrawingJpegCodec, encoderParams);
+ resized.Save(this.OutputPath(input), this.systemDrawingJpegCodec, encoderParams);
}
public void ImageSharpResize(string input)
{
- using FileStream output = File.Open(this.OutputPath(input, ImageSharp), FileMode.Create);
+ using FileStream output = File.Open(this.OutputPath(input), FileMode.Create);
// Resize it to fit a 150x150 square
using var image = ImageSharpImage.Load(input);
@@ -187,7 +182,7 @@ namespace SixLabors.ImageSharp.Benchmarks.LoadResizeSave
image.Mutate(i => i.Resize(new ResizeOptions
{
- Size = new ImageSharpSize(ThumbnailSize, ThumbnailSize),
+ Size = new ImageSharpSize(this.ThumbnailSize, this.ThumbnailSize),
Mode = ResizeMode.Max
}));
@@ -204,7 +199,7 @@ namespace SixLabors.ImageSharp.Benchmarks.LoadResizeSave
this.IncreaseTotalMegapixels(image.Width, image.Height);
// Resize it to fit a 150x150 square
- image.Resize(ThumbnailSize, ThumbnailSize);
+ image.Resize(this.ThumbnailSize, this.ThumbnailSize);
// Reduce the size of the file
image.Strip();
@@ -213,15 +208,15 @@ namespace SixLabors.ImageSharp.Benchmarks.LoadResizeSave
image.Quality = Quality;
// Save the results
- image.Write(this.OutputPath(input, MagickNET));
+ image.Write(this.OutputPath(input));
}
public void MagicScalerResize(string input)
{
var settings = new ProcessImageSettings()
{
- Width = ThumbnailSize,
- Height = ThumbnailSize,
+ Width = this.ThumbnailSize,
+ Height = this.ThumbnailSize,
ResizeMode = CropScaleMode.Max,
SaveFormat = FileFormat.Jpeg,
JpegQuality = Quality,
@@ -229,7 +224,7 @@ namespace SixLabors.ImageSharp.Benchmarks.LoadResizeSave
};
// TODO: Is there a way to capture input dimensions for IncreaseTotalMegapixels?
- using var output = new FileStream(this.OutputPath(input, MagicScaler), FileMode.Create);
+ using var output = new FileStream(this.OutputPath(input), FileMode.Create);
MagicImageProcessor.ProcessImage(input, output, settings);
}
@@ -237,15 +232,15 @@ namespace SixLabors.ImageSharp.Benchmarks.LoadResizeSave
{
using var original = SKBitmap.Decode(input);
this.IncreaseTotalMegapixels(original.Width, original.Height);
- (int width, int height) scaled = this.ScaledSize(original.Width, original.Height, ThumbnailSize);
- using var surface = SKSurface.Create(new SKImageInfo(scaled.width, scaled.height, original.ColorType, original.AlphaType));
+ (int Width, int Height) scaled = this.ScaledSize(original.Width, original.Height, this.ThumbnailSize);
+ using var surface = SKSurface.Create(new SKImageInfo(scaled.Width, scaled.Height, original.ColorType, original.AlphaType));
using var paint = new SKPaint() { FilterQuality = SKFilterQuality.High };
SKCanvas canvas = surface.Canvas;
- canvas.Scale((float)scaled.width / original.Width);
+ canvas.Scale((float)scaled.Width / original.Width);
canvas.DrawBitmap(original, 0, 0, paint);
canvas.Flush();
- using FileStream output = File.OpenWrite(this.OutputPath(input, SkiaSharpCanvas));
+ using FileStream output = File.OpenWrite(this.OutputPath(input));
surface.Snapshot()
.Encode(SKEncodedImageFormat.Jpeg, Quality)
.SaveTo(output);
@@ -255,15 +250,38 @@ namespace SixLabors.ImageSharp.Benchmarks.LoadResizeSave
{
using var original = SKBitmap.Decode(input);
this.IncreaseTotalMegapixels(original.Width, original.Height);
- (int width, int height) scaled = this.ScaledSize(original.Width, original.Height, ThumbnailSize);
- using var resized = original.Resize(new SKImageInfo(scaled.width, scaled.height), SKFilterQuality.High);
+ (int Width, int Height) scaled = this.ScaledSize(original.Width, original.Height, this.ThumbnailSize);
+ using var resized = original.Resize(new SKImageInfo(scaled.Width, scaled.Height), SKFilterQuality.High);
if (resized == null)
{
return;
}
using var image = SKImage.FromBitmap(resized);
- using FileStream output = File.OpenWrite(this.OutputPath(input, SkiaSharpBitmap));
+ using FileStream output = File.OpenWrite(this.OutputPath(input));
+ image.Encode(SKEncodedImageFormat.Jpeg, Quality)
+ .SaveTo(output);
+ }
+
+ public void SkiaBitmapDecodeToTargetSize(string input)
+ {
+ using var codec = SKCodec.Create(input);
+
+ SKImageInfo info = codec.Info;
+ this.IncreaseTotalMegapixels(info.Width, info.Height);
+ (int Width, int Height) scaled = this.ScaledSize(info.Width, info.Height, this.ThumbnailSize);
+ SKSizeI supportedScale = codec.GetScaledDimensions((float)scaled.Width / info.Width);
+
+ using var original = SKBitmap.Decode(codec, new SKImageInfo(supportedScale.Width, supportedScale.Height));
+ using SKBitmap resized = original.Resize(new SKImageInfo(scaled.Width, scaled.Height), SKFilterQuality.High);
+ if (resized == null)
+ {
+ return;
+ }
+
+ using var image = SKImage.FromBitmap(resized);
+
+ using FileStream output = File.OpenWrite(this.OutputPath(input, nameof(this.SkiaBitmapDecodeToTargetSize)));
image.Encode(SKEncodedImageFormat.Jpeg, Quality)
.SaveTo(output);
}
@@ -271,10 +289,10 @@ namespace SixLabors.ImageSharp.Benchmarks.LoadResizeSave
public void NetVipsResize(string input)
{
// Thumbnail to fit a 150x150 square
- using var thumb = NetVipsImage.Thumbnail(input, ThumbnailSize, ThumbnailSize);
+ using var thumb = NetVipsImage.Thumbnail(input, this.ThumbnailSize, this.ThumbnailSize);
// Save the results
- thumb.Jpegsave(this.OutputPath(input, NetVips), q: Quality, strip: true);
+ thumb.Jpegsave(this.OutputPath(input), q: Quality, strip: true);
}
}
}
diff --git a/tests/ImageSharp.Benchmarks/Processing/Resize.cs b/tests/ImageSharp.Benchmarks/Processing/Resize.cs
index 571c92cc8..81fdbfb31 100644
--- a/tests/ImageSharp.Benchmarks/Processing/Resize.cs
+++ b/tests/ImageSharp.Benchmarks/Processing/Resize.cs
@@ -215,4 +215,35 @@ namespace SixLabors.ImageSharp.Benchmarks
// SystemDrawing | Core | Core | 3032 | 400 | 118.3 ms | 6.899 ms | 0.3781 ms | 1.00 | 0.00 | - | - | - | 96 B |
// 'ImageSharp, MaxDegreeOfParallelism = 1' | Core | Core | 3032 | 400 | 122.4 ms | 15.069 ms | 0.8260 ms | 1.03 | 0.01 | - | - | - | 15712 B |
}
+
+ public class Resize_Bicubic_Compare_Rgba32_Rgb24
+ {
+ private Resize_Bicubic_Rgb24 rgb24;
+ private Resize_Bicubic_Rgba32 rgba32;
+
+ [GlobalSetup]
+ public void Setup()
+ {
+ this.rgb24 = new Resize_Bicubic_Rgb24();
+ this.rgb24.Setup();
+ this.rgba32 = new Resize_Bicubic_Rgba32();
+ this.rgba32.Setup();
+ }
+
+ [GlobalCleanup]
+ public void Cleanup()
+ {
+ this.rgb24.Cleanup();
+ this.rgba32.Cleanup();
+ }
+
+ [Benchmark]
+ public void SystemDrawing() => this.rgba32.SystemDrawing();
+
+ [Benchmark(Baseline = true)]
+ public void Rgba32() => this.rgba32.ImageSharp_P1();
+
+ [Benchmark]
+ public void Rgb24() => this.rgb24.ImageSharp_P1();
+ }
}
diff --git a/tests/ImageSharp.Benchmarks/Program.cs b/tests/ImageSharp.Benchmarks/Program.cs
index 8080825d9..f6ffa6f80 100644
--- a/tests/ImageSharp.Benchmarks/Program.cs
+++ b/tests/ImageSharp.Benchmarks/Program.cs
@@ -1,8 +1,6 @@
-// Copyright (c) Six Labors.
+// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
-using System.Reflection;
-
using BenchmarkDotNet.Running;
namespace SixLabors.ImageSharp.Benchmarks
@@ -15,9 +13,8 @@ namespace SixLabors.ImageSharp.Benchmarks
///
/// The arguments to pass to the program.
///
- public static void Main(string[] args)
- {
- new BenchmarkSwitcher(typeof(Program).GetTypeInfo().Assembly).Run(args);
- }
+ public static void Main(string[] args) => BenchmarkSwitcher
+ .FromAssembly(typeof(Program).Assembly)
+ .Run(args);
}
}
diff --git a/tests/ImageSharp.Tests.ProfilingSandbox/ImageSharp.Tests.ProfilingSandbox.csproj b/tests/ImageSharp.Tests.ProfilingSandbox/ImageSharp.Tests.ProfilingSandbox.csproj
index 10deb24c6..1a470fa31 100644
--- a/tests/ImageSharp.Tests.ProfilingSandbox/ImageSharp.Tests.ProfilingSandbox.csproj
+++ b/tests/ImageSharp.Tests.ProfilingSandbox/ImageSharp.Tests.ProfilingSandbox.csproj
@@ -14,10 +14,14 @@
false
Debug;Release;Debug-InnerLoop;Release-InnerLoop
false
- 9
+
+
+ net6.0;net5.0;netcoreapp3.1;netcoreapp2.1;net472
+
+
netcoreapp3.1
diff --git a/tests/ImageSharp.Tests.ProfilingSandbox/LoadResizeSaveParallelMemoryStress.cs b/tests/ImageSharp.Tests.ProfilingSandbox/LoadResizeSaveParallelMemoryStress.cs
index 2aadf02eb..7fe91fe5f 100644
--- a/tests/ImageSharp.Tests.ProfilingSandbox/LoadResizeSaveParallelMemoryStress.cs
+++ b/tests/ImageSharp.Tests.ProfilingSandbox/LoadResizeSaveParallelMemoryStress.cs
@@ -1,4 +1,4 @@
-// Copyright (c) Six Labors.
+// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
using System;
@@ -18,7 +18,7 @@ namespace SixLabors.ImageSharp.Tests.ProfilingSandbox
this.benchmarks = new LoadResizeSaveStressRunner()
{
// MaxDegreeOfParallelism = 10,
- // Filter = JpegKind.Baseline
+ Filter = JpegKind.Baseline,
};
this.benchmarks.Init();
}
@@ -58,6 +58,7 @@ namespace SixLabors.ImageSharp.Tests.ProfilingSandbox
lrs.SystemDrawingBenchmarkParallel();
break;
case ConsoleKey.D2:
+ Console.WriteLine($"Images: {lrs.benchmarks.Images.Length}");
lrs.ImageSharpBenchmarkParallel();
break;
case ConsoleKey.D3:
@@ -120,7 +121,7 @@ namespace SixLabors.ImageSharp.Tests.ProfilingSandbox
return bld.ToString();
- static string L(string header) => new ('-', header.Length);
+ static string L(string header) => new('-', header.Length);
static string F(string column) => $"{{0,{column.Length}:f3}}";
}
}
diff --git a/tests/ImageSharp.Tests.ProfilingSandbox/Program.cs b/tests/ImageSharp.Tests.ProfilingSandbox/Program.cs
index 9dd7e4c82..e6e82b981 100644
--- a/tests/ImageSharp.Tests.ProfilingSandbox/Program.cs
+++ b/tests/ImageSharp.Tests.ProfilingSandbox/Program.cs
@@ -2,7 +2,6 @@
// Licensed under the Apache License, Version 2.0.
using System;
-using System.Diagnostics;
using SixLabors.ImageSharp.Tests.Formats.Jpg;
using SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations;
using SixLabors.ImageSharp.Tests.ProfilingBenchmarks;
diff --git a/tests/ImageSharp.Tests/Color/ColorTests.CastTo.cs b/tests/ImageSharp.Tests/Color/ColorTests.CastTo.cs
index ee1820de7..3003265ca 100644
--- a/tests/ImageSharp.Tests/Color/ColorTests.CastTo.cs
+++ b/tests/ImageSharp.Tests/Color/ColorTests.CastTo.cs
@@ -66,7 +66,7 @@ namespace SixLabors.ImageSharp.Tests
[Fact]
public void Rgb24()
{
- var source = new Rgb24(1, 22, 231);
+ var source = new Rgb24(1, 22, 231);
// Act:
var color = new Color(source);
@@ -79,7 +79,7 @@ namespace SixLabors.ImageSharp.Tests
[Fact]
public void Bgr24()
{
- var source = new Bgr24(1, 22, 231);
+ var source = new Bgr24(1, 22, 231);
// Act:
var color = new Color(source);
@@ -88,6 +88,28 @@ namespace SixLabors.ImageSharp.Tests
Bgr24 data = color;
Assert.Equal(source, data);
}
+
+ [Fact]
+ public void GenericPixel()
+ {
+ AssertGenericPixel(new RgbaVector(float.Epsilon, 2 * float.Epsilon, float.MaxValue, float.MinValue));
+ AssertGenericPixel(new Rgba64(1, 2, ushort.MaxValue, ushort.MaxValue - 1));
+ AssertGenericPixel(new Rgb48(1, 2, ushort.MaxValue - 1));
+ AssertGenericPixel(new La32(1, ushort.MaxValue - 1));
+ AssertGenericPixel(new L16(ushort.MaxValue - 1));
+ AssertGenericPixel(new Rgba32(1, 2, 255, 254));
+ }
+
+ private static void AssertGenericPixel(TPixel source)
+ where TPixel : unmanaged, IPixel
+ {
+ // Act:
+ var color = Color.FromPixel(source);
+
+ // Assert:
+ TPixel actual = color.ToPixel();
+ Assert.Equal(source, actual);
+ }
}
}
}
diff --git a/tests/ImageSharp.Tests/Common/ConstantsTests.cs b/tests/ImageSharp.Tests/Common/ConstantsTests.cs
index 8180814cd..40a531413 100644
--- a/tests/ImageSharp.Tests/Common/ConstantsTests.cs
+++ b/tests/ImageSharp.Tests/Common/ConstantsTests.cs
@@ -13,4 +13,4 @@ namespace SixLabors.ImageSharp.Tests.Common
Assert.Equal(0.001f, Constants.Epsilon);
}
}
-}
\ No newline at end of file
+}
diff --git a/tests/ImageSharp.Tests/Common/NumericsTests.cs b/tests/ImageSharp.Tests/Common/NumericsTests.cs
index 29eae6d48..62819af49 100644
--- a/tests/ImageSharp.Tests/Common/NumericsTests.cs
+++ b/tests/ImageSharp.Tests/Common/NumericsTests.cs
@@ -34,7 +34,7 @@ namespace SixLabors.ImageSharp.Tests.Common
int expected = 0;
int actual = Numerics.Log2(value);
- Assert.True(expected == actual, $"Expected: {expected}, Actual: {actual}");
+ Assert.Equal(expected, actual);
}
[Fact]
@@ -47,7 +47,7 @@ namespace SixLabors.ImageSharp.Tests.Common
int expected = i;
int actual = Numerics.Log2(value);
- Assert.True(expected == actual, $"Expected: {expected}, Actual: {actual}");
+ Assert.Equal(expected, actual);
}
}
@@ -66,7 +66,35 @@ namespace SixLabors.ImageSharp.Tests.Common
int expected = Log2_ReferenceImplementation(value);
int actual = Numerics.Log2(value);
- Assert.True(expected == actual, $"Expected: {expected}, Actual: {actual}");
+ Assert.Equal(expected, actual);
+ }
+ }
+
+ private static uint DivideCeil_ReferenceImplementation(uint value, uint divisor) => (uint)MathF.Ceiling((float)value / divisor);
+
+ [Fact]
+ public void DivideCeil_DivideZero()
+ {
+ uint expected = 0;
+ uint actual = Numerics.DivideCeil(0, 100);
+
+ Assert.Equal(expected, actual);
+ }
+
+ [Theory]
+ [InlineData(1, 100)]
+ public void DivideCeil_RandomValues(int seed, int count)
+ {
+ var rng = new Random(seed);
+ for (int i = 0; i < count; i++)
+ {
+ uint value = (uint)rng.Next();
+ uint divisor = (uint)rng.Next();
+
+ uint expected = DivideCeil_ReferenceImplementation(value, divisor);
+ uint actual = Numerics.DivideCeil(value, divisor);
+
+ Assert.True(expected == actual, $"Expected: {expected}\nActual: {actual}\n{value} / {divisor} = {expected}");
}
}
}
diff --git a/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs b/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs
index 1f680aa6c..f61e2dc8e 100644
--- a/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs
+++ b/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs
@@ -19,10 +19,7 @@ namespace SixLabors.ImageSharp.Tests.Common
{
private ITestOutputHelper Output { get; }
- public SimdUtilsTests(ITestOutputHelper output)
- {
- this.Output = output;
- }
+ public SimdUtilsTests(ITestOutputHelper output) => this.Output = output;
private static int R(float f) => (int)Math.Round(f, MidpointRounding.AwayFromZero);
@@ -63,7 +60,7 @@ namespace SixLabors.ImageSharp.Tests.Common
private static Vector CreateRandomTestVector(int seed, float min, float max)
{
- var data = new float[Vector.Count];
+ float[] data = new float[Vector.Count];
var rnd = new Random(seed);
@@ -154,7 +151,7 @@ namespace SixLabors.ImageSharp.Tests.Common
float[] source = new Random(seed).GenerateRandomFloatArray(count, 0, 1f);
- var dest = new byte[count];
+ byte[] dest = new byte[count];
SimdUtils.BasicIntrinsics256.BulkConvertNormalizedFloatToByte(source, dest);
@@ -163,25 +160,18 @@ namespace SixLabors.ImageSharp.Tests.Common
Assert.Equal(expected, dest);
}
- public static readonly TheoryData ArraySizesDivisibleBy8 = new TheoryData { 0, 8, 16, 1024 };
- public static readonly TheoryData ArraySizesDivisibleBy4 = new TheoryData { 0, 4, 8, 28, 1020 };
- public static readonly TheoryData ArraySizesDivisibleBy3 = new TheoryData { 0, 3, 9, 36, 957 };
- public static readonly TheoryData ArraySizesDivisibleBy32 = new TheoryData { 0, 32, 512 };
+ public static readonly TheoryData ArraySizesDivisibleBy8 = new() { 0, 8, 16, 1024 };
+ public static readonly TheoryData ArraySizesDivisibleBy4 = new() { 0, 4, 8, 28, 1020 };
+ public static readonly TheoryData ArraySizesDivisibleBy3 = new() { 0, 3, 9, 36, 957 };
+ public static readonly TheoryData ArraySizesDivisibleBy32 = new() { 0, 32, 512 };
- public static readonly TheoryData ArbitraryArraySizes =
- new TheoryData
- {
- 0, 1, 2, 3, 4, 7, 8, 9, 15, 16, 17, 63, 64, 255, 511, 512, 513, 514, 515, 516, 517, 518, 519, 520,
- };
+ public static readonly TheoryData ArbitraryArraySizes = new() { 0, 1, 2, 3, 4, 7, 8, 9, 15, 16, 17, 63, 64, 255, 511, 512, 513, 514, 515, 516, 517, 518, 519, 520 };
[Theory]
[MemberData(nameof(ArraySizesDivisibleBy4))]
- public void FallbackIntrinsics128_BulkConvertByteToNormalizedFloat(int count)
- {
- TestImpl_BulkConvertByteToNormalizedFloat(
+ public void FallbackIntrinsics128_BulkConvertByteToNormalizedFloat(int count) => TestImpl_BulkConvertByteToNormalizedFloat(
count,
(s, d) => SimdUtils.FallbackIntrinsics128.ByteToNormalizedFloat(s.Span, d.Span));
- }
[Theory]
[MemberData(nameof(ArraySizesDivisibleBy8))]
@@ -199,24 +189,23 @@ namespace SixLabors.ImageSharp.Tests.Common
[Theory]
[MemberData(nameof(ArraySizesDivisibleBy32))]
- public void ExtendedIntrinsics_BulkConvertByteToNormalizedFloat(int count)
- {
- TestImpl_BulkConvertByteToNormalizedFloat(
+ public void ExtendedIntrinsics_BulkConvertByteToNormalizedFloat(int count) => TestImpl_BulkConvertByteToNormalizedFloat(
count,
(s, d) => SimdUtils.ExtendedIntrinsics.ByteToNormalizedFloat(s.Span, d.Span));
- }
#if SUPPORTS_RUNTIME_INTRINSICS
[Theory]
[MemberData(nameof(ArraySizesDivisibleBy32))]
public void HwIntrinsics_BulkConvertByteToNormalizedFloat(int count)
{
- static void RunTest(string serialized)
+ if (!Sse2.IsSupported)
{
- TestImpl_BulkConvertByteToNormalizedFloat(
+ return;
+ }
+
+ static void RunTest(string serialized) => TestImpl_BulkConvertByteToNormalizedFloat(
FeatureTestRunner.Deserialize(serialized),
(s, d) => SimdUtils.HwIntrinsics.ByteToNormalizedFloat(s.Span, d.Span));
- }
FeatureTestRunner.RunWithHwIntrinsicsFeature(
RunTest,
@@ -227,20 +216,17 @@ namespace SixLabors.ImageSharp.Tests.Common
[Theory]
[MemberData(nameof(ArbitraryArraySizes))]
- public void BulkConvertByteToNormalizedFloat(int count)
- {
- TestImpl_BulkConvertByteToNormalizedFloat(
+ public void BulkConvertByteToNormalizedFloat(int count) => TestImpl_BulkConvertByteToNormalizedFloat(
count,
(s, d) => SimdUtils.ByteToNormalizedFloat(s.Span, d.Span));
- }
private static void TestImpl_BulkConvertByteToNormalizedFloat(
int count,
Action, Memory> convert)
{
byte[] source = new Random(count).GenerateRandomByteArray(count);
- var result = new float[count];
- float[] expected = source.Select(b => (float)b / 255f).ToArray();
+ float[] result = new float[count];
+ float[] expected = source.Select(b => b / 255f).ToArray();
convert(source, result);
@@ -249,12 +235,9 @@ namespace SixLabors.ImageSharp.Tests.Common
[Theory]
[MemberData(nameof(ArraySizesDivisibleBy4))]
- public void FallbackIntrinsics128_BulkConvertNormalizedFloatToByteClampOverflows(int count)
- {
- TestImpl_BulkConvertNormalizedFloatToByteClampOverflows(
+ public void FallbackIntrinsics128_BulkConvertNormalizedFloatToByteClampOverflows(int count) => TestImpl_BulkConvertNormalizedFloatToByteClampOverflows(
count,
(s, d) => SimdUtils.FallbackIntrinsics128.NormalizedFloatToByteSaturate(s.Span, d.Span));
- }
[Theory]
[MemberData(nameof(ArraySizesDivisibleBy8))]
@@ -270,12 +253,9 @@ namespace SixLabors.ImageSharp.Tests.Common
[Theory]
[MemberData(nameof(ArraySizesDivisibleBy32))]
- public void ExtendedIntrinsics_BulkConvertNormalizedFloatToByteClampOverflows(int count)
- {
- TestImpl_BulkConvertNormalizedFloatToByteClampOverflows(
+ public void ExtendedIntrinsics_BulkConvertNormalizedFloatToByteClampOverflows(int count) => TestImpl_BulkConvertNormalizedFloatToByteClampOverflows(
count,
(s, d) => SimdUtils.ExtendedIntrinsics.NormalizedFloatToByteSaturate(s.Span, d.Span));
- }
[Theory]
[InlineData(1234)]
@@ -304,12 +284,14 @@ namespace SixLabors.ImageSharp.Tests.Common
[MemberData(nameof(ArraySizesDivisibleBy32))]
public void HwIntrinsics_BulkConvertNormalizedFloatToByteClampOverflows(int count)
{
- static void RunTest(string serialized)
+ if (!Sse2.IsSupported)
{
- TestImpl_BulkConvertNormalizedFloatToByteClampOverflows(
+ return;
+ }
+
+ static void RunTest(string serialized) => TestImpl_BulkConvertNormalizedFloatToByteClampOverflows(
FeatureTestRunner.Deserialize(serialized),
(s, d) => SimdUtils.HwIntrinsics.NormalizedFloatToByteSaturate(s.Span, d.Span));
- }
FeatureTestRunner.RunWithHwIntrinsicsFeature(
RunTest,
@@ -326,7 +308,7 @@ namespace SixLabors.ImageSharp.Tests.Common
TestImpl_BulkConvertNormalizedFloatToByteClampOverflows(count, (s, d) => SimdUtils.NormalizedFloatToByteSaturate(s.Span, d.Span));
// For small values, let's stress test the implementation a bit:
- if (count > 0 && count < 10)
+ if (count is > 0 and < 10)
{
for (int i = 0; i < 20; i++)
{
@@ -340,23 +322,17 @@ namespace SixLabors.ImageSharp.Tests.Common
[Theory]
[MemberData(nameof(ArbitraryArraySizes))]
- public void PackFromRgbPlanes_Rgb24(int count)
- {
- TestPackFromRgbPlanes(
+ public void PackFromRgbPlanes_Rgb24(int count) => TestPackFromRgbPlanes(
count,
(r, g, b, actual) =>
SimdUtils.PackFromRgbPlanes(Configuration.Default, r, g, b, actual));
- }
[Theory]
[MemberData(nameof(ArbitraryArraySizes))]
- public void PackFromRgbPlanes_Rgba32(int count)
- {
- TestPackFromRgbPlanes(
+ public void PackFromRgbPlanes_Rgba32(int count) => TestPackFromRgbPlanes(
count,
(r, g, b, actual) =>
SimdUtils.PackFromRgbPlanes(Configuration.Default, r, g, b, actual));
- }
#if SUPPORTS_RUNTIME_INTRINSICS
[Fact]
@@ -371,7 +347,7 @@ namespace SixLabors.ImageSharp.Tests.Common
byte[] g = Enumerable.Range(100, 32).Select(x => (byte)x).ToArray();
byte[] b = Enumerable.Range(200, 32).Select(x => (byte)x).ToArray();
const int padding = 4;
- Rgb24[] d = new Rgb24[32 + padding];
+ var d = new Rgb24[32 + padding];
ReadOnlySpan rr = r.AsSpan();
ReadOnlySpan gg = g.AsSpan();
@@ -405,7 +381,7 @@ namespace SixLabors.ImageSharp.Tests.Common
byte[] g = Enumerable.Range(100, 32).Select(x => (byte)x).ToArray();
byte[] b = Enumerable.Range(200, 32).Select(x => (byte)x).ToArray();
- Rgba32[] d = new Rgba32[32];
+ var d = new Rgba32[32];
ReadOnlySpan rr = r.AsSpan();
ReadOnlySpan gg = g.AsSpan();
@@ -432,18 +408,18 @@ namespace SixLabors.ImageSharp.Tests.Common
internal static void TestPackFromRgbPlanes(int count, Action packMethod)
where TPixel : unmanaged, IPixel
{
- Random rnd = new Random(42);
+ var rnd = new Random(42);
byte[] r = rnd.GenerateRandomByteArray(count);
byte[] g = rnd.GenerateRandomByteArray(count);
byte[] b = rnd.GenerateRandomByteArray(count);
- TPixel[] expected = new TPixel[count];
+ var expected = new TPixel[count];
for (int i = 0; i < count; i++)
{
expected[i].FromRgb24(new Rgb24(r[i], g[i], b[i]));
}
- TPixel[] actual = new TPixel[count + 3]; // padding for Rgb24 AVX2
+ var actual = new TPixel[count + 3]; // padding for Rgb24 AVX2
packMethod(r, g, b, actual);
Assert.True(expected.AsSpan().SequenceEqual(actual.AsSpan().Slice(0, count)));
diff --git a/tests/ImageSharp.Tests/ConfigurationTests.cs b/tests/ImageSharp.Tests/ConfigurationTests.cs
index 3ad8ef2f8..803babdfa 100644
--- a/tests/ImageSharp.Tests/ConfigurationTests.cs
+++ b/tests/ImageSharp.Tests/ConfigurationTests.cs
@@ -21,7 +21,7 @@ namespace SixLabors.ImageSharp.Tests
public Configuration DefaultConfiguration { get; }
- private readonly int expectedDefaultConfigurationCount = 6;
+ private readonly int expectedDefaultConfigurationCount = 7;
public ConfigurationTests()
{
diff --git a/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs
index e64d8452f..4e6dc36dc 100644
--- a/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs
@@ -14,7 +14,6 @@ using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison;
using SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs;
using Xunit;
-
using static SixLabors.ImageSharp.Tests.TestImages.Bmp;
// ReSharper disable InconsistentNaming
@@ -55,7 +54,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Bmp
}
[Theory]
- [WithFileCollection(nameof(MiscBmpFiles), PixelTypes.Rgba32)]
+ [WithFile(Car, PixelTypes.Rgba32)]
+ [WithFile(F, PixelTypes.Rgba32)]
public void BmpDecoder_CanDecode_MiscellaneousBitmaps_WithLimitedAllocatorBufferCapacity(
TestImageProvider provider)
{
diff --git a/tests/ImageSharp.Tests/Formats/Bmp/BmpEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Bmp/BmpEncoderTests.cs
index f338c1aff..d645f0b60 100644
--- a/tests/ImageSharp.Tests/Formats/Bmp/BmpEncoderTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Bmp/BmpEncoderTests.cs
@@ -2,7 +2,6 @@
// Licensed under the Apache License, Version 2.0.
using System.IO;
-
using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.Formats.Bmp;
using SixLabors.ImageSharp.Metadata;
@@ -13,7 +12,6 @@ using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison;
using SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs;
using Xunit;
-
using static SixLabors.ImageSharp.Tests.TestImages.Bmp;
// ReSharper disable InconsistentNaming
diff --git a/tests/ImageSharp.Tests/Formats/Bmp/BmpMetadataTests.cs b/tests/ImageSharp.Tests/Formats/Bmp/BmpMetadataTests.cs
index ea5e8b087..8931c242e 100644
--- a/tests/ImageSharp.Tests/Formats/Bmp/BmpMetadataTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Bmp/BmpMetadataTests.cs
@@ -2,11 +2,9 @@
// Licensed under the Apache License, Version 2.0.
using System.IO;
-
using SixLabors.ImageSharp.Formats.Bmp;
using Xunit;
-
using static SixLabors.ImageSharp.Tests.TestImages.Bmp;
// ReSharper disable InconsistentNaming
diff --git a/tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs b/tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs
index c0843a51b..bf13a9097 100644
--- a/tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs
+++ b/tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs
@@ -16,6 +16,7 @@ using Xunit;
namespace SixLabors.ImageSharp.Tests.Formats
{
+ [Collection("RunSerial")]
public class GeneralFormatTests
{
///
@@ -152,7 +153,7 @@ namespace SixLabors.ImageSharp.Tests.Formats
using (FileStream output = File.OpenWrite(Path.Combine(path, $"{file.FileNameWithoutExtension}.tiff")))
{
- image.SaveAsTga(output);
+ image.SaveAsTiff(output);
}
}
}
diff --git a/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs
index bd24e1a8d..cb0b1521d 100644
--- a/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs
@@ -2,7 +2,6 @@
// Licensed under the Apache License, Version 2.0.
using System.IO;
-
using SixLabors.ImageSharp.Formats.Gif;
using SixLabors.ImageSharp.Metadata;
using SixLabors.ImageSharp.PixelFormats;
diff --git a/tests/ImageSharp.Tests/Formats/Gif/GifMetadataTests.cs b/tests/ImageSharp.Tests/Formats/Gif/GifMetadataTests.cs
index e209586f5..59f7ebb74 100644
--- a/tests/ImageSharp.Tests/Formats/Gif/GifMetadataTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Gif/GifMetadataTests.cs
@@ -4,7 +4,6 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
-
using SixLabors.ImageSharp.Formats.Gif;
using SixLabors.ImageSharp.Metadata;
using SixLabors.ImageSharp.PixelFormats;
@@ -13,6 +12,7 @@ using Xunit;
namespace SixLabors.ImageSharp.Tests.Formats.Gif
{
+ [Collection("RunSerial")]
[Trait("Format", "Gif")]
public class GifMetadataTests
{
diff --git a/tests/ImageSharp.Tests/Formats/ImageFormatManagerTests.cs b/tests/ImageSharp.Tests/Formats/ImageFormatManagerTests.cs
index 1e00bfff8..5cd70b100 100644
--- a/tests/ImageSharp.Tests/Formats/ImageFormatManagerTests.cs
+++ b/tests/ImageSharp.Tests/Formats/ImageFormatManagerTests.cs
@@ -12,6 +12,7 @@ using SixLabors.ImageSharp.Formats.Jpeg;
using SixLabors.ImageSharp.Formats.Png;
using SixLabors.ImageSharp.Formats.Tga;
using SixLabors.ImageSharp.Formats.Tiff;
+using SixLabors.ImageSharp.Formats.Webp;
using SixLabors.ImageSharp.PixelFormats;
using Xunit;
@@ -38,6 +39,7 @@ namespace SixLabors.ImageSharp.Tests.Formats
Assert.Equal(1, this.DefaultFormatsManager.ImageEncoders.Select(item => item.Value).OfType().Count());
Assert.Equal(1, this.DefaultFormatsManager.ImageEncoders.Select(item => item.Value).OfType().Count());
Assert.Equal(1, this.DefaultFormatsManager.ImageEncoders.Select(item => item.Value).OfType().Count());
+ Assert.Equal(1, this.DefaultFormatsManager.ImageEncoders.Select(item => item.Value).OfType().Count());
Assert.Equal(1, this.DefaultFormatsManager.ImageDecoders.Select(item => item.Value).OfType().Count());
Assert.Equal(1, this.DefaultFormatsManager.ImageDecoders.Select(item => item.Value).OfType().Count());
@@ -45,6 +47,7 @@ namespace SixLabors.ImageSharp.Tests.Formats
Assert.Equal(1, this.DefaultFormatsManager.ImageDecoders.Select(item => item.Value).OfType().Count());
Assert.Equal(1, this.DefaultFormatsManager.ImageDecoders.Select(item => item.Value).OfType().Count());
Assert.Equal(1, this.DefaultFormatsManager.ImageDecoders.Select(item => item.Value).OfType().Count());
+ Assert.Equal(1, this.DefaultFormatsManager.ImageDecoders.Select(item => item.Value).OfType().Count());
}
[Fact]
diff --git a/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.cs
index 4effc52b2..e5dc0ba01 100644
--- a/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.cs
@@ -4,8 +4,9 @@
// Uncomment this to turn unit tests into benchmarks:
// #define BENCHMARKING
using System;
-using System.Diagnostics;
-
+#if SUPPORTS_RUNTIME_INTRINSICS
+using System.Runtime.Intrinsics.X86;
+#endif
using SixLabors.ImageSharp.Formats.Jpeg.Components;
using SixLabors.ImageSharp.Tests.Formats.Jpg.Utils;
using SixLabors.ImageSharp.Tests.TestUtilities;
@@ -164,52 +165,27 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
}
[Fact]
- public void TransposeInto()
+ public void TransposeInplace()
{
static void RunTest()
{
float[] expected = Create8x8FloatData();
ReferenceImplementations.Transpose8x8(expected);
- var source = default(Block8x8F);
- source.LoadFrom(Create8x8FloatData());
+ var block8x8 = default(Block8x8F);
+ block8x8.LoadFrom(Create8x8FloatData());
- var dest = default(Block8x8F);
- source.TransposeInto(ref dest);
+ block8x8.TransposeInplace();
float[] actual = new float[64];
- dest.ScaledCopyTo(actual);
+ block8x8.ScaledCopyTo(actual);
Assert.Equal(expected, actual);
}
FeatureTestRunner.RunWithHwIntrinsicsFeature(
RunTest,
- HwIntrinsics.AllowAll | HwIntrinsics.DisableAVX);
- }
-
- private class BufferHolder
- {
- public Block8x8F Buffer;
- }
-
- [Fact]
- public void TransposeInto_Benchmark()
- {
- var source = new BufferHolder();
- source.Buffer.LoadFrom(Create8x8FloatData());
- var dest = new BufferHolder();
-
- this.Output.WriteLine($"TransposeInto_PinningImpl_Benchmark X {Times} ...");
- var sw = Stopwatch.StartNew();
-
- for (int i = 0; i < Times; i++)
- {
- source.Buffer.TransposeInto(ref dest.Buffer);
- }
-
- sw.Stop();
- this.Output.WriteLine($"TransposeInto_PinningImpl_Benchmark finished in {sw.ElapsedMilliseconds} ms");
+ HwIntrinsics.AllowAll | HwIntrinsics.DisableAVX | HwIntrinsics.DisableHWIntrinsic);
}
private static float[] Create8x8ColorCropTestData()
@@ -273,32 +249,44 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
}
[Theory]
- [InlineData(1)]
- [InlineData(2)]
- public unsafe void Quantize(int seed)
+ [InlineData(1, 2)]
+ [InlineData(2, 1)]
+ public void Quantize(int srcSeed, int qtSeed)
{
- var block = default(Block8x8F);
- block.LoadFrom(Create8x8RoundedRandomFloatData(-2000, 2000, seed));
-
- var qt = default(Block8x8F);
- qt.LoadFrom(Create8x8RoundedRandomFloatData(-2000, 2000, seed));
+ static void RunTest(string srcSeedSerialized, string qtSeedSerialized)
+ {
+ int srcSeed = FeatureTestRunner.Deserialize(srcSeedSerialized);
+ int qtSeed = FeatureTestRunner.Deserialize(qtSeedSerialized);
- var unzig = ZigZag.CreateUnzigTable();
+ Block8x8F source = CreateRandomFloatBlock(-2000, 2000, srcSeed);
- int* expectedResults = stackalloc int[Block8x8F.Size];
- ReferenceImplementations.QuantizeRational(&block, expectedResults, &qt, unzig.Data);
+ // Quantization code is used only in jpeg where it's guaranteed that
+ // qunatization valus are greater than 1
+ // Quantize method supports negative numbers by very small numbers can cause troubles
+ Block8x8F quant = CreateRandomFloatBlock(1, 2000, qtSeed);
- var actualResults = default(Block8x8F);
+ // Reference implementation quantizes given block via division
+ Block8x8 expected = default;
+ ReferenceImplementations.Quantize(ref source, ref expected, ref quant, ZigZag.ZigZagOrder);
- Block8x8F.Quantize(ref block, ref actualResults, ref qt, ref unzig);
+ // Actual current implementation quantizes given block via multiplication
+ // With quantization table reciprocal
+ for (int i = 0; i < Block8x8F.Size; i++)
+ {
+ quant[i] = 1f / quant[i];
+ }
- for (int i = 0; i < Block8x8F.Size; i++)
- {
- int expected = expectedResults[i];
- int actual = (int)actualResults[i];
+ Block8x8 actual = default;
+ Block8x8F.Quantize(ref source, ref actual, ref quant);
- Assert.Equal(expected, actual);
+ Assert.True(CompareBlocks(expected, actual, 1, out int diff), $"Blocks are not equal, diff={diff}");
}
+
+ FeatureTestRunner.RunWithHwIntrinsicsFeature(
+ RunTest,
+ srcSeed,
+ qtSeed,
+ HwIntrinsics.AllowAll | HwIntrinsics.DisableAVX | HwIntrinsics.DisableSSE);
}
[Fact]
@@ -368,48 +356,6 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
HwIntrinsics.AllowAll | HwIntrinsics.DisableAVX);
}
- [Theory]
- [InlineData(1)]
- [InlineData(2)]
- [InlineData(3)]
- public unsafe void DequantizeBlock(int seed)
- {
- Block8x8F original = CreateRandomFloatBlock(-500, 500, seed);
- Block8x8F qt = CreateRandomFloatBlock(0, 10, seed + 42);
-
- var unzig = ZigZag.CreateUnzigTable();
-
- Block8x8F expected = original;
- Block8x8F actual = original;
-
- ReferenceImplementations.DequantizeBlock(&expected, &qt, unzig.Data);
- Block8x8F.DequantizeBlock(&actual, &qt, unzig.Data);
-
- this.CompareBlocks(expected, actual, 0);
- }
-
- [Theory]
- [InlineData(1)]
- [InlineData(2)]
- [InlineData(3)]
- public unsafe void ZigZag_CreateDequantizationTable_MultiplicationShouldQuantize(int seed)
- {
- Block8x8F original = CreateRandomFloatBlock(-500, 500, seed);
- Block8x8F qt = CreateRandomFloatBlock(0, 10, seed + 42);
-
- var unzig = ZigZag.CreateUnzigTable();
- Block8x8F zigQt = ZigZag.CreateDequantizationTable(ref qt);
-
- Block8x8F expected = original;
- Block8x8F actual = original;
-
- ReferenceImplementations.DequantizeBlock(&expected, &qt, unzig.Data);
-
- actual.MultiplyInPlace(ref zigQt);
-
- this.CompareBlocks(expected, actual, 0);
- }
-
[Fact]
public void AddToAllInPlace()
{
@@ -462,7 +408,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
short[] data = Create8x8ShortData();
- var source = new Block8x8(data);
+ var source = Block8x8.Load(data);
Block8x8F dest = default;
dest.LoadFromInt16Scalar(ref source);
@@ -483,7 +429,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
short[] data = Create8x8ShortData();
- var source = new Block8x8(data);
+ var source = Block8x8.Load(data);
Block8x8F dest = default;
dest.LoadFromInt16ExtendedAvx2(ref source);
@@ -493,5 +439,96 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
Assert.Equal(data[i], dest[i]);
}
}
+
+ [Fact]
+ public void EqualsToScalar_AllOne()
+ {
+ static void RunTest()
+ {
+ // Fill matrix with valid value
+ Block8x8F block = default;
+ for (int i = 0; i < Block8x8F.Size; i++)
+ {
+ block[i] = 1;
+ }
+
+ bool isEqual = block.EqualsToScalar(1);
+ Assert.True(isEqual);
+ }
+
+ // 2 paths:
+ // 1. DisableFMA - call avx implementation
+ // 3. DisableAvx2 - call fallback code of float implementation
+ FeatureTestRunner.RunWithHwIntrinsicsFeature(
+ RunTest,
+ HwIntrinsics.AllowAll | HwIntrinsics.DisableAVX2);
+ }
+
+ [Theory]
+ [InlineData(10)]
+ public void EqualsToScalar_OneOffEachPosition(int equalsTo)
+ {
+ static void RunTest(string serializedEqualsTo)
+ {
+ int equalsTo = FeatureTestRunner.Deserialize(serializedEqualsTo);
+ int offValue = 0;
+
+ // Fill matrix with valid value
+ Block8x8F block = default;
+ for (int i = 0; i < Block8x8F.Size; i++)
+ {
+ block[i] = equalsTo;
+ }
+
+ // Assert with invalid values at different positions
+ for (int i = 0; i < Block8x8F.Size; i++)
+ {
+ block[i] = offValue;
+
+ bool isEqual = block.EqualsToScalar(equalsTo);
+ Assert.False(isEqual, $"False equality:\n{block}");
+
+ // restore valid value for next iteration assertion
+ block[i] = equalsTo;
+ }
+ }
+
+ // 2 paths:
+ // 1. DisableFMA - call avx implementation
+ // 3. DisableAvx2 - call fallback code of float implementation
+ FeatureTestRunner.RunWithHwIntrinsicsFeature(
+ RunTest,
+ equalsTo,
+ HwIntrinsics.AllowAll | HwIntrinsics.DisableAVX2);
+ }
+
+ [Theory]
+ [InlineData(39)]
+ public void EqualsToScalar_Valid(int equalsTo)
+ {
+ static void RunTest(string serializedEqualsTo)
+ {
+ int equalsTo = FeatureTestRunner.Deserialize(serializedEqualsTo);
+
+ // Fill matrix with valid value
+ Block8x8F block = default;
+ for (int i = 0; i < Block8x8F.Size; i++)
+ {
+ block[i] = equalsTo;
+ }
+
+ // Assert
+ bool isEqual = block.EqualsToScalar(equalsTo);
+ Assert.True(isEqual);
+ }
+
+ // 2 paths:
+ // 1. DisableFMA - call avx implementation
+ // 3. DisableAvx2 - call fallback code of float implementation
+ FeatureTestRunner.RunWithHwIntrinsicsFeature(
+ RunTest,
+ equalsTo,
+ HwIntrinsics.AllowAll | HwIntrinsics.DisableAVX2);
+ }
}
}
diff --git a/tests/ImageSharp.Tests/Formats/Jpg/Block8x8Tests.cs b/tests/ImageSharp.Tests/Formats/Jpg/Block8x8Tests.cs
index 9195f0915..3737cce80 100644
--- a/tests/ImageSharp.Tests/Formats/Jpg/Block8x8Tests.cs
+++ b/tests/ImageSharp.Tests/Formats/Jpg/Block8x8Tests.cs
@@ -1,9 +1,10 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
+using System;
using SixLabors.ImageSharp.Formats.Jpeg.Components;
using SixLabors.ImageSharp.Tests.Formats.Jpg.Utils;
-
+using SixLabors.ImageSharp.Tests.TestUtilities;
using Xunit;
using Xunit.Abstractions;
@@ -22,7 +23,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
{
short[] data = Create8x8ShortData();
- var block = new Block8x8(data);
+ var block = Block8x8.Load(data);
for (int i = 0; i < Block8x8.Size; i++)
{
@@ -43,32 +44,12 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
Assert.Equal(42, block[42]);
}
- [Fact]
- public unsafe void Indexer_GetScalarAt_SetScalarAt()
- {
- int sum;
- var block = default(Block8x8);
-
- for (int i = 0; i < Block8x8.Size; i++)
- {
- Block8x8.SetScalarAt(&block, i, (short)i);
- }
-
- sum = 0;
- for (int i = 0; i < Block8x8.Size; i++)
- {
- sum += Block8x8.GetScalarAt(&block, i);
- }
-
- Assert.Equal(sum, 64 * 63 / 2);
- }
-
[Fact]
public void AsFloatBlock()
{
short[] data = Create8x8ShortData();
- var source = new Block8x8(data);
+ var source = Block8x8.Load(data);
Block8x8F dest = source.AsFloatBlock();
@@ -82,7 +63,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
public void ToArray()
{
short[] data = Create8x8ShortData();
- var block = new Block8x8(data);
+ var block = Block8x8.Load(data);
short[] result = block.ToArray();
@@ -93,8 +74,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
public void Equality_WhenTrue()
{
short[] data = Create8x8ShortData();
- var block1 = new Block8x8(data);
- var block2 = new Block8x8(data);
+ var block1 = Block8x8.Load(data);
+ var block2 = Block8x8.Load(data);
block1[0] = 42;
block2[0] = 42;
@@ -107,8 +88,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
public void Equality_WhenFalse()
{
short[] data = Create8x8ShortData();
- var block1 = new Block8x8(data);
- var block2 = new Block8x8(data);
+ var block1 = Block8x8.Load(data);
+ var block2 = Block8x8.Load(data);
block1[0] = 42;
block2[0] = 666;
@@ -131,8 +112,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
public void TotalDifference()
{
short[] data = Create8x8ShortData();
- var block1 = new Block8x8(data);
- var block2 = new Block8x8(data);
+ var block1 = Block8x8.Load(data);
+ var block2 = Block8x8.Load(data);
block2[10] += 7;
block2[63] += 8;
@@ -141,5 +122,159 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
Assert.Equal(15, d);
}
+
+ [Fact]
+ public void GetLastNonZeroIndex_AllZero()
+ {
+ static void RunTest()
+ {
+ Block8x8 data = default;
+
+ nint expected = -1;
+
+ nint actual = data.GetLastNonZeroIndex();
+
+ Assert.Equal(expected, actual);
+ }
+
+ FeatureTestRunner.RunWithHwIntrinsicsFeature(
+ RunTest,
+ HwIntrinsics.AllowAll | HwIntrinsics.DisableAVX2);
+ }
+
+ [Fact]
+ public void GetLastNonZeroIndex_AllNonZero()
+ {
+ static void RunTest()
+ {
+ Block8x8 data = default;
+ for (int i = 0; i < Block8x8.Size; i++)
+ {
+ data[i] = 10;
+ }
+
+ nint expected = Block8x8.Size - 1;
+
+ nint actual = data.GetLastNonZeroIndex();
+
+ Assert.Equal(expected, actual);
+ }
+
+ FeatureTestRunner.RunWithHwIntrinsicsFeature(
+ RunTest,
+ HwIntrinsics.AllowAll | HwIntrinsics.DisableAVX2);
+ }
+
+ [Theory]
+ [InlineData(1)]
+ [InlineData(2)]
+ public void GetLastNonZeroIndex_RandomFilledSingle(int seed)
+ {
+ static void RunTest(string seedSerialized)
+ {
+ int seed = FeatureTestRunner.Deserialize(seedSerialized);
+ var rng = new Random(seed);
+
+ for (int i = 0; i < 1000; i++)
+ {
+ Block8x8 data = default;
+
+ int setIndex = rng.Next(1, Block8x8.Size);
+ data[setIndex] = (short)rng.Next(-2000, 2000);
+
+ nint expected = setIndex;
+
+ nint actual = data.GetLastNonZeroIndex();
+
+ Assert.Equal(expected, actual);
+ }
+ }
+
+ FeatureTestRunner.RunWithHwIntrinsicsFeature(
+ RunTest,
+ seed,
+ HwIntrinsics.AllowAll | HwIntrinsics.DisableAVX2);
+ }
+
+ [Theory]
+ [InlineData(1)]
+ [InlineData(2)]
+ public void GetLastNonZeroIndex_RandomFilledPartially(int seed)
+ {
+ static void RunTest(string seedSerialized)
+ {
+ int seed = FeatureTestRunner.Deserialize(seedSerialized);
+ var rng = new Random(seed);
+
+ for (int i = 0; i < 1000; i++)
+ {
+ Block8x8 data = default;
+
+ int lastIndex = rng.Next(1, Block8x8.Size);
+ short fillValue = (short)rng.Next(-2000, 2000);
+ for (int dataIndex = 0; dataIndex <= lastIndex; dataIndex++)
+ {
+ data[dataIndex] = fillValue;
+ }
+
+ int expected = lastIndex;
+
+ nint actual = data.GetLastNonZeroIndex();
+
+ Assert.Equal(expected, actual);
+ }
+ }
+
+ FeatureTestRunner.RunWithHwIntrinsicsFeature(
+ RunTest,
+ seed,
+ HwIntrinsics.AllowAll | HwIntrinsics.DisableAVX2);
+ }
+
+ [Theory]
+ [InlineData(1)]
+ [InlineData(2)]
+ public void GetLastNonZeroIndex_RandomFilledFragmented(int seed)
+ {
+ static void RunTest(string seedSerialized)
+ {
+ int seed = FeatureTestRunner.Deserialize(seedSerialized);
+ var rng = new Random(seed);
+
+ for (int i = 0; i < 1000; i++)
+ {
+ Block8x8 data = default;
+
+ short fillValue = (short)rng.Next(-2000, 2000);
+
+ // first filled chunk
+ int firstChunkStart = rng.Next(0, Block8x8.Size / 2);
+ int firstChunkEnd = rng.Next(firstChunkStart, Block8x8.Size / 2);
+ for (int dataIdx = firstChunkStart; dataIdx <= firstChunkEnd; dataIdx++)
+ {
+ data[dataIdx] = fillValue;
+ }
+
+ // second filled chunk, there might be a spot with zero(s) between first and second chunk
+ int secondChunkStart = rng.Next(firstChunkEnd, Block8x8.Size);
+ int secondChunkEnd = rng.Next(secondChunkStart, Block8x8.Size);
+ for (int dataIdx = secondChunkStart; dataIdx <= secondChunkEnd; dataIdx++)
+ {
+ data[dataIdx] = fillValue;
+ }
+
+ int expected = secondChunkEnd;
+
+ nint actual = data.GetLastNonZeroIndex();
+
+ Assert.True(expected == actual, $"Expected: {expected}\nActual: {actual}\nInput matrix: {data}");
+ }
+ }
+
+ FeatureTestRunner.RunWithHwIntrinsicsFeature(
+ RunTest,
+ seed,
+ HwIntrinsics.AllowAll | HwIntrinsics.DisableAVX2);
+ }
}
}
diff --git a/tests/ImageSharp.Tests/Formats/Jpg/DCTTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/DCTTests.cs
index d49a6498c..0a49d20cd 100644
--- a/tests/ImageSharp.Tests/Formats/Jpg/DCTTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Jpg/DCTTests.cs
@@ -33,15 +33,14 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
{
float[] sourceArray = Create8x8RoundedRandomFloatData(-1000, 1000, seed);
- var source = Block8x8F.Load(sourceArray);
+ var srcBlock = Block8x8F.Load(sourceArray);
- Block8x8F expected = ReferenceImplementations.LLM_FloatingPoint_DCT.TransformIDCT(ref source);
+ Block8x8F expected = ReferenceImplementations.LLM_FloatingPoint_DCT.TransformIDCT(ref srcBlock);
var temp = default(Block8x8F);
- var actual = default(Block8x8F);
- FastFloatingPointDCT.TransformIDCT(ref source, ref actual, ref temp);
+ FastFloatingPointDCT.TransformIDCT(ref srcBlock, ref temp);
- this.CompareBlocks(expected, actual, 1f);
+ this.CompareBlocks(expected, srcBlock, 1f);
}
[Theory]
@@ -52,15 +51,14 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
{
float[] sourceArray = Create8x8RoundedRandomFloatData(-1000, 1000, seed);
- var source = Block8x8F.Load(sourceArray);
+ var srcBlock = Block8x8F.Load(sourceArray);
- Block8x8F expected = ReferenceImplementations.AccurateDCT.TransformIDCT(ref source);
+ Block8x8F expected = ReferenceImplementations.AccurateDCT.TransformIDCT(ref srcBlock);
var temp = default(Block8x8F);
- var actual = default(Block8x8F);
- FastFloatingPointDCT.TransformIDCT(ref source, ref actual, ref temp);
+ FastFloatingPointDCT.TransformIDCT(ref srcBlock, ref temp);
- this.CompareBlocks(expected, actual, 1f);
+ this.CompareBlocks(expected, srcBlock, 1f);
}
// Inverse transform
@@ -120,24 +118,19 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
public void IDCT8x8_Avx(int seed)
{
#if SUPPORTS_RUNTIME_INTRINSICS
- var skip = !Avx.IsSupported;
-#else
- var skip = true;
-#endif
-
- if (skip)
+ if (!Avx.IsSupported)
{
this.Output.WriteLine("No AVX present, skipping test!");
return;
}
Span src = Create8x8RoundedRandomFloatData(-200, 200, seed);
- var srcBlock = default(Block8x8F);
+ Block8x8F srcBlock = default;
srcBlock.LoadFrom(src);
- var destBlock = default(Block8x8F);
+ Block8x8F destBlock = default;
- var expectedDest = new float[64];
+ float[] expectedDest = new float[64];
// reference, left part
ReferenceImplementations.LLM_FloatingPoint_DCT.IDCT2D8x4_32f(src, expectedDest);
@@ -148,10 +141,11 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
// testee, whole 8x8
FastFloatingPointDCT.IDCT8x8_Avx(ref srcBlock, ref destBlock);
- var actualDest = new float[64];
+ float[] actualDest = new float[64];
destBlock.ScaledCopyTo(actualDest);
Assert.Equal(actualDest, expectedDest, new ApproximateFloatComparer(1f));
+#endif
}
[Theory]
@@ -167,8 +161,6 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
var srcBlock = default(Block8x8F);
srcBlock.LoadFrom(src);
- var destBlock = default(Block8x8F);
-
var expectedDest = new float[64];
var temp1 = new float[64];
var temp2 = default(Block8x8F);
@@ -177,10 +169,10 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
ReferenceImplementations.LLM_FloatingPoint_DCT.IDCT2D_llm(src, expectedDest, temp1);
// testee
- FastFloatingPointDCT.TransformIDCT(ref srcBlock, ref destBlock, ref temp2);
+ FastFloatingPointDCT.TransformIDCT(ref srcBlock, ref temp2);
var actualDest = new float[64];
- destBlock.ScaledCopyTo(actualDest);
+ srcBlock.ScaledCopyTo(actualDest);
Assert.Equal(actualDest, expectedDest, new ApproximateFloatComparer(1f));
}
@@ -198,95 +190,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
}
// Forward transform
- [Theory]
- [InlineData(1)]
- [InlineData(2)]
- public void FDCT8x4_LeftPart(int seed)
- {
- Span src = Create8x8RoundedRandomFloatData(-200, 200, seed);
- var srcBlock = default(Block8x8F);
- srcBlock.LoadFrom(src);
-
- var destBlock = default(Block8x8F);
-
- var expectedDest = new float[64];
-
- // reference
- ReferenceImplementations.LLM_FloatingPoint_DCT.FDCT2D8x4_32f(src, expectedDest);
-
- // testee
- FastFloatingPointDCT.FDCT8x4_LeftPart(ref srcBlock, ref destBlock);
-
- var actualDest = new float[64];
- destBlock.ScaledCopyTo(actualDest);
-
- Assert.Equal(actualDest, expectedDest, new ApproximateFloatComparer(1f));
- }
-
- [Theory]
- [InlineData(1)]
- [InlineData(2)]
- public void FDCT8x4_RightPart(int seed)
- {
- Span src = Create8x8RoundedRandomFloatData(-200, 200, seed);
- var srcBlock = default(Block8x8F);
- srcBlock.LoadFrom(src);
-
- var destBlock = default(Block8x8F);
-
- var expectedDest = new float[64];
-
- // reference
- ReferenceImplementations.LLM_FloatingPoint_DCT.FDCT2D8x4_32f(src.Slice(4), expectedDest.AsSpan(4));
-
- // testee
- FastFloatingPointDCT.FDCT8x4_RightPart(ref srcBlock, ref destBlock);
-
- var actualDest = new float[64];
- destBlock.ScaledCopyTo(actualDest);
-
- Assert.Equal(actualDest, expectedDest, new ApproximateFloatComparer(1f));
- }
-
- [Theory]
- [InlineData(1)]
- [InlineData(2)]
- public void FDCT8x8_Avx(int seed)
- {
-#if SUPPORTS_RUNTIME_INTRINSICS
- var skip = !Avx.IsSupported;
-#else
- var skip = true;
-#endif
- if (skip)
- {
- this.Output.WriteLine("No AVX present, skipping test!");
- return;
- }
-
- Span src = Create8x8RoundedRandomFloatData(-200, 200, seed);
- var srcBlock = default(Block8x8F);
- srcBlock.LoadFrom(src);
-
- var destBlock = default(Block8x8F);
-
- var expectedDest = new float[64];
-
- // reference, left part
- ReferenceImplementations.LLM_FloatingPoint_DCT.FDCT2D8x4_32f(src, expectedDest);
-
- // reference, right part
- ReferenceImplementations.LLM_FloatingPoint_DCT.FDCT2D8x4_32f(src.Slice(4), expectedDest.AsSpan(4));
-
- // testee, whole 8x8
- FastFloatingPointDCT.FDCT8x8_Avx(ref srcBlock, ref destBlock);
-
- var actualDest = new float[64];
- destBlock.ScaledCopyTo(actualDest);
-
- Assert.Equal(actualDest, expectedDest, new ApproximateFloatComparer(1f));
- }
-
+ // This test covers entire FDCT conversions chain
+ // This test checks all implementations: intrinsic and scalar fallback
[Theory]
[InlineData(1)]
[InlineData(2)]
@@ -297,37 +202,38 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
int seed = FeatureTestRunner.Deserialize(serialized);
Span src = Create8x8RoundedRandomFloatData(-200, 200, seed);
- var srcBlock = default(Block8x8F);
- srcBlock.LoadFrom(src);
-
- var destBlock = default(Block8x8F);
+ var block = default(Block8x8F);
+ block.LoadFrom(src);
- var expectedDest = new float[64];
- var temp1 = new float[64];
- var temp2 = default(Block8x8F);
+ float[] expectedDest = new float[64];
+ float[] temp1 = new float[64];
// reference
ReferenceImplementations.LLM_FloatingPoint_DCT.FDCT2D_llm(src, expectedDest, temp1, downscaleBy8: true);
// testee
- FastFloatingPointDCT.TransformFDCT(ref srcBlock, ref destBlock, ref temp2, false);
+ // Part of the FDCT calculations is fused into the quantization step
+ // We must multiply transformed block with reciprocal values from FastFloatingPointDCT.ANN_DCT_reciprocalAdjustmen
+ FastFloatingPointDCT.TransformFDCT(ref block);
+ for (int i = 0; i < 64; i++)
+ {
+ block[i] = block[i] * FastFloatingPointDCT.DctReciprocalAdjustmentCoefficients[i];
+ }
- var actualDest = new float[64];
- destBlock.ScaledCopyTo(actualDest);
+ float[] actualDest = block.ToArray();
- Assert.Equal(actualDest, expectedDest, new ApproximateFloatComparer(1f));
+ Assert.Equal(expectedDest, actualDest, new ApproximateFloatComparer(1f));
}
// 3 paths:
// 1. AllowAll - call avx/fma implementation
// 2. DisableFMA - call avx implementation without fma acceleration
- // 3. DisableAvx - call fallback code of Vector4 implementation
- //
- // DisableSSE isn't needed because fallback Vector4 code will compile to either sse or fallback code with same result
+ // 3. DisableAvx - call sse implementation
+ // 4. DisableHWIntrinsic - call scalar fallback implementation
FeatureTestRunner.RunWithHwIntrinsicsFeature(
RunTest,
seed,
- HwIntrinsics.AllowAll | HwIntrinsics.DisableFMA | HwIntrinsics.DisableAVX);
+ HwIntrinsics.AllowAll | HwIntrinsics.DisableFMA | HwIntrinsics.DisableAVX | HwIntrinsics.DisableHWIntrinsic);
}
}
}
diff --git a/tests/ImageSharp.Tests/Formats/Jpg/GenericBlock8x8Tests.cs b/tests/ImageSharp.Tests/Formats/Jpg/GenericBlock8x8Tests.cs
index c0f3b6a6a..d5ee2a2b8 100644
--- a/tests/ImageSharp.Tests/Formats/Jpg/GenericBlock8x8Tests.cs
+++ b/tests/ImageSharp.Tests/Formats/Jpg/GenericBlock8x8Tests.cs
@@ -2,7 +2,6 @@
// Licensed under the Apache License, Version 2.0.
using System;
-
using SixLabors.ImageSharp.Formats.Jpeg.Components;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
diff --git a/tests/ImageSharp.Tests/Formats/Jpg/HuffmanScanEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/HuffmanScanEncoderTests.cs
index b953e80b8..42f2fa0d5 100644
--- a/tests/ImageSharp.Tests/Formats/Jpg/HuffmanScanEncoderTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Jpg/HuffmanScanEncoderTests.cs
@@ -85,157 +85,5 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
Assert.Equal(expected, actual);
}
}
-
- [Fact]
- public void GetLastValuableElementIndex_AllZero()
- {
- static void RunTest()
- {
- Block8x8F data = default;
-
- int expectedLessThan = 1;
-
- int actual = HuffmanScanEncoder.GetLastValuableElementIndex(ref data);
-
- Assert.True(actual < expectedLessThan);
- }
-
- FeatureTestRunner.RunWithHwIntrinsicsFeature(
- RunTest,
- HwIntrinsics.AllowAll | HwIntrinsics.DisableAVX2);
- }
-
- [Fact]
- public void GetLastValuableElementIndex_AllNonZero()
- {
- static void RunTest()
- {
- Block8x8F data = default;
- for (int i = 0; i < Block8x8F.Size; i++)
- {
- data[i] = 10;
- }
-
- int expected = Block8x8F.Size - 1;
-
- int actual = HuffmanScanEncoder.GetLastValuableElementIndex(ref data);
-
- Assert.Equal(expected, actual);
- }
-
- FeatureTestRunner.RunWithHwIntrinsicsFeature(
- RunTest,
- HwIntrinsics.AllowAll | HwIntrinsics.DisableAVX2);
- }
-
- [Theory]
- [InlineData(1)]
- [InlineData(2)]
- public void GetLastValuableElementIndex_RandomFilledSingle(int seed)
- {
- static void RunTest(string seedSerialized)
- {
- int seed = FeatureTestRunner.Deserialize(seedSerialized);
- var rng = new Random(seed);
-
- for (int i = 0; i < 1000; i++)
- {
- Block8x8F data = default;
-
- int setIndex = rng.Next(1, Block8x8F.Size);
- data[setIndex] = rng.Next();
-
- int expected = setIndex;
-
- int actual = HuffmanScanEncoder.GetLastValuableElementIndex(ref data);
-
- Assert.Equal(expected, actual);
- }
- }
-
- FeatureTestRunner.RunWithHwIntrinsicsFeature(
- RunTest,
- seed,
- HwIntrinsics.AllowAll | HwIntrinsics.DisableAVX2);
- }
-
- [Theory]
- [InlineData(1)]
- [InlineData(2)]
- public void GetLastValuableElementIndex_RandomFilledPartially(int seed)
- {
- static void RunTest(string seedSerialized)
- {
- int seed = FeatureTestRunner.Deserialize(seedSerialized);
- var rng = new Random(seed);
-
- for (int i = 0; i < 1000; i++)
- {
- Block8x8F data = default;
-
- int lastIndex = rng.Next(1, Block8x8F.Size);
- int fillValue = rng.Next();
- for (int dataIndex = 0; dataIndex <= lastIndex; dataIndex++)
- {
- data[dataIndex] = fillValue;
- }
-
- int expected = lastIndex;
-
- int actual = HuffmanScanEncoder.GetLastValuableElementIndex(ref data);
-
- Assert.Equal(expected, actual);
- }
- }
-
- FeatureTestRunner.RunWithHwIntrinsicsFeature(
- RunTest,
- seed,
- HwIntrinsics.AllowAll | HwIntrinsics.DisableAVX2);
- }
-
- [Theory]
- [InlineData(1)]
- [InlineData(2)]
- public void GetLastValuableElementIndex_RandomFilledFragmented(int seed)
- {
- static void RunTest(string seedSerialized)
- {
- int seed = FeatureTestRunner.Deserialize(seedSerialized);
- var rng = new Random(seed);
-
- for (int i = 0; i < 1000; i++)
- {
- Block8x8F data = default;
-
- int fillValue = rng.Next();
-
- // first filled chunk
- int lastIndex1 = rng.Next(1, Block8x8F.Size / 2);
- for (int dataIndex = 0; dataIndex <= lastIndex1; dataIndex++)
- {
- data[dataIndex] = fillValue;
- }
-
- // second filled chunk, there might be a spot with zero(s) between first and second chunk
- int lastIndex2 = rng.Next(lastIndex1 + 1, Block8x8F.Size);
- for (int dataIndex = 0; dataIndex <= lastIndex2; dataIndex++)
- {
- data[dataIndex] = fillValue;
- }
-
- int expected = lastIndex2;
-
- int actual = HuffmanScanEncoder.GetLastValuableElementIndex(ref data);
-
- Assert.Equal(expected, actual);
- }
- }
-
- FeatureTestRunner.RunWithHwIntrinsicsFeature(
- RunTest,
- seed,
- HwIntrinsics.AllowAll | HwIntrinsics.DisableAVX2);
- }
}
}
diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs
index 5f0562146..4e0970e3b 100644
--- a/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs
@@ -3,7 +3,6 @@
using System;
using System.Numerics;
-
using SixLabors.ImageSharp.ColorSpaces;
using SixLabors.ImageSharp.ColorSpaces.Conversion;
using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder;
@@ -356,13 +355,13 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
JpegColorConverter converter = simd ? (JpegColorConverter)new JpegColorConverter.FromYCbCrVector4(8) : new JpegColorConverter.FromYCbCrBasic(8);
// Warm up:
- converter.ConvertToRgba(values, result);
+ converter.ConvertToRgbInplace(values);
using (new MeasureGuard(this.Output, $"{converter.GetType().Name} x {times}"))
{
for (int i = 0; i < times; i++)
{
- converter.ConvertToRgba(values, result);
+ converter.ConvertToRgbInplace(values);
}
}
}
@@ -375,6 +374,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
float maxVal = 255f)
{
var rnd = new Random(seed);
+
var buffers = new Buffer2D[componentCount];
for (int i = 0; i < componentCount; i++)
{
@@ -416,39 +416,48 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
int resultBufferLength,
int seed)
{
- JpegColorConverter.ComponentValues values = CreateRandomValues(componentCount, inputBufferLength, seed);
- var result = new Vector4[resultBufferLength];
+ JpegColorConverter.ComponentValues original = CreateRandomValues(componentCount, inputBufferLength, seed);
+ JpegColorConverter.ComponentValues values = Copy(original);
- converter.ConvertToRgba(values, result);
+ converter.ConvertToRgbInplace(values);
for (int i = 0; i < resultBufferLength; i++)
{
- Validate(converter.ColorSpace, values, result, i);
+ Validate(converter.ColorSpace, original, values, i);
+ }
+
+ static JpegColorConverter.ComponentValues Copy(JpegColorConverter.ComponentValues values)
+ {
+ Span c0 = values.Component0.ToArray();
+ Span c1 = values.ComponentCount > 1 ? values.Component1.ToArray().AsSpan() : c0;
+ Span c2 = values.ComponentCount > 2 ? values.Component2.ToArray().AsSpan() : c0;
+ Span c3 = values.ComponentCount > 3 ? values.Component3.ToArray().AsSpan() : Span.Empty;
+ return new JpegColorConverter.ComponentValues(values.ComponentCount, c0, c1, c2, c3);
}
}
private static void Validate(
JpegColorSpace colorSpace,
- in JpegColorConverter.ComponentValues values,
- Vector4[] result,
+ in JpegColorConverter.ComponentValues original,
+ in JpegColorConverter.ComponentValues result,
int i)
{
switch (colorSpace)
{
case JpegColorSpace.Grayscale:
- ValidateGrayScale(values, result, i);
+ ValidateGrayScale(original, result, i);
break;
case JpegColorSpace.Ycck:
- ValidateCyyK(values, result, i);
+ ValidateCyyK(original, result, i);
break;
case JpegColorSpace.Cmyk:
- ValidateCmyk(values, result, i);
+ ValidateCmyk(original, result, i);
break;
case JpegColorSpace.RGB:
- ValidateRgb(values, result, i);
+ ValidateRgb(original, result, i);
break;
case JpegColorSpace.YCbCr:
- ValidateYCbCr(values, result, i);
+ ValidateYCbCr(original, result, i);
break;
default:
Assert.True(false, $"Colorspace {colorSpace} not supported!");
@@ -456,22 +465,20 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
}
}
- private static void ValidateYCbCr(in JpegColorConverter.ComponentValues values, Vector4[] result, int i)
+ private static void ValidateYCbCr(in JpegColorConverter.ComponentValues values, in JpegColorConverter.ComponentValues result, int i)
{
float y = values.Component0[i];
float cb = values.Component1[i];
float cr = values.Component2[i];
var ycbcr = new YCbCr(y, cb, cr);
- Vector4 rgba = result[i];
- var actual = new Rgb(rgba.X, rgba.Y, rgba.Z);
+ var actual = new Rgb(result.Component0[i], result.Component1[i], result.Component2[i]);
var expected = ColorSpaceConverter.ToRgb(ycbcr);
Assert.Equal(expected, actual, ColorSpaceComparer);
- Assert.Equal(1, rgba.W);
}
- private static void ValidateCyyK(in JpegColorConverter.ComponentValues values, Vector4[] result, int i)
+ private static void ValidateCyyK(in JpegColorConverter.ComponentValues values, in JpegColorConverter.ComponentValues result, int i)
{
var v = new Vector4(0, 0, 0, 1F);
var scale = new Vector4(1 / 255F, 1 / 255F, 1 / 255F, 1F);
@@ -490,39 +497,34 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
v *= scale;
- Vector4 rgba = result[i];
- var actual = new Rgb(rgba.X, rgba.Y, rgba.Z);
+ var actual = new Rgb(result.Component0[i], result.Component1[i], result.Component2[i]);
var expected = new Rgb(v.X, v.Y, v.Z);
Assert.Equal(expected, actual, ColorSpaceComparer);
- Assert.Equal(1, rgba.W);
}
- private static void ValidateRgb(in JpegColorConverter.ComponentValues values, Vector4[] result, int i)
+ private static void ValidateRgb(in JpegColorConverter.ComponentValues values, in JpegColorConverter.ComponentValues result, int i)
{
float r = values.Component0[i];
float g = values.Component1[i];
float b = values.Component2[i];
- Vector4 rgba = result[i];
- var actual = new Rgb(rgba.X, rgba.Y, rgba.Z);
+
+ var actual = new Rgb(result.Component0[i], result.Component1[i], result.Component2[i]);
var expected = new Rgb(r / 255F, g / 255F, b / 255F);
Assert.Equal(expected, actual, ColorSpaceComparer);
- Assert.Equal(1, rgba.W);
}
- private static void ValidateGrayScale(in JpegColorConverter.ComponentValues values, Vector4[] result, int i)
+ private static void ValidateGrayScale(in JpegColorConverter.ComponentValues values, in JpegColorConverter.ComponentValues result, int i)
{
float y = values.Component0[i];
- Vector4 rgba = result[i];
- var actual = new Rgb(rgba.X, rgba.Y, rgba.Z);
+ var actual = new Rgb(result.Component0[i], result.Component0[i], result.Component0[i]);
var expected = new Rgb(y / 255F, y / 255F, y / 255F);
Assert.Equal(expected, actual, ColorSpaceComparer);
- Assert.Equal(1, rgba.W);
}
- private static void ValidateCmyk(in JpegColorConverter.ComponentValues values, Vector4[] result, int i)
+ private static void ValidateCmyk(in JpegColorConverter.ComponentValues values, in JpegColorConverter.ComponentValues result, int i)
{
var v = new Vector4(0, 0, 0, 1F);
var scale = new Vector4(1 / 255F, 1 / 255F, 1 / 255F, 1F);
@@ -539,12 +541,10 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
v *= scale;
- Vector4 rgba = result[i];
- var actual = new Rgb(rgba.X, rgba.Y, rgba.Z);
+ var actual = new Rgb(result.Component0[i], result.Component1[i], result.Component2[i]);
var expected = new Rgb(v.X, v.Y, v.Z);
Assert.Equal(expected, actual, ColorSpaceComparer);
- Assert.Equal(1, rgba.W);
}
}
}
diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Baseline.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Baseline.cs
index 7002bfd65..021e3d272 100644
--- a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Baseline.cs
+++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Baseline.cs
@@ -13,9 +13,9 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
public partial class JpegDecoderTests
{
[Theory]
- [WithFileCollection(nameof(BaselineTestJpegs), PixelTypes.Rgba32, false)]
- [WithFile(TestImages.Jpeg.Baseline.Calliphora, PixelTypes.Rgba32, true)]
- [WithFile(TestImages.Jpeg.Baseline.Turtle420, PixelTypes.Rgba32, true)]
+ [WithFileCollection(nameof(BaselineTestJpegs), PixelTypes.Rgb24, false)]
+ [WithFile(TestImages.Jpeg.Baseline.Calliphora, PixelTypes.Rgb24, true)]
+ [WithFile(TestImages.Jpeg.Baseline.Turtle420, PixelTypes.Rgb24, true)]
public void DecodeBaselineJpeg(TestImageProvider provider, bool enforceDiscontiguousBuffers)
where TPixel : unmanaged, IPixel
{
@@ -26,7 +26,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
if (!string.IsNullOrEmpty(nonContiguousBuffersStr))
{
- provider.LimitAllocatorBufferCapacity().InPixels(1000 * 8);
+ provider.LimitAllocatorBufferCapacity().InPixels(16_000);
}
using Image image = provider.GetImage(JpegDecoder);
diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Images.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Images.cs
index 2faea2611..d12240cba 100644
--- a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Images.cs
+++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Images.cs
@@ -17,8 +17,6 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
TestImages.Jpeg.Baseline.Jpeg400,
TestImages.Jpeg.Baseline.Turtle420,
TestImages.Jpeg.Baseline.Testorig420,
-
- // BUG: The following image has a high difference compared to the expected output: 1.0096%
TestImages.Jpeg.Baseline.Jpeg420Small,
TestImages.Jpeg.Issues.Fuzz.AccessViolationException922,
TestImages.Jpeg.Baseline.Jpeg444,
@@ -89,7 +87,9 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
TestImages.Jpeg.Issues.Fuzz.ArgumentException826B,
TestImages.Jpeg.Issues.Fuzz.ArgumentException826C,
TestImages.Jpeg.Issues.Fuzz.AccessViolationException827,
- TestImages.Jpeg.Issues.Fuzz.ExecutionEngineException839
+ TestImages.Jpeg.Issues.Fuzz.ExecutionEngineException839,
+ TestImages.Jpeg.Issues.Fuzz.IndexOutOfRangeException1693A,
+ TestImages.Jpeg.Issues.Fuzz.IndexOutOfRangeException1693B
};
private static readonly Dictionary CustomToleranceValues =
@@ -101,7 +101,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
[TestImages.Jpeg.Baseline.Bad.BadRST] = 0.0589f / 100,
[TestImages.Jpeg.Baseline.Testorig420] = 0.38f / 100,
- [TestImages.Jpeg.Baseline.Jpeg420Small] = 1.1f / 100,
+ [TestImages.Jpeg.Baseline.Jpeg420Small] = 0.287f / 100,
[TestImages.Jpeg.Baseline.Turtle420] = 1.0f / 100,
// Progressive:
diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Metadata.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Metadata.cs
index f47ae5522..5e42c6c8f 100644
--- a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Metadata.cs
+++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Metadata.cs
@@ -4,7 +4,6 @@
using System;
using System.IO;
using System.Runtime.CompilerServices;
-
using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.Formats.Jpeg;
using SixLabors.ImageSharp.Metadata;
@@ -55,7 +54,9 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
{
{ TestImages.Jpeg.Baseline.Calliphora, 80 },
{ TestImages.Jpeg.Progressive.Fb, 75 },
- { TestImages.Jpeg.Issues.IncorrectQuality845, 99 }
+ { TestImages.Jpeg.Issues.IncorrectQuality845, 98 },
+ { TestImages.Jpeg.Baseline.ForestBridgeDifferentComponentsQuality, 89 },
+ { TestImages.Jpeg.Progressive.Winter, 80 }
};
[Theory]
@@ -65,16 +66,13 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
string imagePath,
int expectedPixelSize,
bool exifProfilePresent,
- bool iccProfilePresent)
- {
- TestMetadataImpl(
+ bool iccProfilePresent) => TestMetadataImpl(
useIdentify,
JpegDecoder,
imagePath,
expectedPixelSize,
exifProfilePresent,
iccProfilePresent);
- }
[Theory]
[MemberData(nameof(RatioFiles))]
@@ -84,7 +82,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
using (var stream = new MemoryStream(testFile.Bytes, false))
{
var decoder = new JpegDecoder();
- using (Image image = decoder.Decode(Configuration.Default, stream))
+ using (Image image = decoder.Decode(Configuration.Default, stream))
{
ImageMetadata meta = image.Metadata;
Assert.Equal(xResolution, meta.HorizontalResolution);
@@ -131,8 +129,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
var testFile = TestFile.Create(imagePath);
using (var stream = new MemoryStream(testFile.Bytes, false))
{
- var decoder = new JpegDecoder();
- using (Image image = decoder.Decode(Configuration.Default, stream))
+ using (Image image = JpegDecoder.Decode(Configuration.Default, stream))
{
JpegMetadata meta = image.Metadata.GetJpegMetadata();
Assert.Equal(quality, meta.Quality);
@@ -140,6 +137,42 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
}
}
+ [Theory]
+ [InlineData(TestImages.Jpeg.Baseline.Floorplan, JpegColorType.Luminance)]
+ [InlineData(TestImages.Jpeg.Baseline.Jpeg420Small, JpegColorType.YCbCrRatio420)]
+ [InlineData(TestImages.Jpeg.Baseline.Jpeg444, JpegColorType.YCbCrRatio444)]
+ [InlineData(TestImages.Jpeg.Baseline.JpegRgb, JpegColorType.Rgb)]
+ [InlineData(TestImages.Jpeg.Baseline.Cmyk, JpegColorType.Cmyk)]
+ [InlineData(TestImages.Jpeg.Baseline.Jpeg410, JpegColorType.YCbCrRatio410)]
+ [InlineData(TestImages.Jpeg.Baseline.Jpeg422, JpegColorType.YCbCrRatio422)]
+ [InlineData(TestImages.Jpeg.Baseline.Jpeg411, JpegColorType.YCbCrRatio411)]
+ public void Identify_DetectsCorrectColorType(string imagePath, JpegColorType expectedColorType)
+ {
+ var testFile = TestFile.Create(imagePath);
+ using (var stream = new MemoryStream(testFile.Bytes, false))
+ {
+ IImageInfo image = JpegDecoder.Identify(Configuration.Default, stream);
+ JpegMetadata meta = image.Metadata.GetJpegMetadata();
+ Assert.Equal(expectedColorType, meta.ColorType);
+ }
+ }
+
+ [Theory]
+ [WithFile(TestImages.Jpeg.Baseline.Floorplan, PixelTypes.Rgb24, JpegColorType.Luminance)]
+ [WithFile(TestImages.Jpeg.Baseline.Jpeg420Small, PixelTypes.Rgb24, JpegColorType.YCbCrRatio420)]
+ [WithFile(TestImages.Jpeg.Baseline.Jpeg444, PixelTypes.Rgb24, JpegColorType.YCbCrRatio444)]
+ [WithFile(TestImages.Jpeg.Baseline.JpegRgb, PixelTypes.Rgb24, JpegColorType.Rgb)]
+ [WithFile(TestImages.Jpeg.Baseline.Cmyk, PixelTypes.Rgb24, JpegColorType.Cmyk)]
+ public void Decode_DetectsCorrectColorType(TestImageProvider provider, JpegColorType expectedColorType)
+ where TPixel : unmanaged, IPixel
+ {
+ using (Image image = provider.GetImage(JpegDecoder))
+ {
+ JpegMetadata meta = image.Metadata.GetJpegMetadata();
+ Assert.Equal(expectedColorType, meta.ColorType);
+ }
+ }
+
private static void TestImageInfo(string imagePath, IImageDecoder decoder, bool useIdentify, Action test)
{
var testFile = TestFile.Create(imagePath);
@@ -159,9 +192,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
string imagePath,
int expectedPixelSize,
bool exifProfilePresent,
- bool iccProfilePresent)
- {
- TestImageInfo(
+ bool iccProfilePresent) => TestImageInfo(
imagePath,
decoder,
useIdentify,
@@ -205,7 +236,6 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
Assert.Null(iccProfile);
}
});
- }
[Theory]
[InlineData(false)]
@@ -235,9 +265,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
[Theory]
[InlineData(false)]
[InlineData(true)]
- public void Decoder_Reads_Correct_Resolution_From_Jfif(bool useIdentify)
- {
- TestImageInfo(
+ public void Decoder_Reads_Correct_Resolution_From_Jfif(bool useIdentify) => TestImageInfo(
TestImages.Jpeg.Baseline.Floorplan,
JpegDecoder,
useIdentify,
@@ -246,14 +274,11 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
Assert.Equal(300, imageInfo.Metadata.HorizontalResolution);
Assert.Equal(300, imageInfo.Metadata.VerticalResolution);
});
- }
[Theory]
[InlineData(false)]
[InlineData(true)]
- public void Decoder_Reads_Correct_Resolution_From_Exif(bool useIdentify)
- {
- TestImageInfo(
+ public void Decoder_Reads_Correct_Resolution_From_Exif(bool useIdentify) => TestImageInfo(
TestImages.Jpeg.Baseline.Jpeg420Exif,
JpegDecoder,
useIdentify,
@@ -262,6 +287,5 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
Assert.Equal(72, imageInfo.Metadata.HorizontalResolution);
Assert.Equal(72, imageInfo.Metadata.VerticalResolution);
});
- }
}
}
diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Progressive.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Progressive.cs
index 9beb8358c..e8533b9bc 100644
--- a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Progressive.cs
+++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Progressive.cs
@@ -15,7 +15,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
public const string DecodeProgressiveJpegOutputName = "DecodeProgressiveJpeg";
[Theory]
- [WithFileCollection(nameof(ProgressiveTestJpegs), PixelTypes.Rgba32)]
+ [WithFileCollection(nameof(ProgressiveTestJpegs), PixelTypes.Rgb24)]
public void DecodeProgressiveJpeg(TestImageProvider provider)
where TPixel : unmanaged, IPixel
{
@@ -30,17 +30,17 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
}
[Theory]
- [WithFile(TestImages.Jpeg.Progressive.Progress, PixelTypes.Rgba32)]
- public void DecodeProgressiveJpeg_WithLimitedAllocatorBufferCapacity(TestImageProvider provider)
+ [WithFile(TestImages.Jpeg.Progressive.Progress, PixelTypes.Rgb24)]
+ public void DecodeProgressiveJpeg_WithLimitedAllocatorBufferCapacity(TestImageProvider provider)
{
static void RunTest(string providerDump, string nonContiguousBuffersStr)
{
- TestImageProvider provider =
- BasicSerializer.Deserialize>(providerDump);
+ TestImageProvider provider =
+ BasicSerializer.Deserialize>(providerDump);
provider.LimitAllocatorBufferCapacity().InBytesSqrt(200);
- using Image image = provider.GetImage(JpegDecoder);
+ using Image image = provider.GetImage(JpegDecoder);
image.DebugSave(provider, nonContiguousBuffersStr);
provider.Utility.TestName = DecodeProgressiveJpegOutputName;
diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs
index d13a9696c..2cbc29027 100644
--- a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs
@@ -6,7 +6,6 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
-
using SixLabors.ImageSharp.Formats.Jpeg;
using SixLabors.ImageSharp.IO;
using SixLabors.ImageSharp.Memory;
@@ -26,7 +25,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
[Trait("Format", "Jpg")]
public partial class JpegDecoderTests
{
- public const PixelTypes CommonNonDefaultPixelTypes = PixelTypes.Rgba32 | PixelTypes.Argb32 | PixelTypes.RgbaVector;
+ public const PixelTypes CommonNonDefaultPixelTypes = PixelTypes.Rgba32 | PixelTypes.Argb32 | PixelTypes.Bgr24 | PixelTypes.RgbaVector;
private const float BaselineTolerance = 0.001F / 100;
@@ -63,10 +62,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
return !TestEnvironment.Is64BitProcess && largeImagesToSkipOn32Bit.Contains(provider.SourceFileOrDescription);
}
- public JpegDecoderTests(ITestOutputHelper output)
- {
- this.Output = output;
- }
+ public JpegDecoderTests(ITestOutputHelper output) => this.Output = output;
private ITestOutputHelper Output { get; }
@@ -78,8 +74,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
byte[] bytes = TestFile.Create(TestImages.Jpeg.Progressive.Progress).Bytes;
using var ms = new MemoryStream(bytes);
using var bufferedStream = new BufferedReadStream(Configuration.Default, ms);
- var decoder = new JpegDecoderCore(Configuration.Default, new JpegDecoder());
- decoder.ParseStream(bufferedStream);
+ using var decoder = new JpegDecoderCore(Configuration.Default, new JpegDecoder());
+ using Image image = decoder.Decode(bufferedStream, cancellationToken: default);
// I don't know why these numbers are different. All I know is that the decoder works
// and spectral data is exactly correct also.
@@ -89,6 +85,14 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
public const string DecodeBaselineJpegOutputName = "DecodeBaselineJpeg";
+ [Fact]
+ public void Decode_NonGeneric_CreatesRgb24Image()
+ {
+ string file = Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, TestImages.Jpeg.Baseline.Jpeg420Small);
+ using var image = Image.Load(file);
+ Assert.IsType>(image);
+ }
+
[Theory]
[WithFile(TestImages.Jpeg.Baseline.Calliphora, CommonNonDefaultPixelTypes)]
public void JpegDecoder_IsNotBoundToSinglePixelType(TestImageProvider provider)
@@ -132,10 +136,10 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
[InlineData(0)]
[InlineData(0.5)]
[InlineData(0.9)]
- public async Task Decode_IsCancellable(int percentageOfStreamReadToCancel)
+ public async Task DecodeAsync_IsCancellable(int percentageOfStreamReadToCancel)
{
var cts = new CancellationTokenSource();
- var file = Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, TestImages.Jpeg.Baseline.Jpeg420Small);
+ string file = Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, TestImages.Jpeg.Baseline.Jpeg420Small);
using var pausedStream = new PausedStream(file);
pausedStream.OnWaiting(s =>
{
@@ -164,7 +168,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
{
var cts = new CancellationTokenSource();
- var file = Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, TestImages.Jpeg.Baseline.Jpeg420Small);
+ string file = Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, TestImages.Jpeg.Baseline.Jpeg420Small);
using var pausedStream = new PausedStream(file);
pausedStream.OnWaiting(s =>
{
@@ -178,6 +182,32 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
await Assert.ThrowsAsync(async () => await Image.IdentifyAsync(config, "someFakeFile", cts.Token));
}
+ [Theory]
+ [WithFile(TestImages.Jpeg.Baseline.ArithmeticCoding, PixelTypes.Rgba32)]
+ [WithFile(TestImages.Jpeg.Baseline.ArithmeticCodingProgressive, PixelTypes.Rgba32)]
+ [WithFile(TestImages.Jpeg.Baseline.Lossless, PixelTypes.Rgba32)]
+ public void ThrowsNotSupported_WithUnsupportedJpegs(TestImageProvider provider)
+ where TPixel : unmanaged, IPixel
+ {
+ Assert.Throws(() =>
+ {
+ using Image image = provider.GetImage(JpegDecoder);
+ });
+ }
+
+ // https://github.com/SixLabors/ImageSharp/pull/1732
+ [Theory]
+ [WithFile(TestImages.Jpeg.Issues.WrongColorSpace, PixelTypes.Rgba32)]
+ public void Issue1732_DecodesWithRgbColorSpace(TestImageProvider provider)
+ where TPixel : unmanaged, IPixel
+ {
+ using (Image image = provider.GetImage(JpegDecoder))
+ {
+ image.DebugSave(provider);
+ image.CompareToOriginal(provider);
+ }
+ }
+
// DEBUG ONLY!
// The PDF.js output should be saved by "tests\ImageSharp.Tests\Formats\Jpg\pdfjs\jpeg-converter.htm"
// into "\tests\Images\ActualOutput\JpegDecoderTests\"
diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs
index 8e12b04be..62952f537 100644
--- a/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs
@@ -5,7 +5,6 @@ using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
-
using SixLabors.ImageSharp.Formats.Jpeg;
using SixLabors.ImageSharp.Metadata;
using SixLabors.ImageSharp.Metadata.Profiles.Exif;
@@ -24,6 +23,10 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
[Trait("Format", "Jpg")]
public class JpegEncoderTests
{
+ private static JpegEncoder JpegEncoder => new JpegEncoder();
+
+ private static JpegDecoder JpegDecoder => new JpegDecoder();
+
public static readonly TheoryData QualityFiles =
new TheoryData
{
@@ -31,15 +34,18 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
{ TestImages.Jpeg.Progressive.Fb, 75 }
};
- public static readonly TheoryData BitsPerPixel_Quality =
- new TheoryData
+ public static readonly TheoryData BitsPerPixel_Quality =
+ new TheoryData
{
- { JpegSubsample.Ratio420, 40 },
- { JpegSubsample.Ratio420, 60 },
- { JpegSubsample.Ratio420, 100 },
- { JpegSubsample.Ratio444, 40 },
- { JpegSubsample.Ratio444, 60 },
- { JpegSubsample.Ratio444, 100 },
+ { JpegColorType.YCbCrRatio420, 40 },
+ { JpegColorType.YCbCrRatio420, 60 },
+ { JpegColorType.YCbCrRatio420, 100 },
+ { JpegColorType.YCbCrRatio444, 40 },
+ { JpegColorType.YCbCrRatio444, 60 },
+ { JpegColorType.YCbCrRatio444, 100 },
+ { JpegColorType.Rgb, 40 },
+ { JpegColorType.Rgb, 60 },
+ { JpegColorType.Rgb, 100 }
};
public static readonly TheoryData Grayscale_Quality =
@@ -59,17 +65,84 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
};
[Theory]
- [MemberData(nameof(QualityFiles))]
- public void Encode_PreserveQuality(string imagePath, int quality)
+ [WithFile(TestImages.Jpeg.Baseline.Floorplan, PixelTypes.Rgba32, JpegColorType.Luminance)]
+ [WithFile(TestImages.Jpeg.Baseline.Jpeg444, PixelTypes.Rgba32, JpegColorType.YCbCrRatio444)]
+ [WithFile(TestImages.Jpeg.Baseline.Jpeg420Small, PixelTypes.Rgba32, JpegColorType.YCbCrRatio420)]
+ [WithFile(TestImages.Jpeg.Baseline.JpegRgb, PixelTypes.Rgba32, JpegColorType.Rgb)]
+ public void Encode_PreservesColorType(TestImageProvider provider, JpegColorType expectedColorType)
+ where TPixel : unmanaged, IPixel
+ {
+ // arrange
+ using Image input = provider.GetImage(JpegDecoder);
+ using var memoryStream = new MemoryStream();
+
+ // act
+ input.Save(memoryStream, JpegEncoder);
+
+ // assert
+ memoryStream.Position = 0;
+ using var output = Image.Load(memoryStream);
+ JpegMetadata meta = output.Metadata.GetJpegMetadata();
+ Assert.Equal(expectedColorType, meta.ColorType);
+ }
+
+ [Theory]
+ [WithFile(TestImages.Jpeg.Baseline.Cmyk, PixelTypes.Rgba32)]
+ [WithFile(TestImages.Jpeg.Baseline.Jpeg410, PixelTypes.Rgba32)]
+ [WithFile(TestImages.Jpeg.Baseline.Jpeg411, PixelTypes.Rgba32)]
+ [WithFile(TestImages.Jpeg.Baseline.Jpeg422, PixelTypes.Rgba32)]
+ public void Encode_WithUnsupportedColorType_FromInputImage_DefaultsToYCbCr420(TestImageProvider provider)
+ where TPixel : unmanaged, IPixel
{
- var options = new JpegEncoder();
+ // arrange
+ using Image input = provider.GetImage(JpegDecoder);
+ using var memoryStream = new MemoryStream();
+
+ // act
+ input.Save(memoryStream, new JpegEncoder()
+ {
+ Quality = 75
+ });
+ // assert
+ memoryStream.Position = 0;
+ using var output = Image.Load(memoryStream);
+ JpegMetadata meta = output.Metadata.GetJpegMetadata();
+ Assert.Equal(JpegColorType.YCbCrRatio420, meta.ColorType);
+ }
+
+ [Theory]
+ [InlineData(JpegColorType.Cmyk)]
+ [InlineData(JpegColorType.YCbCrRatio410)]
+ [InlineData(JpegColorType.YCbCrRatio411)]
+ [InlineData(JpegColorType.YCbCrRatio422)]
+ public void Encode_WithUnsupportedColorType_DefaultsToYCbCr420(JpegColorType colorType)
+ {
+ // arrange
+ var jpegEncoder = new JpegEncoder() { ColorType = colorType };
+ using var input = new Image(10, 10);
+ using var memoryStream = new MemoryStream();
+
+ // act
+ input.Save(memoryStream, jpegEncoder);
+
+ // assert
+ memoryStream.Position = 0;
+ using var output = Image.Load(memoryStream);
+ JpegMetadata meta = output.Metadata.GetJpegMetadata();
+ Assert.Equal(JpegColorType.YCbCrRatio420, meta.ColorType);
+ }
+
+ [Theory]
+ [MemberData(nameof(QualityFiles))]
+ public void Encode_PreservesQuality(string imagePath, int quality)
+ {
var testFile = TestFile.Create(imagePath);
using (Image input = testFile.CreateRgba32Image())
{
using (var memStream = new MemoryStream())
{
- input.Save(memStream, options);
+ input.Save(memStream, JpegEncoder);
memStream.Position = 0;
using (var output = Image.Load(memStream))
@@ -83,16 +156,30 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
[Theory]
[WithFile(TestImages.Png.CalliphoraPartial, nameof(BitsPerPixel_Quality), PixelTypes.Rgba32)]
+ public void EncodeBaseline_CalliphoraPartial(TestImageProvider provider, JpegColorType colorType, int quality)
+ where TPixel : unmanaged, IPixel => TestJpegEncoderCore(provider, colorType, quality);
+
+ [Theory]
+ [WithFile(TestImages.Png.CalliphoraPartial, nameof(BitsPerPixel_Quality), PixelTypes.Rgba32)]
+ [WithTestPatternImages(nameof(BitsPerPixel_Quality), 158, 24, PixelTypes.Rgba32)]
+ [WithTestPatternImages(nameof(BitsPerPixel_Quality), 153, 21, PixelTypes.Rgba32)]
+ [WithTestPatternImages(nameof(BitsPerPixel_Quality), 600, 400, PixelTypes.Rgba32)]
+ [WithTestPatternImages(nameof(BitsPerPixel_Quality), 138, 24, PixelTypes.Rgba32)]
+ public void EncodeBaseline_WorksWithDifferentSizes(TestImageProvider provider, JpegColorType colorType, int quality)
+ where TPixel : unmanaged, IPixel => TestJpegEncoderCore(provider, colorType, quality);
+
+ [Theory]
+ [WithSolidFilledImages(nameof(BitsPerPixel_Quality), 1, 1, 100, 100, 100, 255, PixelTypes.L8)]
+ [WithSolidFilledImages(nameof(BitsPerPixel_Quality), 1, 1, 255, 100, 50, 255, PixelTypes.Rgba32)]
+ [WithTestPatternImages(nameof(BitsPerPixel_Quality), 143, 81, PixelTypes.Rgba32)]
+ [WithTestPatternImages(nameof(BitsPerPixel_Quality), 7, 5, PixelTypes.Rgba32)]
+ [WithTestPatternImages(nameof(BitsPerPixel_Quality), 96, 48, PixelTypes.Rgba32)]
[WithTestPatternImages(nameof(BitsPerPixel_Quality), 73, 71, PixelTypes.Rgba32)]
[WithTestPatternImages(nameof(BitsPerPixel_Quality), 48, 24, PixelTypes.Rgba32)]
[WithTestPatternImages(nameof(BitsPerPixel_Quality), 46, 8, PixelTypes.Rgba32)]
[WithTestPatternImages(nameof(BitsPerPixel_Quality), 51, 7, PixelTypes.Rgba32)]
- [WithSolidFilledImages(nameof(BitsPerPixel_Quality), 1, 1, 255, 100, 50, 255, PixelTypes.Rgba32)]
- [WithTestPatternImages(nameof(BitsPerPixel_Quality), 7, 5, PixelTypes.Rgba32)]
- [WithTestPatternImages(nameof(BitsPerPixel_Quality), 600, 400, PixelTypes.Rgba32)]
- [WithSolidFilledImages(nameof(BitsPerPixel_Quality), 1, 1, 100, 100, 100, 255, PixelTypes.L8)]
- public void EncodeBaseline_WorksWithDifferentSizes(TestImageProvider provider, JpegSubsample subsample, int quality)
- where TPixel : unmanaged, IPixel => TestJpegEncoderCore(provider, subsample, quality);
+ public void EncodeBaseline_WithSmallImages_WorksWithDifferentSizes(TestImageProvider provider, JpegColorType colorType, int quality)
+ where TPixel : unmanaged, IPixel => TestJpegEncoderCore(provider, colorType, quality, comparer: ImageComparer.Tolerant(0.12f));
[Theory]
[WithFile(TestImages.Png.BikeGrayscale, nameof(Grayscale_Quality), PixelTypes.L8)]
@@ -102,46 +189,51 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
[WithSolidFilledImages(1, 1, 100, 100, 100, 255, PixelTypes.La16, 100)]
[WithSolidFilledImages(1, 1, 100, 100, 100, 255, PixelTypes.La32, 100)]
public void EncodeBaseline_Grayscale(TestImageProvider provider, int quality)
- where TPixel : unmanaged, IPixel => TestJpegEncoderCore(provider, null, quality, JpegColorType.Luminance);
+ where TPixel : unmanaged, IPixel => TestJpegEncoderCore(provider, JpegColorType.Luminance, quality);
+
+ [Theory]
+ [WithTestPatternImages(nameof(BitsPerPixel_Quality), 96, 96, PixelTypes.Rgba32 | PixelTypes.Bgra32)]
+ public void EncodeBaseline_IsNotBoundToSinglePixelType(TestImageProvider provider, JpegColorType colorType, int quality)
+ where TPixel : unmanaged, IPixel => TestJpegEncoderCore(provider, colorType, quality);
[Theory]
[WithTestPatternImages(nameof(BitsPerPixel_Quality), 48, 48, PixelTypes.Rgba32 | PixelTypes.Bgra32)]
- public void EncodeBaseline_IsNotBoundToSinglePixelType(TestImageProvider provider, JpegSubsample subsample, int quality)
- where TPixel : unmanaged, IPixel => TestJpegEncoderCore(provider, subsample, quality);
+ public void EncodeBaseline_WithSmallImages_IsNotBoundToSinglePixelType(TestImageProvider provider, JpegColorType colorType, int quality)
+ where TPixel : unmanaged, IPixel => TestJpegEncoderCore(provider, colorType, quality, comparer: ImageComparer.Tolerant(0.06f));
[Theory]
- [WithFile(TestImages.Png.CalliphoraPartial, PixelTypes.Rgba32, JpegSubsample.Ratio444)]
- [WithTestPatternImages(587, 821, PixelTypes.Rgba32, JpegSubsample.Ratio444)]
- [WithTestPatternImages(677, 683, PixelTypes.Bgra32, JpegSubsample.Ratio420)]
- [WithSolidFilledImages(400, 400, "Red", PixelTypes.Bgr24, JpegSubsample.Ratio420)]
- public void EncodeBaseline_WorksWithDiscontiguousBuffers(TestImageProvider provider, JpegSubsample subsample)
+ [WithFile(TestImages.Png.CalliphoraPartial, PixelTypes.Rgba32, JpegColorType.YCbCrRatio444)]
+ [WithTestPatternImages(587, 821, PixelTypes.Rgba32, JpegColorType.YCbCrRatio444)]
+ [WithTestPatternImages(677, 683, PixelTypes.Bgra32, JpegColorType.YCbCrRatio420)]
+ [WithSolidFilledImages(400, 400, "Red", PixelTypes.Bgr24, JpegColorType.YCbCrRatio420)]
+ public void EncodeBaseline_WorksWithDiscontiguousBuffers(TestImageProvider provider, JpegColorType colorType)
where TPixel : unmanaged, IPixel
{
- ImageComparer comparer = subsample == JpegSubsample.Ratio444
+ ImageComparer comparer = colorType == JpegColorType.YCbCrRatio444
? ImageComparer.TolerantPercentage(0.1f)
: ImageComparer.TolerantPercentage(5f);
provider.LimitAllocatorBufferCapacity().InBytesSqrt(200);
- TestJpegEncoderCore(provider, subsample, 100, JpegColorType.YCbCr, comparer);
+ TestJpegEncoderCore(provider, colorType, 100, comparer);
}
///
/// Anton's SUPER-SCIENTIFIC tolerance threshold calculation
///
- private static ImageComparer GetComparer(int quality, JpegSubsample? subsample)
+ private static ImageComparer GetComparer(int quality, JpegColorType? colorType)
{
float tolerance = 0.015f; // ~1.5%
if (quality < 50)
{
- tolerance *= 10f;
+ tolerance *= 4.5f;
}
- else if (quality < 75 || subsample == JpegSubsample.Ratio420)
+ else if (quality < 75 || colorType == JpegColorType.YCbCrRatio420)
{
- tolerance *= 5f;
- if (subsample == JpegSubsample.Ratio420)
+ tolerance *= 2.0f;
+ if (colorType == JpegColorType.YCbCrRatio420)
{
- tolerance *= 2f;
+ tolerance *= 2.0f;
}
}
@@ -150,9 +242,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
private static void TestJpegEncoderCore(
TestImageProvider provider,
- JpegSubsample? subsample,
+ JpegColorType colorType = JpegColorType.YCbCrRatio420,
int quality = 100,
- JpegColorType colorType = JpegColorType.YCbCr,
ImageComparer comparer = null)
where TPixel : unmanaged, IPixel
{
@@ -163,13 +254,12 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
var encoder = new JpegEncoder
{
- Subsample = subsample,
Quality = quality,
ColorType = colorType
};
- string info = $"{subsample}-Q{quality}";
+ string info = $"{colorType}-Q{quality}";
- comparer ??= GetComparer(quality, subsample);
+ comparer ??= GetComparer(quality, colorType);
// Does DebugSave & load reference CompareToReferenceInput():
image.VerifyEncoder(provider, "jpeg", info, encoder, comparer, referenceImageExtension: "png");
@@ -225,14 +315,12 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
[MemberData(nameof(RatioFiles))]
public void Encode_PreserveRatio(string imagePath, int xResolution, int yResolution, PixelResolutionUnit resolutionUnit)
{
- var options = new JpegEncoder();
-
var testFile = TestFile.Create(imagePath);
using (Image input = testFile.CreateRgba32Image())
{
using (var memStream = new MemoryStream())
{
- input.Save(memStream, options);
+ input.Save(memStream, JpegEncoder);
memStream.Position = 0;
using (var output = Image.Load(memStream))
@@ -253,11 +341,10 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
using var input = new Image(1, 1);
input.Metadata.IptcProfile = new IptcProfile();
input.Metadata.IptcProfile.SetValue(IptcTag.Byline, "unit_test");
- var encoder = new JpegEncoder();
// act
using var memStream = new MemoryStream();
- input.Save(memStream, encoder);
+ input.Save(memStream, JpegEncoder);
// assert
memStream.Position = 0;
@@ -275,11 +362,10 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
using var input = new Image(1, 1);
input.Metadata.ExifProfile = new ExifProfile();
input.Metadata.ExifProfile.SetValue(ExifTag.Software, "unit_test");
- var encoder = new JpegEncoder();
// act
using var memStream = new MemoryStream();
- input.Save(memStream, encoder);
+ input.Save(memStream, JpegEncoder);
// assert
memStream.Position = 0;
@@ -296,11 +382,10 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
// arrange
using var input = new Image(1, 1);
input.Metadata.IccProfile = new IccProfile(IccTestDataProfiles.Profile_Random_Array);
- var encoder = new JpegEncoder();
// act
using var memStream = new MemoryStream();
- input.Save(memStream, encoder);
+ input.Save(memStream, JpegEncoder);
// assert
memStream.Position = 0;
@@ -312,9 +397,9 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
}
[Theory]
- [InlineData(JpegSubsample.Ratio420)]
- [InlineData(JpegSubsample.Ratio444)]
- public async Task Encode_IsCancellable(JpegSubsample subsample)
+ [InlineData(JpegColorType.YCbCrRatio420)]
+ [InlineData(JpegColorType.YCbCrRatio444)]
+ public async Task Encode_IsCancellable(JpegColorType colorType)
{
var cts = new CancellationTokenSource();
using var pausedStream = new PausedStream(new MemoryStream());
@@ -336,7 +421,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
using var image = new Image(5000, 5000);
await Assert.ThrowsAsync(async () =>
{
- var encoder = new JpegEncoder() { Subsample = subsample };
+ var encoder = new JpegEncoder() { ColorType = colorType };
await image.SaveAsync(pausedStream, encoder, cts.Token);
});
}
diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegImagePostProcessorTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegImagePostProcessorTests.cs
deleted file mode 100644
index 93d9aee92..000000000
--- a/tests/ImageSharp.Tests/Formats/Jpg/JpegImagePostProcessorTests.cs
+++ /dev/null
@@ -1,97 +0,0 @@
-// Copyright (c) Six Labors.
-// Licensed under the Apache License, Version 2.0.
-
-using SixLabors.ImageSharp.Formats.Jpeg;
-using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder;
-using SixLabors.ImageSharp.PixelFormats;
-using SixLabors.ImageSharp.Tests.Formats.Jpg.Utils;
-using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison;
-
-using Xunit;
-using Xunit.Abstractions;
-
-namespace SixLabors.ImageSharp.Tests.Formats.Jpg
-{
- [Trait("Format", "Jpg")]
- public class JpegImagePostProcessorTests
- {
- public static string[] BaselineTestJpegs =
- {
- TestImages.Jpeg.Baseline.Calliphora,
- TestImages.Jpeg.Baseline.Cmyk,
- TestImages.Jpeg.Baseline.Ycck,
- TestImages.Jpeg.Baseline.Jpeg400,
- TestImages.Jpeg.Baseline.Testorig420,
- TestImages.Jpeg.Baseline.Jpeg444,
- };
-
- public JpegImagePostProcessorTests(ITestOutputHelper output)
- {
- this.Output = output;
- }
-
- private ITestOutputHelper Output { get; }
-
- private static void SaveBuffer(JpegComponentPostProcessor cp, TestImageProvider provider)
- where TPixel : unmanaged, IPixel
- {
- using (Image image = cp.ColorBuffer.ToGrayscaleImage(1f / 255f))
- {
- image.DebugSave(provider, $"-C{cp.Component.Index}-");
- }
- }
-
- [Theory]
- [WithFile(TestImages.Jpeg.Baseline.Calliphora, PixelTypes.Rgba32)]
- [WithFile(TestImages.Jpeg.Baseline.Testorig420, PixelTypes.Rgba32)]
- public void DoProcessorStep(TestImageProvider provider)
- where TPixel : unmanaged, IPixel
- {
- string imageFile = provider.SourceFileOrDescription;
- using (JpegDecoderCore decoder = JpegFixture.ParseJpegStream(imageFile))
- using (var pp = new JpegImagePostProcessor(Configuration.Default, decoder))
- using (var imageFrame = new ImageFrame(Configuration.Default, decoder.ImageWidth, decoder.ImageHeight))
- {
- pp.DoPostProcessorStep(imageFrame);
-
- JpegComponentPostProcessor[] cp = pp.ComponentProcessors;
-
- SaveBuffer(cp[0], provider);
- SaveBuffer(cp[1], provider);
- SaveBuffer(cp[2], provider);
- }
- }
-
- [Theory]
- [WithFileCollection(nameof(BaselineTestJpegs), PixelTypes.Rgba32)]
- public void PostProcess(TestImageProvider provider)
- where TPixel : unmanaged, IPixel
- {
- string imageFile = provider.SourceFileOrDescription;
- using (JpegDecoderCore decoder = JpegFixture.ParseJpegStream(imageFile))
- using (var pp = new JpegImagePostProcessor(Configuration.Default, decoder))
- using (var image = new Image(decoder.ImageWidth, decoder.ImageHeight))
- {
- pp.PostProcess(image.Frames.RootFrame, default);
-
- image.DebugSave(provider);
-
- ImagingTestCaseUtility testUtil = provider.Utility;
- testUtil.TestGroupName = nameof(JpegDecoderTests);
- testUtil.TestName = JpegDecoderTests.DecodeBaselineJpegOutputName;
-
- using (Image referenceImage =
- provider.GetReferenceOutputImage(appendPixelTypeToFileName: false))
- {
- ImageSimilarityReport report = ImageComparer.Exact.CompareImagesOrFrames(referenceImage, image);
-
- this.Output.WriteLine($"*** {imageFile} ***");
- this.Output.WriteLine($"Difference: {report.DifferencePercentageString}");
-
- // ReSharper disable once PossibleInvalidOperationException
- Assert.True(report.TotalNormalizedDifference.Value < 0.005f);
- }
- }
- }
- }
-}
diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegMetadataTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegMetadataTests.cs
index 503ede129..3f045dd1a 100644
--- a/tests/ImageSharp.Tests/Formats/Jpg/JpegMetadataTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegMetadataTests.cs
@@ -16,10 +16,49 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
var clone = (JpegMetadata)meta.DeepClone();
clone.Quality = 99;
- clone.ColorType = JpegColorType.YCbCr;
+ clone.ColorType = JpegColorType.YCbCrRatio420;
Assert.False(meta.Quality.Equals(clone.Quality));
Assert.False(meta.ColorType.Equals(clone.ColorType));
}
+
+ [Fact]
+ public void Quality_DefaultQuality()
+ {
+ var meta = new JpegMetadata();
+
+ Assert.Equal(meta.Quality, ImageSharp.Formats.Jpeg.Components.Quantization.DefaultQualityFactor);
+ }
+
+ [Fact]
+ public void Quality_LuminanceOnlyQuality()
+ {
+ int quality = 50;
+
+ var meta = new JpegMetadata { LuminanceQuality = quality };
+
+ Assert.Equal(meta.Quality, quality);
+ }
+
+ [Fact]
+ public void Quality_BothComponentsQuality()
+ {
+ int quality = 50;
+
+ var meta = new JpegMetadata { LuminanceQuality = quality, ChrominanceQuality = quality };
+
+ Assert.Equal(meta.Quality, quality);
+ }
+
+ [Fact]
+ public void Quality_ReturnsMaxQuality()
+ {
+ int qualityLuma = 50;
+ int qualityChroma = 30;
+
+ var meta = new JpegMetadata { LuminanceQuality = qualityLuma, ChrominanceQuality = qualityChroma };
+
+ Assert.Equal(meta.Quality, qualityLuma);
+ }
}
}
diff --git a/tests/ImageSharp.Tests/Formats/Jpg/LibJpegToolsTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/LibJpegToolsTests.cs
index 1703d007f..80f6222ff 100644
--- a/tests/ImageSharp.Tests/Formats/Jpg/LibJpegToolsTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Jpg/LibJpegToolsTests.cs
@@ -2,7 +2,6 @@
// Licensed under the Apache License, Version 2.0.
using System.IO;
-
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Tests.Formats.Jpg.Utils;
diff --git a/tests/ImageSharp.Tests/Formats/Jpg/ParseStreamTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/ParseStreamTests.cs
index de8103d63..c4d0faf33 100644
--- a/tests/ImageSharp.Tests/Formats/Jpg/ParseStreamTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Jpg/ParseStreamTests.cs
@@ -2,7 +2,6 @@
// Licensed under the Apache License, Version 2.0.
using System.Text;
-
using SixLabors.ImageSharp.Formats.Jpeg;
using SixLabors.ImageSharp.Formats.Jpeg.Components;
using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder;
@@ -32,7 +31,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
{
var expectedColorSpace = (JpegColorSpace)expectedColorSpaceValue;
- using (JpegDecoderCore decoder = JpegFixture.ParseJpegStream(imageFile))
+ using (JpegDecoderCore decoder = JpegFixture.ParseJpegStream(imageFile, metaDataOnly: true))
{
Assert.Equal(expectedColorSpace, decoder.ColorSpace);
}
@@ -43,12 +42,12 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
{
using (JpegDecoderCore decoder = JpegFixture.ParseJpegStream(TestImages.Jpeg.Baseline.Jpeg400))
{
- Assert.Equal(1, decoder.ComponentCount);
+ Assert.Equal(1, decoder.Frame.ComponentCount);
Assert.Equal(1, decoder.Components.Length);
- Size expectedSizeInBlocks = decoder.ImageSizeInPixels.DivideRoundUp(8);
+ Size expectedSizeInBlocks = decoder.Frame.PixelSize.DivideRoundUp(8);
- Assert.Equal(expectedSizeInBlocks, decoder.ImageSizeInMCU);
+ Assert.Equal(expectedSizeInBlocks, decoder.Frame.McuSize);
var uniform1 = new Size(1, 1);
JpegComponent c0 = decoder.Components[0];
@@ -70,7 +69,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
using (JpegDecoderCore decoder = JpegFixture.ParseJpegStream(imageFile))
{
sb.AppendLine(imageFile);
- sb.AppendLine($"Size:{decoder.ImageSizeInPixels} MCU:{decoder.ImageSizeInMCU}");
+ sb.AppendLine($"Size:{decoder.Frame.PixelSize} MCU:{decoder.Frame.McuSize}");
JpegComponent c0 = decoder.Components[0];
JpegComponent c1 = decoder.Components[1];
@@ -106,7 +105,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
using (JpegDecoderCore decoder = JpegFixture.ParseJpegStream(imageFile))
{
- Assert.Equal(componentCount, decoder.ComponentCount);
+ Assert.Equal(componentCount, decoder.Frame.ComponentCount);
Assert.Equal(componentCount, decoder.Components.Length);
JpegComponent c0 = decoder.Components[0];
@@ -115,7 +114,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
var uniform1 = new Size(1, 1);
- Size expectedLumaSizeInBlocks = decoder.ImageSizeInMCU.MultiplyBy(fLuma);
+ Size expectedLumaSizeInBlocks = decoder.Frame.McuSize.MultiplyBy(fLuma);
Size divisor = fLuma.DivideBy(fChroma);
diff --git a/tests/ImageSharp.Tests/Formats/Jpg/ProfileResolverTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/ProfileResolverTests.cs
index 8d2328a3a..6f52cb919 100644
--- a/tests/ImageSharp.Tests/Formats/Jpg/ProfileResolverTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Jpg/ProfileResolverTests.cs
@@ -2,7 +2,6 @@
// Licensed under the Apache License, Version 2.0.
using System.Text;
-
using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder;
using Xunit;
diff --git a/tests/ImageSharp.Tests/Formats/Jpg/QuantizationTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/QuantizationTests.cs
new file mode 100644
index 000000000..e9fe3d067
--- /dev/null
+++ b/tests/ImageSharp.Tests/Formats/Jpg/QuantizationTests.cs
@@ -0,0 +1,45 @@
+// Copyright (c) Six Labors.
+// Licensed under the Apache License, Version 2.0.
+
+using SixLabors.ImageSharp.Formats.Jpeg.Components;
+using Xunit;
+using JpegQuantization = SixLabors.ImageSharp.Formats.Jpeg.Components.Quantization;
+
+namespace SixLabors.ImageSharp.Tests.Formats.Jpg
+{
+ [Trait("Format", "Jpg")]
+ public class QuantizationTests
+ {
+ [Fact]
+ public void QualityEstimationFromStandardEncoderTables_Luminance()
+ {
+ int firstIndex = JpegQuantization.QualityEstimationConfidenceLowerThreshold;
+ int lastIndex = JpegQuantization.QualityEstimationConfidenceUpperThreshold;
+ for (int quality = firstIndex; quality <= lastIndex; quality++)
+ {
+ Block8x8F table = JpegQuantization.ScaleLuminanceTable(quality);
+ int estimatedQuality = JpegQuantization.EstimateLuminanceQuality(ref table);
+
+ Assert.True(
+ quality.Equals(estimatedQuality),
+ $"Failed to estimate luminance quality for standard table at quality level {quality}");
+ }
+ }
+
+ [Fact]
+ public void QualityEstimationFromStandardEncoderTables_Chrominance()
+ {
+ int firstIndex = JpegQuantization.QualityEstimationConfidenceLowerThreshold;
+ int lastIndex = JpegQuantization.QualityEstimationConfidenceUpperThreshold;
+ for (int quality = firstIndex; quality <= lastIndex; quality++)
+ {
+ Block8x8F table = JpegQuantization.ScaleChrominanceTable(quality);
+ int estimatedQuality = JpegQuantization.EstimateChrominanceQuality(ref table);
+
+ Assert.True(
+ quality.Equals(estimatedQuality),
+ $"Failed to estimate chrominance quality for standard table at quality level {quality}");
+ }
+ }
+ }
+}
diff --git a/tests/ImageSharp.Tests/Formats/Jpg/ReferenceImplementationsTests.StandardIntegerDCT.cs b/tests/ImageSharp.Tests/Formats/Jpg/ReferenceImplementationsTests.StandardIntegerDCT.cs
index c7bf9d1b6..6e25334f2 100644
--- a/tests/ImageSharp.Tests/Formats/Jpg/ReferenceImplementationsTests.StandardIntegerDCT.cs
+++ b/tests/ImageSharp.Tests/Formats/Jpg/ReferenceImplementationsTests.StandardIntegerDCT.cs
@@ -2,7 +2,6 @@
// Licensed under the Apache License, Version 2.0.
using System;
-
using SixLabors.ImageSharp.Formats.Jpeg.Components;
using SixLabors.ImageSharp.Tests.Formats.Jpg.Utils;
diff --git a/tests/ImageSharp.Tests/Formats/Jpg/ReferenceImplementationsTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/ReferenceImplementationsTests.cs
index d3077a6e3..5c7c3267d 100644
--- a/tests/ImageSharp.Tests/Formats/Jpg/ReferenceImplementationsTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Jpg/ReferenceImplementationsTests.cs
@@ -15,4 +15,4 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
{
}
}
-}
\ No newline at end of file
+}
diff --git a/tests/ImageSharp.Tests/Formats/Jpg/SpectralJpegTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/SpectralJpegTests.cs
index 91b1b9cd7..1785f3dec 100644
--- a/tests/ImageSharp.Tests/Formats/Jpg/SpectralJpegTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Jpg/SpectralJpegTests.cs
@@ -4,9 +4,11 @@
using System;
using System.IO;
using System.Linq;
-
using SixLabors.ImageSharp.Formats.Jpeg;
+using SixLabors.ImageSharp.Formats.Jpeg.Components;
+using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder;
using SixLabors.ImageSharp.IO;
+using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Tests.Formats.Jpg.Utils;
@@ -19,10 +21,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
[Trait("Format", "Jpg")]
public class SpectralJpegTests
{
- public SpectralJpegTests(ITestOutputHelper output)
- {
- this.Output = output;
- }
+ public SpectralJpegTests(ITestOutputHelper output) => this.Output = output;
private ITestOutputHelper Output { get; }
@@ -48,16 +47,20 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
public void Decoder_ParseStream_SaveSpectralResult(TestImageProvider provider)
where TPixel : unmanaged, IPixel
{
- var decoder = new JpegDecoderCore(Configuration.Default, new JpegDecoder());
-
+ // Calculating data from ImageSharp
byte[] sourceBytes = TestFile.Create(provider.SourceFileOrDescription).Bytes;
+ var decoder = new JpegDecoderCore(Configuration.Default, new JpegDecoder());
using var ms = new MemoryStream(sourceBytes);
using var bufferedStream = new BufferedReadStream(Configuration.Default, ms);
- decoder.ParseStream(bufferedStream);
- var data = LibJpegTools.SpectralData.LoadFromImageSharpDecoder(decoder);
- VerifyJpeg.SaveSpectralImage(provider, data);
+ // internal scan decoder which we substitute to assert spectral correctness
+ var debugConverter = new DebugSpectralConverter();
+ var scanDecoder = new HuffmanScanDecoder(bufferedStream, debugConverter, cancellationToken: default);
+
+ // This would parse entire image
+ decoder.ParseStream(bufferedStream, scanDecoder, cancellationToken: default);
+ VerifyJpeg.SaveSpectralImage(provider, debugConverter.SpectralData);
}
[Theory]
@@ -70,25 +73,31 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
return;
}
- var decoder = new JpegDecoderCore(Configuration.Default, new JpegDecoder());
+ // Expected data from libjpeg
+ LibJpegTools.SpectralData libJpegData = LibJpegTools.ExtractSpectralData(provider.SourceFileOrDescription);
+ // Calculating data from ImageSharp
byte[] sourceBytes = TestFile.Create(provider.SourceFileOrDescription).Bytes;
+ var decoder = new JpegDecoderCore(Configuration.Default, new JpegDecoder());
using var ms = new MemoryStream(sourceBytes);
using var bufferedStream = new BufferedReadStream(Configuration.Default, ms);
- decoder.ParseStream(bufferedStream);
- var imageSharpData = LibJpegTools.SpectralData.LoadFromImageSharpDecoder(decoder);
- this.VerifySpectralCorrectnessImpl(provider, imageSharpData);
+ // internal scan decoder which we substitute to assert spectral correctness
+ var debugConverter = new DebugSpectralConverter();
+ var scanDecoder = new HuffmanScanDecoder(bufferedStream, debugConverter, cancellationToken: default);
+
+ // This would parse entire image
+ decoder.ParseStream(bufferedStream, scanDecoder, cancellationToken: default);
+
+ // Actual verification
+ this.VerifySpectralCorrectnessImpl(libJpegData, debugConverter.SpectralData);
}
- private void VerifySpectralCorrectnessImpl(
- TestImageProvider provider,
+ private void VerifySpectralCorrectnessImpl(
+ LibJpegTools.SpectralData libJpegData,
LibJpegTools.SpectralData imageSharpData)
- where TPixel : unmanaged, IPixel
{
- LibJpegTools.SpectralData libJpegData = LibJpegTools.ExtractSpectralData(provider.SourceFileOrDescription);
-
bool equality = libJpegData.Equals(imageSharpData);
this.Output.WriteLine("Spectral data equality: " + equality);
@@ -108,11 +117,11 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
LibJpegTools.ComponentData libJpegComponent = libJpegData.Components[i];
LibJpegTools.ComponentData imageSharpComponent = imageSharpData.Components[i];
- (double total, double average) diff = LibJpegTools.CalculateDifference(libJpegComponent, imageSharpComponent);
+ (double total, double average) = LibJpegTools.CalculateDifference(libJpegComponent, imageSharpComponent);
- this.Output.WriteLine($"Component{i}: {diff}");
- averageDifference += diff.average;
- totalDifference += diff.total;
+ this.Output.WriteLine($"Component{i}: [total: {total} | average: {average}]");
+ averageDifference += average;
+ totalDifference += total;
tolerance += libJpegComponent.SpectralBlocks.DangerousGetSingleSpan().Length;
}
@@ -126,5 +135,71 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
Assert.True(totalDifference < tolerance);
}
+
+ private class DebugSpectralConverter : SpectralConverter
+ where TPixel : unmanaged, IPixel
+ {
+ private JpegFrame frame;
+
+ private LibJpegTools.SpectralData spectralData;
+
+ private int baselineScanRowCounter;
+
+ public LibJpegTools.SpectralData SpectralData
+ {
+ get
+ {
+ // Due to underlying architecture, baseline interleaved jpegs would inject spectral data during parsing
+ // Progressive and multi-scan images must be loaded manually
+ if (this.frame.Progressive || this.frame.MultiScan)
+ {
+ LibJpegTools.ComponentData[] components = this.spectralData.Components;
+ for (int i = 0; i < components.Length; i++)
+ {
+ components[i].LoadSpectral(this.frame.Components[i]);
+ }
+ }
+
+ return this.spectralData;
+ }
+ }
+
+ public override void ConvertStrideBaseline()
+ {
+ // This would be called only for baseline non-interleaved images
+ // We must copy spectral strides here
+ LibJpegTools.ComponentData[] components = this.spectralData.Components;
+ for (int i = 0; i < components.Length; i++)
+ {
+ components[i].LoadSpectralStride(this.frame.Components[i].SpectralBlocks, this.baselineScanRowCounter);
+ }
+
+ this.baselineScanRowCounter++;
+
+ // As spectral buffers are reused for each stride decoding - we need to manually clear it like it's done in SpectralConverter
+ foreach (JpegComponent component in this.frame.Components)
+ {
+ Buffer2D spectralBlocks = component.SpectralBlocks;
+ for (int i = 0; i < spectralBlocks.Height; i++)
+ {
+ spectralBlocks.GetRowSpan(i).Clear();
+ }
+ }
+ }
+
+ public override void InjectFrameData(JpegFrame frame, IRawJpegData jpegData)
+ {
+ this.frame = frame;
+
+ var spectralComponents = new LibJpegTools.ComponentData[frame.ComponentCount];
+ for (int i = 0; i < spectralComponents.Length; i++)
+ {
+ JpegComponent component = frame.Components[i];
+ spectralComponents[i] = new LibJpegTools.ComponentData(component.WidthInBlocks, component.HeightInBlocks, component.Index);
+ }
+
+ this.spectralData = new LibJpegTools.SpectralData(spectralComponents);
+ }
+ }
}
}
diff --git a/tests/ImageSharp.Tests/Formats/Jpg/SpectralToPixelConversionTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/SpectralToPixelConversionTests.cs
new file mode 100644
index 000000000..f0f92d763
--- /dev/null
+++ b/tests/ImageSharp.Tests/Formats/Jpg/SpectralToPixelConversionTests.cs
@@ -0,0 +1,69 @@
+// Copyright (c) Six Labors.
+// Licensed under the Apache License, Version 2.0.
+
+using System.IO;
+using System.Linq;
+using SixLabors.ImageSharp.Formats.Jpeg;
+using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder;
+using SixLabors.ImageSharp.IO;
+using SixLabors.ImageSharp.Metadata;
+using SixLabors.ImageSharp.PixelFormats;
+using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison;
+using Xunit;
+using Xunit.Abstractions;
+
+namespace SixLabors.ImageSharp.Tests.Formats.Jpg
+{
+ [Trait("Format", "Jpg")]
+ public class SpectralToPixelConversionTests
+ {
+ public static readonly string[] BaselineTestJpegs =
+ {
+ TestImages.Jpeg.Baseline.Calliphora, TestImages.Jpeg.Baseline.Cmyk, TestImages.Jpeg.Baseline.Jpeg400,
+ TestImages.Jpeg.Baseline.Jpeg444, TestImages.Jpeg.Baseline.Testorig420,
+ TestImages.Jpeg.Baseline.Jpeg420Small, TestImages.Jpeg.Baseline.Bad.BadEOF,
+ TestImages.Jpeg.Baseline.MultiScanBaselineCMYK
+ };
+
+ public SpectralToPixelConversionTests(ITestOutputHelper output)
+ {
+ this.Output = output;
+ }
+
+ private ITestOutputHelper Output { get; }
+
+ [Theory]
+ [WithFileCollection(nameof(BaselineTestJpegs), PixelTypes.Rgba32)]
+ public void Decoder_PixelBufferComparison(TestImageProvider provider)
+ where TPixel : unmanaged, IPixel
+ {
+ // Stream
+ byte[] sourceBytes = TestFile.Create(provider.SourceFileOrDescription).Bytes;
+ using var ms = new MemoryStream(sourceBytes);
+ using var bufferedStream = new BufferedReadStream(Configuration.Default, ms);
+
+ // Decoding
+ using var converter = new SpectralConverter(Configuration.Default, cancellationToken: default);
+ var decoder = new JpegDecoderCore(Configuration.Default, new JpegDecoder());
+ var scanDecoder = new HuffmanScanDecoder(bufferedStream, converter, cancellationToken: default);
+ decoder.ParseStream(bufferedStream, scanDecoder, cancellationToken: default);
+
+ // Test metadata
+ provider.Utility.TestGroupName = nameof(JpegDecoderTests);
+ provider.Utility.TestName = JpegDecoderTests.DecodeBaselineJpegOutputName;
+
+ // Comparison
+ using (Image image = new Image(Configuration.Default, converter.GetPixelBuffer(), new ImageMetadata()))
+ using (Image referenceImage = provider.GetReferenceOutputImage(appendPixelTypeToFileName: false))
+ {
+ ImageSimilarityReport report = ImageComparer.Exact.CompareImagesOrFrames(referenceImage, image);
+
+ this.Output.WriteLine($"*** {provider.SourceFileOrDescription} ***");
+ this.Output.WriteLine($"Difference: {report.DifferencePercentageString}");
+
+ // ReSharper disable once PossibleInvalidOperationException
+ Assert.True(report.TotalNormalizedDifference.Value < 0.005f);
+ }
+ }
+ }
+}
diff --git a/tests/ImageSharp.Tests/Formats/Jpg/Utils/JpegFixture.cs b/tests/ImageSharp.Tests/Formats/Jpg/Utils/JpegFixture.cs
index c6f4704f0..a76b2bf2e 100644
--- a/tests/ImageSharp.Tests/Formats/Jpg/Utils/JpegFixture.cs
+++ b/tests/ImageSharp.Tests/Formats/Jpg/Utils/JpegFixture.cs
@@ -5,10 +5,10 @@ using System;
using System.Diagnostics;
using System.IO;
using System.Text;
-
using SixLabors.ImageSharp.Formats.Jpeg;
using SixLabors.ImageSharp.Formats.Jpeg.Components;
using SixLabors.ImageSharp.IO;
+using SixLabors.ImageSharp.PixelFormats;
using Xunit;
using Xunit.Abstractions;
@@ -189,6 +189,38 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg.Utils
Assert.False(failed);
}
+ internal static bool CompareBlocks(Block8x8 a, Block8x8 b, int tolerance, out int diff)
+ {
+ bool res = CompareBlocks(a.AsFloatBlock(), b.AsFloatBlock(), tolerance + 1e-5f, out float fdiff);
+ diff = (int)fdiff;
+ return res;
+ }
+
+ internal static bool CompareBlocks(Block8x8F a, Block8x8F b, float tolerance, out float diff) =>
+ CompareBlocks(a.ToArray(), b.ToArray(), tolerance, out diff);
+
+ internal static bool CompareBlocks(Span a, Span b, float tolerance, out float diff)
+ {
+ var comparer = new ApproximateFloatComparer(tolerance);
+ bool failed = false;
+
+ diff = 0;
+
+ for (int i = 0; i < 64; i++)
+ {
+ float expected = a[i];
+ float actual = b[i];
+ diff += Math.Abs(expected - actual);
+
+ if (!comparer.Equals(expected, actual))
+ {
+ failed = true;
+ }
+ }
+
+ return !failed;
+ }
+
internal static JpegDecoderCore ParseJpegStream(string testFileName, bool metaDataOnly = false)
{
byte[] bytes = TestFile.Create(testFileName).Bytes;
@@ -196,7 +228,14 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg.Utils
using var bufferedStream = new BufferedReadStream(Configuration.Default, ms);
var decoder = new JpegDecoderCore(Configuration.Default, new JpegDecoder());
- decoder.ParseStream(bufferedStream, metaDataOnly);
+ if (metaDataOnly)
+ {
+ decoder.Identify(bufferedStream, cancellationToken: default);
+ }
+ else
+ {
+ using Image image = decoder.Decode(bufferedStream, cancellationToken: default);
+ }
return decoder;
}
diff --git a/tests/ImageSharp.Tests/Formats/Jpg/Utils/LibJpegTools.ComponentData.cs b/tests/ImageSharp.Tests/Formats/Jpg/Utils/LibJpegTools.ComponentData.cs
index 6f6032ee2..adbd695c0 100644
--- a/tests/ImageSharp.Tests/Formats/Jpg/Utils/LibJpegTools.ComponentData.cs
+++ b/tests/ImageSharp.Tests/Formats/Jpg/Utils/LibJpegTools.ComponentData.cs
@@ -4,7 +4,6 @@
using System;
using System.Linq;
using System.Numerics;
-
using SixLabors.ImageSharp.Formats.Jpeg.Components;
using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder;
using SixLabors.ImageSharp.Memory;
@@ -53,26 +52,51 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg.Utils
{
this.MinVal = Math.Min(this.MinVal, data.Min());
this.MaxVal = Math.Max(this.MaxVal, data.Max());
- this.SpectralBlocks[x, y] = new Block8x8(data);
+ this.SpectralBlocks[x, y] = Block8x8.Load(data);
}
- public static ComponentData Load(JpegComponent c, int index)
+ public void LoadSpectralStride(Buffer2D data, int strideIndex)
{
- var result = new ComponentData(
- c.WidthInBlocks,
- c.HeightInBlocks,
- index);
+ int startIndex = strideIndex * data.Height;
+
+ int endIndex = Math.Min(this.HeightInBlocks, startIndex + data.Height);
+
+ for (int y = startIndex; y < endIndex; y++)
+ {
+ Span blockRow = data.GetRowSpan(y - startIndex);
+ for (int x = 0; x < this.WidthInBlocks; x++)
+ {
+ short[] block = blockRow[x].ToArray();
+
+ // x coordinate stays the same - we load entire stride
+ // y coordinate is tricky as we load single stride to full buffer - offset is needed
+ this.MakeBlock(block, y, x);
+ }
+ }
+ }
- for (int y = 0; y < result.HeightInBlocks; y++)
+ public void LoadSpectral(JpegComponent c)
+ {
+ Buffer2D data = c.SpectralBlocks;
+ for (int y = 0; y < this.HeightInBlocks; y++)
{
- Span blockRow = c.SpectralBlocks.GetRowSpan(y);
- for (int x = 0; x < result.WidthInBlocks; x++)
+ Span blockRow = data.GetRowSpan(y);
+ for (int x = 0; x < this.WidthInBlocks; x++)
{
- short[] data = blockRow[x].ToArray();
- result.MakeBlock(data, y, x);
+ short[] block = blockRow[x].ToArray();
+ this.MakeBlock(block, y, x);
}
}
+ }
+
+ public static ComponentData Load(JpegComponent c, int index)
+ {
+ var result = new ComponentData(
+ c.WidthInBlocks,
+ c.HeightInBlocks,
+ index);
+ result.LoadSpectral(c);
return result;
}
diff --git a/tests/ImageSharp.Tests/Formats/Jpg/Utils/LibJpegTools.SpectralData.cs b/tests/ImageSharp.Tests/Formats/Jpg/Utils/LibJpegTools.SpectralData.cs
index 6ed7c15ae..2caad95b3 100644
--- a/tests/ImageSharp.Tests/Formats/Jpg/Utils/LibJpegTools.SpectralData.cs
+++ b/tests/ImageSharp.Tests/Formats/Jpg/Utils/LibJpegTools.SpectralData.cs
@@ -4,7 +4,6 @@
using System;
using System.Linq;
using System.Numerics;
-
using SixLabors.ImageSharp.Formats.Jpeg;
using SixLabors.ImageSharp.Formats.Jpeg.Components;
using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder;
@@ -29,14 +28,6 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg.Utils
this.Components = components;
}
- public static SpectralData LoadFromImageSharpDecoder(JpegDecoderCore decoder)
- {
- JpegComponent[] srcComponents = decoder.Frame.Components;
- LibJpegTools.ComponentData[] destComponents = srcComponents.Select(LibJpegTools.ComponentData.Load).ToArray();
-
- return new SpectralData(destComponents);
- }
-
public Image TryCreateRGBSpectralImage()
{
if (this.ComponentCount != 3)
diff --git a/tests/ImageSharp.Tests/Formats/Jpg/Utils/LibJpegTools.cs b/tests/ImageSharp.Tests/Formats/Jpg/Utils/LibJpegTools.cs
index 60187a860..b74e4445e 100644
--- a/tests/ImageSharp.Tests/Formats/Jpg/Utils/LibJpegTools.cs
+++ b/tests/ImageSharp.Tests/Formats/Jpg/Utils/LibJpegTools.cs
@@ -6,7 +6,6 @@ using System.Diagnostics;
using System.IO;
using System.Numerics;
using System.Runtime.InteropServices;
-
using SixLabors.ImageSharp.Formats.Jpeg.Components;
namespace SixLabors.ImageSharp.Tests.Formats.Jpg.Utils
@@ -16,7 +15,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg.Utils
///
internal static partial class LibJpegTools
{
- public static (double total, double average) CalculateDifference(ComponentData expected, ComponentData actual)
+ public static (double Total, double Average) CalculateDifference(ComponentData expected, ComponentData actual)
{
BigInteger totalDiff = 0;
if (actual.WidthInBlocks < expected.WidthInBlocks)
diff --git a/tests/ImageSharp.Tests/Formats/Jpg/Utils/ReferenceImplementations.AccurateDCT.cs b/tests/ImageSharp.Tests/Formats/Jpg/Utils/ReferenceImplementations.AccurateDCT.cs
index e70bdc8cc..d640aebbb 100644
--- a/tests/ImageSharp.Tests/Formats/Jpg/Utils/ReferenceImplementations.AccurateDCT.cs
+++ b/tests/ImageSharp.Tests/Formats/Jpg/Utils/ReferenceImplementations.AccurateDCT.cs
@@ -2,7 +2,6 @@
// Licensed under the Apache License, Version 2.0.
using System;
-
using SixLabors.ImageSharp.Formats.Jpeg.Components;
namespace SixLabors.ImageSharp.Tests.Formats.Jpg.Utils
diff --git a/tests/ImageSharp.Tests/Formats/Jpg/Utils/ReferenceImplementations.LLM_FloatingPoint_DCT.cs b/tests/ImageSharp.Tests/Formats/Jpg/Utils/ReferenceImplementations.LLM_FloatingPoint_DCT.cs
index 3d113ffd0..b917821b0 100644
--- a/tests/ImageSharp.Tests/Formats/Jpg/Utils/ReferenceImplementations.LLM_FloatingPoint_DCT.cs
+++ b/tests/ImageSharp.Tests/Formats/Jpg/Utils/ReferenceImplementations.LLM_FloatingPoint_DCT.cs
@@ -4,7 +4,6 @@
using System;
using System.Numerics;
using System.Runtime.CompilerServices;
-
using SixLabors.ImageSharp.Formats.Jpeg.Components;
using Xunit.Abstractions;
diff --git a/tests/ImageSharp.Tests/Formats/Jpg/Utils/ReferenceImplementations.StandardIntegerDCT.cs b/tests/ImageSharp.Tests/Formats/Jpg/Utils/ReferenceImplementations.StandardIntegerDCT.cs
index 45159ba6f..b34a8bc00 100644
--- a/tests/ImageSharp.Tests/Formats/Jpg/Utils/ReferenceImplementations.StandardIntegerDCT.cs
+++ b/tests/ImageSharp.Tests/Formats/Jpg/Utils/ReferenceImplementations.StandardIntegerDCT.cs
@@ -2,7 +2,6 @@
// Licensed under the Apache License, Version 2.0.
using System;
-
using SixLabors.ImageSharp.Formats.Jpeg.Components;
// ReSharper disable InconsistentNaming
diff --git a/tests/ImageSharp.Tests/Formats/Jpg/Utils/ReferenceImplementations.cs b/tests/ImageSharp.Tests/Formats/Jpg/Utils/ReferenceImplementations.cs
index 2c673f30e..c9741521c 100644
--- a/tests/ImageSharp.Tests/Formats/Jpg/Utils/ReferenceImplementations.cs
+++ b/tests/ImageSharp.Tests/Formats/Jpg/Utils/ReferenceImplementations.cs
@@ -3,7 +3,6 @@
using System;
using System.Runtime.CompilerServices;
-
using SixLabors.ImageSharp.Formats.Jpeg.Components;
// ReSharper disable InconsistentNaming
@@ -15,18 +14,12 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg.Utils
///
internal static partial class ReferenceImplementations
{
- public static unsafe void DequantizeBlock(Block8x8F* blockPtr, Block8x8F* qtPtr, byte* unzigPtr)
+ public static void DequantizeBlock(ref Block8x8F block, ref Block8x8F qt, ReadOnlySpan zigzag)
{
- float* b = (float*)blockPtr;
- float* qtp = (float*)qtPtr;
- for (int qtIndex = 0; qtIndex < Block8x8F.Size; qtIndex++)
+ for (int i = 0; i < Block8x8F.Size; i++)
{
- byte i = unzigPtr[qtIndex];
- float* unzigPos = b + i;
-
- float val = *unzigPos;
- val *= qtp[qtIndex];
- *unzigPos = val;
+ int zig = zigzag[i];
+ block[zig] *= qt[i];
}
}
@@ -101,42 +94,18 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg.Utils
///
/// Reference implementation to test .
- /// Rounding is done used an integer-based algorithm defined in .
- ///
- /// The input block
- /// The destination block of integers
- /// The quantization table
- /// Pointer to
- public static unsafe void QuantizeRational(Block8x8F* src, int* dest, Block8x8F* qt, byte* unzigPtr)
- {
- float* s = (float*)src;
- float* q = (float*)qt;
-
- for (int zig = 0; zig < Block8x8F.Size; zig++)
- {
- int a = (int)s[unzigPtr[zig]];
- int b = (int)q[zig];
-
- int val = RationalRound(a, b);
- dest[zig] = val;
- }
- }
-
- ///
- /// Rounds a rational number defined as dividend/divisor into an integer.
///
- /// The dividend.
- /// The divisor.
- /// The rounded value.
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static int RationalRound(int dividend, int divisor)
+ /// The input block.
+ /// The destination block of 16bit integers.
+ /// The quantization table.
+ /// Zig-Zag index sequence span.
+ public static void Quantize(ref Block8x8F src, ref Block8x8 dest, ref Block8x8F qt, ReadOnlySpan zigzag)
{
- if (dividend >= 0)
+ for (int i = 0; i < Block8x8F.Size; i++)
{
- return (dividend + (divisor >> 1)) / divisor;
+ int zig = zigzag[i];
+ dest[i] = (short)Math.Round(src[zig] / qt[zig], MidpointRounding.AwayFromZero);
}
-
- return -((-dividend + (divisor >> 1)) / divisor);
}
}
}
diff --git a/tests/ImageSharp.Tests/Formats/Jpg/Utils/VerifyJpeg.cs b/tests/ImageSharp.Tests/Formats/Jpg/Utils/VerifyJpeg.cs
index 10717dfcf..e83b3b53d 100644
--- a/tests/ImageSharp.Tests/Formats/Jpg/Utils/VerifyJpeg.cs
+++ b/tests/ImageSharp.Tests/Formats/Jpg/Utils/VerifyJpeg.cs
@@ -3,7 +3,6 @@
using System.Collections.Generic;
using System.Linq;
-
using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder;
using SixLabors.ImageSharp.PixelFormats;
diff --git a/tests/ImageSharp.Tests/Formats/Jpg/ZigZagTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/ZigZagTests.cs
index e03cf9958..39046438a 100644
--- a/tests/ImageSharp.Tests/Formats/Jpg/ZigZagTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Jpg/ZigZagTests.cs
@@ -13,8 +13,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
public void ZigZagCanHandleAllPossibleCoefficients()
{
// Mimic the behaviour of the huffman scan decoder using all possible byte values
- var block = new short[64];
- var zigzag = ZigZag.CreateUnzigTable();
+ short[] block = new short[64];
for (int h = 0; h < 255; h++)
{
@@ -27,7 +26,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
if (s != 0)
{
i += r;
- block[zigzag[i++]] = (short)s;
+ block[ZigZag.ZigZagOrder[i++]] = (short)s;
}
else
{
diff --git a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.Chunks.cs b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.Chunks.cs
index 150b3bd0a..8b6432ac3 100644
--- a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.Chunks.cs
+++ b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.Chunks.cs
@@ -4,7 +4,6 @@
using System.Buffers.Binary;
using System.IO;
using System.Text;
-
using SixLabors.ImageSharp.Formats.Png;
using SixLabors.ImageSharp.PixelFormats;
diff --git a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs
index 9832aeb7b..9fc4d03dd 100644
--- a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs
@@ -368,6 +368,24 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png
Assert.Null(ex);
}
+ // https://github.com/SixLabors/ImageSharp/issues/1765
+ [Theory]
+ [WithFile(TestImages.Png.Issue1765_Net6DeflateStreamRead, PixelTypes.Rgba32)]
+ public void Issue1765(TestImageProvider provider)
+ where TPixel : unmanaged, IPixel
+ {
+ System.Exception ex = Record.Exception(
+ () =>
+ {
+ using (Image image = provider.GetImage(PngDecoder))
+ {
+ image.DebugSave(provider);
+ image.CompareToOriginal(provider, ImageComparer.Exact);
+ }
+ });
+ Assert.Null(ex);
+ }
+
// https://github.com/SixLabors/ImageSharp/issues/410
[Theory]
[WithFile(TestImages.Png.Bad.Issue410_MalformedApplePng, PixelTypes.Rgba32)]
diff --git a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.Chunks.cs b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.Chunks.cs
index 06cde65f8..30a684702 100644
--- a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.Chunks.cs
+++ b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.Chunks.cs
@@ -5,7 +5,6 @@ using System;
using System.Buffers.Binary;
using System.Collections.Generic;
using System.IO;
-
using SixLabors.ImageSharp.Formats.Png;
using SixLabors.ImageSharp.PixelFormats;
diff --git a/tests/ImageSharp.Tests/Formats/Png/PngFilterTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngFilterTests.cs
index 80bfd3497..9b6119380 100644
--- a/tests/ImageSharp.Tests/Formats/Png/PngFilterTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Png/PngFilterTests.cs
@@ -4,7 +4,6 @@
// Uncomment this to turn unit tests into benchmarks:
// #define BENCHMARKING
using System;
-
using SixLabors.ImageSharp.Formats.Png;
using SixLabors.ImageSharp.Formats.Png.Filters;
using SixLabors.ImageSharp.Tests.TestUtilities;
diff --git a/tests/ImageSharp.Tests/Formats/Tga/TgaDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Tga/TgaDecoderTests.cs
index ac94a8fc8..1c53ff6a1 100644
--- a/tests/ImageSharp.Tests/Formats/Tga/TgaDecoderTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Tga/TgaDecoderTests.cs
@@ -10,7 +10,6 @@ using SixLabors.ImageSharp.Tests.TestUtilities;
using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison;
using Xunit;
-
using static SixLabors.ImageSharp.Tests.TestImages.Tga;
// ReSharper disable InconsistentNaming
diff --git a/tests/ImageSharp.Tests/Formats/Tga/TgaEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Tga/TgaEncoderTests.cs
index 1ad4f9a84..4c768a1a5 100644
--- a/tests/ImageSharp.Tests/Formats/Tga/TgaEncoderTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Tga/TgaEncoderTests.cs
@@ -2,12 +2,10 @@
// Licensed under the Apache License, Version 2.0.
using System.IO;
-
using SixLabors.ImageSharp.Formats.Tga;
using SixLabors.ImageSharp.PixelFormats;
using Xunit;
-
using static SixLabors.ImageSharp.Tests.TestImages.Tga;
// ReSharper disable InconsistentNaming
diff --git a/tests/ImageSharp.Tests/Formats/Tga/TgaFileHeaderTests.cs b/tests/ImageSharp.Tests/Formats/Tga/TgaFileHeaderTests.cs
index 61ddf37b7..2cdca3ff7 100644
--- a/tests/ImageSharp.Tests/Formats/Tga/TgaFileHeaderTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Tga/TgaFileHeaderTests.cs
@@ -2,7 +2,6 @@
// Licensed under the Apache License, Version 2.0.
using System.IO;
-
using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.Formats.Tga;
diff --git a/tests/ImageSharp.Tests/Formats/Tga/TgaTestUtils.cs b/tests/ImageSharp.Tests/Formats/Tga/TgaTestUtils.cs
index 58ed31e61..c96777031 100644
--- a/tests/ImageSharp.Tests/Formats/Tga/TgaTestUtils.cs
+++ b/tests/ImageSharp.Tests/Formats/Tga/TgaTestUtils.cs
@@ -3,7 +3,6 @@
using System;
using System.IO;
-
using ImageMagick;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison;
diff --git a/tests/ImageSharp.Tests/Formats/Tiff/Compression/DeflateTiffCompressionTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/Compression/DeflateTiffCompressionTests.cs
index 782a504d5..ff7025b50 100644
--- a/tests/ImageSharp.Tests/Formats/Tiff/Compression/DeflateTiffCompressionTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Tiff/Compression/DeflateTiffCompressionTests.cs
@@ -5,6 +5,7 @@ using System.IO;
using SixLabors.ImageSharp.Compression.Zlib;
using SixLabors.ImageSharp.Formats.Tiff.Compression.Decompressors;
using SixLabors.ImageSharp.Formats.Tiff.Constants;
+using SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation;
using SixLabors.ImageSharp.IO;
using Xunit;
@@ -26,9 +27,9 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff.Compression
{
var buffer = new byte[data.Length];
- using var decompressor = new DeflateTiffCompression(Configuration.Default.MemoryAllocator, 10, 8, TiffPredictor.None);
+ using var decompressor = new DeflateTiffCompression(Configuration.Default.MemoryAllocator, 10, 8, TiffColorType.BlackIsZero8, TiffPredictor.None, false);
- decompressor.Decompress(stream, 0, (uint)stream.Length, buffer);
+ decompressor.Decompress(stream, 0, (uint)stream.Length, 1, buffer);
Assert.Equal(data, buffer);
}
diff --git a/tests/ImageSharp.Tests/Formats/Tiff/Compression/LzwTiffCompressionTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/Compression/LzwTiffCompressionTests.cs
index bf585e9c8..08705738f 100644
--- a/tests/ImageSharp.Tests/Formats/Tiff/Compression/LzwTiffCompressionTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Tiff/Compression/LzwTiffCompressionTests.cs
@@ -5,6 +5,7 @@ using System.IO;
using SixLabors.ImageSharp.Formats.Tiff.Compression.Compressors;
using SixLabors.ImageSharp.Formats.Tiff.Compression.Decompressors;
using SixLabors.ImageSharp.Formats.Tiff.Constants;
+using SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation;
using SixLabors.ImageSharp.IO;
using Xunit;
@@ -38,8 +39,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff.Compression
using BufferedReadStream stream = CreateCompressedStream(data);
var buffer = new byte[data.Length];
- using var decompressor = new LzwTiffCompression(Configuration.Default.MemoryAllocator, 10, 8, TiffPredictor.None);
- decompressor.Decompress(stream, 0, (uint)stream.Length, buffer);
+ using var decompressor = new LzwTiffCompression(Configuration.Default.MemoryAllocator, 10, 8, TiffColorType.BlackIsZero8, TiffPredictor.None, false);
+ decompressor.Decompress(stream, 0, (uint)stream.Length, 1, buffer);
Assert.Equal(data, buffer);
}
diff --git a/tests/ImageSharp.Tests/Formats/Tiff/Compression/NoneTiffCompressionTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/Compression/NoneTiffCompressionTests.cs
index 82ecb315b..d153e1ed2 100644
--- a/tests/ImageSharp.Tests/Formats/Tiff/Compression/NoneTiffCompressionTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Tiff/Compression/NoneTiffCompressionTests.cs
@@ -17,10 +17,12 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff.Compression
[InlineData(new byte[] { 10, 15, 20, 25, 30, 35, 40, 45 }, 5, new byte[] { 10, 15, 20, 25, 30 })]
public void Decompress_ReadsData(byte[] inputData, uint byteCount, byte[] expectedResult)
{
- var stream = new BufferedReadStream(Configuration.Default, new MemoryStream(inputData));
- var buffer = new byte[expectedResult.Length];
+ using var memoryStream = new MemoryStream(inputData);
+ using var stream = new BufferedReadStream(Configuration.Default, memoryStream);
+ byte[] buffer = new byte[expectedResult.Length];
- new NoneTiffCompression(default, default, default).Decompress(stream, 0, byteCount, buffer);
+ using var decompressor = new NoneTiffCompression(default, default, default);
+ decompressor.Decompress(stream, 0, byteCount, 1, buffer);
Assert.Equal(expectedResult, buffer);
}
diff --git a/tests/ImageSharp.Tests/Formats/Tiff/Compression/PackBitsTiffCompressionTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/Compression/PackBitsTiffCompressionTests.cs
index b67cb8325..b56c1e7c9 100644
--- a/tests/ImageSharp.Tests/Formats/Tiff/Compression/PackBitsTiffCompressionTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Tiff/Compression/PackBitsTiffCompressionTests.cs
@@ -26,11 +26,12 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff.Compression
[InlineData(new byte[] { 0xFE, 0xAA, 0x02, 0x80, 0x00, 0x2A, 0xFD, 0xAA, 0x03, 0x80, 0x00, 0x2A, 0x22, 0xF7, 0xAA }, new byte[] { 0xAA, 0xAA, 0xAA, 0x80, 0x00, 0x2A, 0xAA, 0xAA, 0xAA, 0xAA, 0x80, 0x00, 0x2A, 0x22, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA })] // Apple PackBits sample
public void Decompress_ReadsData(byte[] inputData, byte[] expectedResult)
{
- var stream = new BufferedReadStream(Configuration.Default, new MemoryStream(inputData));
- var buffer = new byte[expectedResult.Length];
+ using var memoryStream = new MemoryStream(inputData);
+ using var stream = new BufferedReadStream(Configuration.Default, memoryStream);
+ byte[] buffer = new byte[expectedResult.Length];
using var decompressor = new PackBitsTiffCompression(new ArrayPoolMemoryAllocator(), default, default);
- decompressor.Decompress(stream, 0, (uint)inputData.Length, buffer);
+ decompressor.Decompress(stream, 0, (uint)inputData.Length, 1, buffer);
Assert.Equal(expectedResult, buffer);
}
@@ -41,7 +42,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff.Compression
{
// arrange
Span input = inputData.AsSpan();
- var compressed = new byte[expectedResult.Length];
+ byte[] compressed = new byte[expectedResult.Length];
// act
PackBitsWriter.PackBits(input, compressed);
diff --git a/tests/ImageSharp.Tests/Formats/Tiff/PhotometricInterpretation/BlackIsZeroTiffColorTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/PhotometricInterpretation/BlackIsZeroTiffColorTests.cs
index 769ab850e..38611c6f3 100644
--- a/tests/ImageSharp.Tests/Formats/Tiff/PhotometricInterpretation/BlackIsZeroTiffColorTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Tiff/PhotometricInterpretation/BlackIsZeroTiffColorTests.cs
@@ -188,7 +188,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff.PhotometricInterpretation
{
AssertDecode(expectedResult, pixels =>
{
- new BlackIsZero8TiffColor().Decode(inputData, pixels, left, top, width, height);
+ new BlackIsZero8TiffColor(Configuration.Default).Decode(inputData, pixels, left, top, width, height);
});
}
}
diff --git a/tests/ImageSharp.Tests/Formats/Tiff/PhotometricInterpretation/RgbTiffColorTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/PhotometricInterpretation/RgbTiffColorTests.cs
index 9adf59e48..f9f633106 100644
--- a/tests/ImageSharp.Tests/Formats/Tiff/PhotometricInterpretation/RgbTiffColorTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Tiff/PhotometricInterpretation/RgbTiffColorTests.cs
@@ -179,7 +179,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff.PhotometricInterpretation
{
AssertDecode(expectedResult, pixels =>
{
- new Rgb888TiffColor().Decode(inputData, pixels, left, top, width, height);
+ new Rgb888TiffColor(Configuration.Default).Decode(inputData, pixels, left, top, width, height);
});
}
}
diff --git a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs
index a007cd3a9..4a13bbe62 100644
--- a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs
@@ -10,9 +10,7 @@ using SixLabors.ImageSharp.Metadata;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison;
using SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs;
-
using Xunit;
-
using static SixLabors.ImageSharp.Tests.TestImages.Tiff;
namespace SixLabors.ImageSharp.Tests.Formats.Tiff
@@ -23,21 +21,21 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff
{
public static readonly string[] MultiframeTestImages = Multiframes;
- public static readonly string[] NotSupportedImages = NotSupported;
-
private static TiffDecoder TiffDecoder => new TiffDecoder();
private static MagickReferenceDecoder ReferenceDecoder => new MagickReferenceDecoder();
[Theory]
- [WithFileCollection(nameof(NotSupportedImages), PixelTypes.Rgba32)]
+ [WithFile(RgbUncompressedTiled, PixelTypes.Rgba32)]
+ [WithFile(MultiframeDifferentSize, PixelTypes.Rgba32)]
+ [WithFile(MultiframeDifferentVariants, PixelTypes.Rgba32)]
public void ThrowsNotSupported(TestImageProvider provider)
where TPixel : unmanaged, IPixel => Assert.Throws(() => provider.GetImage(TiffDecoder));
[Theory]
[InlineData(RgbUncompressed, 24, 256, 256, 300, 300, PixelResolutionUnit.PixelsPerInch)]
[InlineData(SmallRgbDeflate, 24, 32, 32, 96, 96, PixelResolutionUnit.PixelsPerInch)]
- [InlineData(Calliphora_GrayscaleUncompressed, 8, 804, 1198, 96, 96, PixelResolutionUnit.PixelsPerInch)]
+ [InlineData(Calliphora_GrayscaleUncompressed, 8, 200, 298, 96, 96, PixelResolutionUnit.PixelsPerInch)]
[InlineData(Flower4BitPalette, 4, 73, 43, 72, 72, PixelResolutionUnit.PixelsPerInch)]
public void Identify(string imagePath, int expectedPixelSize, int expectedWidth, int expectedHeight, double expectedHResolution, double expectedVResolution, PixelResolutionUnit expectedResolutionUnit)
{
@@ -84,6 +82,12 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff
public void TiffDecoder_CanDecode_Uncompressed(TestImageProvider provider)
where TPixel : unmanaged, IPixel => TestTiffDecoder(provider);
+ [Theory]
+ [WithFile(FlowerRgb888Planar6Strips, PixelTypes.Rgba32)]
+ [WithFile(FlowerRgb888Planar15Strips, PixelTypes.Rgba32)]
+ public void TiffDecoder_Planar(TestImageProvider provider)
+ where TPixel : unmanaged, IPixel => TestTiffDecoder(provider);
+
[Theory]
[WithFile(Calliphora_PaletteUncompressed, PixelTypes.Rgba32)]
[WithFile(PaletteDeflateMultistrip, PixelTypes.Rgba32)]
@@ -107,49 +111,120 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff
[Theory]
[WithFile(Flower2BitGray, PixelTypes.Rgba32)]
- public void TiffDecoder_CanDecode_2Bit(TestImageProvider provider)
+ public void TiffDecoder_CanDecode_2Bit_Gray(TestImageProvider provider)
where TPixel : unmanaged, IPixel => TestTiffDecoder(provider);
[Theory]
[WithFile(FlowerRgb222Contiguous, PixelTypes.Rgba32)]
[WithFile(FlowerRgb222Planar, PixelTypes.Rgba32)]
- [WithFile(Flower6BitGray, PixelTypes.Rgba32)]
public void TiffDecoder_CanDecode_6Bit(TestImageProvider provider)
where TPixel : unmanaged, IPixel => TestTiffDecoder(provider);
+ [Theory]
+ [WithFile(Flower6BitGray, PixelTypes.Rgba32)]
+ public void TiffDecoder_CanDecode_6Bit_Gray(TestImageProvider provider)
+ where TPixel : unmanaged, IPixel => TestTiffDecoder(provider);
+
[Theory]
[WithFile(Flower8BitGray, PixelTypes.Rgba32)]
- public void TiffDecoder_CanDecode_8Bit(TestImageProvider provider)
+ public void TiffDecoder_CanDecode_8Bit_Gray(TestImageProvider provider)
where TPixel : unmanaged, IPixel => TestTiffDecoder(provider);
[Theory]
[WithFile(Flower10BitGray, PixelTypes.Rgba32)]
- public void TiffDecoder_CanDecode_10Bit(TestImageProvider provider)
+ public void TiffDecoder_CanDecode_10Bit_Gray(TestImageProvider provider)
where TPixel : unmanaged, IPixel => TestTiffDecoder(provider);
[Theory]
[WithFile(FlowerRgb444Contiguous, PixelTypes.Rgba32)]
[WithFile(FlowerRgb444Planar, PixelTypes.Rgba32)]
- [WithFile(Flower12BitGray, PixelTypes.Rgba32)]
public void TiffDecoder_CanDecode_12Bit(TestImageProvider provider)
where TPixel : unmanaged, IPixel => TestTiffDecoder(provider);
+ [Theory]
+ [WithFile(Flower12BitGray, PixelTypes.Rgba32)]
+ public void TiffDecoder_CanDecode_12Bit_Gray(TestImageProvider provider)
+ where TPixel : unmanaged, IPixel => TestTiffDecoder(provider);
+
[Theory]
[WithFile(Flower14BitGray, PixelTypes.Rgba32)]
- public void TiffDecoder_CanDecode_14Bit(TestImageProvider provider)
+ public void TiffDecoder_CanDecode_14Bit_Gray(TestImageProvider provider)
where TPixel : unmanaged, IPixel => TestTiffDecoder(provider);
[Theory]
+ [WithFile(Flower16BitGrayLittleEndian, PixelTypes.Rgba32)]
[WithFile(Flower16BitGray, PixelTypes.Rgba32)]
- public void TiffDecoder_CanDecode_16Bit(TestImageProvider provider)
+ [WithFile(Flower16BitGrayMinIsWhiteLittleEndian, PixelTypes.Rgba32)]
+ [WithFile(Flower16BitGrayMinIsWhiteBigEndian, PixelTypes.Rgba32)]
+ public void TiffDecoder_CanDecode_16Bit_Gray(TestImageProvider provider)
where TPixel : unmanaged, IPixel => TestTiffDecoder(provider);
+ [Theory]
+ [WithFile(Flower16BitGrayPredictorBigEndian, PixelTypes.Rgba32)]
+ [WithFile(Flower16BitGrayPredictorLittleEndian, PixelTypes.Rgba32)]
+ public void TiffDecoder_CanDecode_16Bit_Gray_WithPredictor(TestImageProvider provider)
+ where TPixel : unmanaged, IPixel => TestTiffDecoder(provider);
+
+ [Theory]
+ [WithFile(Flower24BitGray, PixelTypes.Rgba32)]
+ [WithFile(Flower24BitGrayLittleEndian, PixelTypes.Rgba32)]
+ public void TiffDecoder_CanDecode_24Bit_Gray(TestImageProvider provider)
+ where TPixel : unmanaged, IPixel
+ {
+ // Note: because the MagickReferenceDecoder fails to load the image, we only debug save them.
+ using Image image = provider.GetImage();
+ image.DebugSave(provider);
+ }
+
+ [Theory]
+ [WithFile(FlowerYCbCr888Contiguous, PixelTypes.Rgba32)]
+ [WithFile(FlowerYCbCr888Planar, PixelTypes.Rgba32)]
+ [WithFile(RgbYCbCr888Contiguoush1v1, PixelTypes.Rgba32)]
+ [WithFile(RgbYCbCr888Contiguoush2v1, PixelTypes.Rgba32)]
+ [WithFile(RgbYCbCr888Contiguoush2v2, PixelTypes.Rgba32)]
+ [WithFile(RgbYCbCr888Contiguoush4v4, PixelTypes.Rgba32)]
+ [WithFile(FlowerYCbCr888Contiguoush2v1, PixelTypes.Rgba32)]
+ [WithFile(FlowerYCbCr888Contiguoush2v2, PixelTypes.Rgba32)]
+ [WithFile(FlowerYCbCr888Contiguoush4v4, PixelTypes.Rgba32)]
+ public void TiffDecoder_CanDecode_YCbCr_24Bit(TestImageProvider provider)
+ where TPixel : unmanaged, IPixel
+ {
+ // Note: The image from MagickReferenceDecoder does not look right, maybe we are doing something wrong
+ // converting the pixel data from Magick.Net to our format with YCbCr?
+ using Image image = provider.GetImage();
+ image.DebugSave(provider);
+ }
+
[Theory]
[WithFile(FlowerRgb101010Contiguous, PixelTypes.Rgba32)]
[WithFile(FlowerRgb101010Planar, PixelTypes.Rgba32)]
public void TiffDecoder_CanDecode_30Bit(TestImageProvider provider)
where TPixel : unmanaged, IPixel => TestTiffDecoder(provider);
+ [Theory]
+ [WithFile(Flower32BitGray, PixelTypes.Rgba32)]
+ [WithFile(Flower32BitGrayLittleEndian, PixelTypes.Rgba32)]
+ [WithFile(Flower32BitGrayMinIsWhite, PixelTypes.Rgba32)]
+ [WithFile(Flower32BitGrayMinIsWhiteLittleEndian, PixelTypes.Rgba32)]
+ public void TiffDecoder_CanDecode_32Bit_Gray(TestImageProvider provider)
+ where TPixel : unmanaged, IPixel
+ {
+ // Note: because the MagickReferenceDecoder fails to load the image, we only debug save them.
+ using Image image = provider.GetImage();
+ image.DebugSave(provider);
+ }
+
+ [Theory]
+ [WithFile(Flower32BitGrayPredictorBigEndian, PixelTypes.Rgba32)]
+ [WithFile(Flower32BitGrayPredictorLittleEndian, PixelTypes.Rgba32)]
+ public void TiffDecoder_CanDecode_32Bit_Gray_WithPredictor(TestImageProvider provider)
+ where TPixel : unmanaged, IPixel
+ {
+ // Note: because the MagickReferenceDecoder fails to load the image, we only debug save them.
+ using Image image = provider.GetImage();
+ image.DebugSave(provider);
+ }
+
[Theory]
[WithFile(FlowerRgb121212Contiguous, PixelTypes.Rgba32)]
public void TiffDecoder_CanDecode_36Bit(TestImageProvider provider)
@@ -163,10 +238,80 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff
[Theory]
[WithFile(FlowerRgb161616Contiguous, PixelTypes.Rgba32)]
+ [WithFile(FlowerRgb161616ContiguousLittleEndian, PixelTypes.Rgba32)]
[WithFile(FlowerRgb161616Planar, PixelTypes.Rgba32)]
+ [WithFile(FlowerRgb161616PlanarLittleEndian, PixelTypes.Rgba32)]
+ [WithFile(Issues1716Rgb161616BitLittleEndian, PixelTypes.Rgba32)]
public void TiffDecoder_CanDecode_48Bit(TestImageProvider provider)
where TPixel : unmanaged, IPixel => TestTiffDecoder(provider);
+ [Theory]
+ [WithFile(FlowerRgb161616PredictorBigEndian, PixelTypes.Rgba32)]
+ [WithFile(FlowerRgb161616PredictorLittleEndian, PixelTypes.Rgba32)]
+ public void TiffDecoder_CanDecode_48Bit_WithPredictor(TestImageProvider provider)
+ where TPixel : unmanaged, IPixel => TestTiffDecoder(provider);
+
+ [Theory]
+ [WithFile(FlowerRgb242424Contiguous, PixelTypes.Rgba32)]
+ [WithFile(FlowerRgb242424ContiguousLittleEndian, PixelTypes.Rgba32)]
+ [WithFile(FlowerRgb242424Planar, PixelTypes.Rgba32)]
+ [WithFile(FlowerRgb242424PlanarLittleEndian, PixelTypes.Rgba32)]
+ public void TiffDecoder_CanDecode_72Bit(TestImageProvider provider)
+ where TPixel : unmanaged, IPixel
+ {
+ // Note: because the MagickReferenceDecoder fails to load the image, we only debug save them.
+ using Image image = provider.GetImage();
+ image.DebugSave(provider);
+ }
+
+ [Theory]
+ [WithFile(FlowerRgb323232Contiguous, PixelTypes.Rgba32)]
+ [WithFile(FlowerRgb323232ContiguousLittleEndian, PixelTypes.Rgba32)]
+ [WithFile(FlowerRgb323232Planar, PixelTypes.Rgba32)]
+ [WithFile(FlowerRgb323232PlanarLittleEndian, PixelTypes.Rgba32)]
+ public void TiffDecoder_CanDecode_96Bit(TestImageProvider provider)
+ where TPixel : unmanaged, IPixel
+ {
+ // Note: because the MagickReferenceDecoder fails to load the image, we only debug save them.
+ using Image image = provider.GetImage();
+ image.DebugSave(provider);
+ }
+
+ [Theory]
+ [WithFile(FlowerRgbFloat323232, PixelTypes.Rgba32)]
+ [WithFile(FlowerRgbFloat323232LittleEndian, PixelTypes.Rgba32)]
+ public void TiffDecoder_CanDecode_Float_96Bit(TestImageProvider provider)
+ where TPixel : unmanaged, IPixel
+ {
+ // Note: because the MagickReferenceDecoder fails to load the image, we only debug save them.
+ using Image image = provider.GetImage();
+ image.DebugSave(provider);
+ }
+
+ [Theory]
+ [WithFile(FlowerRgb323232PredictorBigEndian, PixelTypes.Rgba32)]
+ [WithFile(FlowerRgb323232PredictorLittleEndian, PixelTypes.Rgba32)]
+ public void TiffDecoder_CanDecode_96Bit_WithPredictor(TestImageProvider provider)
+ where TPixel : unmanaged, IPixel
+ {
+ // Note: because the MagickReferenceDecoder fails to load the image, we only debug save them.
+ using Image image = provider.GetImage();
+ image.DebugSave(provider);
+ }
+
+ [Theory]
+ [WithFile(Flower32BitFloatGray, PixelTypes.Rgba32)]
+ [WithFile(Flower32BitFloatGrayLittleEndian, PixelTypes.Rgba32)]
+ [WithFile(Flower32BitFloatGrayMinIsWhite, PixelTypes.Rgba32)]
+ [WithFile(Flower32BitFloatGrayMinIsWhiteLittleEndian, PixelTypes.Rgba32)]
+ public void TiffDecoder_CanDecode_Float_96Bit_Gray(TestImageProvider provider)
+ where TPixel : unmanaged, IPixel
+ {
+ // Note: because the MagickReferenceDecoder fails to load the image, we only debug save them.
+ using Image image = provider.GetImage();
+ image.DebugSave(provider);
+ }
+
[Theory]
[WithFile(GrayscaleDeflateMultistrip, PixelTypes.Rgba32)]
[WithFile(RgbDeflateMultistrip, PixelTypes.Rgba32)]
@@ -209,6 +354,18 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff
public void TiffDecoder_CanDecode_Fax3Compressed(TestImageProvider provider)
where TPixel : unmanaged, IPixel => TestTiffDecoder(provider);
+ [Theory]
+ [WithFile(Fax4Compressed, PixelTypes.Rgba32)]
+ [WithFile(Fax4CompressedLowerOrderBitsFirst, PixelTypes.Rgba32)]
+ [WithFile(Calliphora_Fax4Compressed, PixelTypes.Rgba32)]
+ public void TiffDecoder_CanDecode_Fax4Compressed(TestImageProvider provider)
+ where TPixel : unmanaged, IPixel => TestTiffDecoder(provider);
+
+ [Theory]
+ [WithFile(CcittFax3LowerOrderBitsFirst, PixelTypes.Rgba32)]
+ public void TiffDecoder_CanDecode_Compressed_LowerOrderBitsFirst(TestImageProvider provider)
+ where TPixel : unmanaged, IPixel => TestTiffDecoder(provider);
+
[Theory]
[WithFile(Calliphora_RgbPackbits, PixelTypes.Rgba32)]
[WithFile(RgbPackbits, PixelTypes.Rgba32)]
@@ -216,6 +373,14 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff
public void TiffDecoder_CanDecode_PackBitsCompressed(TestImageProvider provider)
where TPixel : unmanaged, IPixel => TestTiffDecoder(provider);
+ [Theory]
+ [WithFile(RgbJpegCompressed, PixelTypes.Rgba32)]
+ [WithFile(RgbWithStripsJpegCompressed, PixelTypes.Rgba32)]
+ [WithFile(YCbCrJpegCompressed, PixelTypes.Rgba32)]
+ [WithFile(RgbJpegCompressedNoJpegTable, PixelTypes.Rgba32)]
+ public void TiffDecoder_CanDecode_JpegCompressed(TestImageProvider provider)
+ where TPixel : unmanaged, IPixel => TestTiffDecoder(provider, useExactComparer: false);
+
[Theory]
[WithFileCollection(nameof(MultiframeTestImages), PixelTypes.Rgba32)]
public void DecodeMultiframe(TestImageProvider provider)
diff --git a/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderBaseTester.cs b/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderBaseTester.cs
new file mode 100644
index 000000000..fb2292379
--- /dev/null
+++ b/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderBaseTester.cs
@@ -0,0 +1,113 @@
+// Copyright (c) Six Labors.
+// Licensed under the Apache License, Version 2.0.
+
+using System.IO;
+using SixLabors.ImageSharp.Formats;
+using SixLabors.ImageSharp.Formats.Tiff;
+using SixLabors.ImageSharp.Formats.Tiff.Constants;
+using SixLabors.ImageSharp.Metadata.Profiles.Exif;
+using SixLabors.ImageSharp.PixelFormats;
+using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison;
+using SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs;
+
+using Xunit;
+
+namespace SixLabors.ImageSharp.Tests.Formats.Tiff
+{
+ [Trait("Format", "Tiff")]
+ public abstract class TiffEncoderBaseTester
+ {
+ protected static readonly IImageDecoder ReferenceDecoder = new MagickReferenceDecoder();
+
+ protected static void TestStripLength(
+ TestImageProvider provider,
+ TiffPhotometricInterpretation photometricInterpretation,
+ TiffCompression compression,
+ bool useExactComparer = true,
+ float compareTolerance = 0.01f)
+ where TPixel : unmanaged, IPixel
+ {
+ // arrange
+ var tiffEncoder = new TiffEncoder() { PhotometricInterpretation = photometricInterpretation, Compression = compression };
+ using Image input = provider.GetImage();
+ using var memStream = new MemoryStream();
+ TiffFrameMetadata inputMeta = input.Frames.RootFrame.Metadata.GetTiffMetadata();
+ TiffCompression inputCompression = inputMeta.Compression ?? TiffCompression.None;
+
+ // act
+ input.Save(memStream, tiffEncoder);
+
+ // assert
+ memStream.Position = 0;
+ using var output = Image.Load(memStream);
+ ExifProfile exifProfileOutput = output.Frames.RootFrame.Metadata.ExifProfile;
+ TiffFrameMetadata outputMeta = output.Frames.RootFrame.Metadata.GetTiffMetadata();
+ ImageFrame rootFrame = output.Frames.RootFrame;
+
+ Number rowsPerStrip = exifProfileOutput.GetValue(ExifTag.RowsPerStrip) != null ? exifProfileOutput.GetValue(ExifTag.RowsPerStrip).Value : TiffConstants.RowsPerStripInfinity;
+ Assert.True(output.Height > (int)rowsPerStrip);
+ Assert.True(exifProfileOutput.GetValue(ExifTag.StripOffsets)?.Value.Length > 1);
+ Number[] stripByteCounts = exifProfileOutput.GetValue(ExifTag.StripByteCounts)?.Value;
+ Assert.NotNull(stripByteCounts);
+ Assert.True(stripByteCounts.Length > 1);
+ Assert.NotNull(outputMeta.BitsPerPixel);
+
+ foreach (Number sz in stripByteCounts)
+ {
+ Assert.True((uint)sz <= TiffConstants.DefaultStripSize);
+ }
+
+ // For uncompressed more accurate test.
+ if (compression == TiffCompression.None)
+ {
+ for (int i = 0; i < stripByteCounts.Length - 1; i++)
+ {
+ // The difference must be less than one row.
+ int stripBytes = (int)stripByteCounts[i];
+ int widthBytes = ((int)outputMeta.BitsPerPixel + 7) / 8 * rootFrame.Width;
+
+ Assert.True((TiffConstants.DefaultStripSize - stripBytes) < widthBytes);
+ }
+ }
+
+ // Compare with reference.
+ TestTiffEncoderCore(
+ provider,
+ inputMeta.BitsPerPixel,
+ photometricInterpretation,
+ inputCompression,
+ useExactComparer: useExactComparer,
+ compareTolerance: compareTolerance);
+ }
+
+ protected static void TestTiffEncoderCore(
+ TestImageProvider provider,
+ TiffBitsPerPixel? bitsPerPixel,
+ TiffPhotometricInterpretation photometricInterpretation,
+ TiffCompression compression = TiffCompression.None,
+ TiffPredictor predictor = TiffPredictor.None,
+ bool useExactComparer = true,
+ float compareTolerance = 0.001f,
+ IImageDecoder imageDecoder = null)
+ where TPixel : unmanaged, IPixel
+ {
+ using Image image = provider.GetImage();
+ var encoder = new TiffEncoder
+ {
+ PhotometricInterpretation = photometricInterpretation,
+ BitsPerPixel = bitsPerPixel,
+ Compression = compression,
+ HorizontalPredictor = predictor
+ };
+
+ // Does DebugSave & load reference CompareToReferenceInput():
+ image.VerifyEncoder(
+ provider,
+ "tiff",
+ bitsPerPixel,
+ encoder,
+ useExactComparer ? ImageComparer.Exact : ImageComparer.Tolerant(compareTolerance),
+ referenceDecoder: imageDecoder ?? ReferenceDecoder);
+ }
+ }
+}
diff --git a/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderHeaderTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderHeaderTests.cs
index acbe2b489..d05e37e2a 100644
--- a/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderHeaderTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderHeaderTests.cs
@@ -2,7 +2,6 @@
// Licensed under the Apache License, Version 2.0.
using System.IO;
-
using SixLabors.ImageSharp.Formats.Tiff;
using SixLabors.ImageSharp.Formats.Tiff.Writers;
using SixLabors.ImageSharp.Memory;
diff --git a/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderMultiframeTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderMultiframeTests.cs
new file mode 100644
index 000000000..3df3dea30
--- /dev/null
+++ b/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderMultiframeTests.cs
@@ -0,0 +1,178 @@
+// Copyright (c) Six Labors.
+// Licensed under the Apache License, Version 2.0.
+
+using System;
+using SixLabors.ImageSharp.Formats.Tiff;
+using SixLabors.ImageSharp.Formats.Tiff.Constants;
+using SixLabors.ImageSharp.PixelFormats;
+using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison;
+using Xunit;
+using static SixLabors.ImageSharp.Tests.TestImages.Tiff;
+
+namespace SixLabors.ImageSharp.Tests.Formats.Tiff
+{
+ [Trait("Format", "Tiff")]
+ public class TiffEncoderMultiframeTests : TiffEncoderBaseTester
+ {
+ [Theory]
+ [WithFile(MultiframeLzwPredictor, PixelTypes.Rgba32)]
+ public void TiffEncoder_EncodeMultiframe_Works(TestImageProvider provider)
+ where TPixel : unmanaged, IPixel => TestTiffEncoderCore(provider, TiffBitsPerPixel.Bit24, TiffPhotometricInterpretation.Rgb);
+
+ [Theory]
+ [WithFile(MultiframeDifferentSize, PixelTypes.Rgba32)]
+ [WithFile(MultiframeDifferentVariants, PixelTypes.Rgba32)]
+ public void TiffEncoder_EncodeMultiframe_NotSupport(TestImageProvider provider)
+ where TPixel : unmanaged, IPixel => Assert.Throws(() => TestTiffEncoderCore(provider, TiffBitsPerPixel.Bit24, TiffPhotometricInterpretation.Rgb));
+
+ [Theory]
+ [WithFile(MultiframeDeflateWithPreview, PixelTypes.Rgba32)]
+ public void TiffEncoder_EncodeMultiframe_WithPreview(TestImageProvider provider)
+ where TPixel : unmanaged, IPixel => TestTiffEncoderCore(provider, TiffBitsPerPixel.Bit24, TiffPhotometricInterpretation.Rgb);
+
+ [Theory]
+ [WithFile(TestImages.Gif.Receipt, PixelTypes.Rgb24)]
+ [WithFile(TestImages.Gif.Issues.BadDescriptorWidth, PixelTypes.Rgba32)]
+ public void TiffEncoder_EncodeMultiframe_Convert(TestImageProvider provider)
+ where TPixel : unmanaged, IPixel => TestTiffEncoderCore(provider, TiffBitsPerPixel.Bit48, TiffPhotometricInterpretation.Rgb);
+
+ [Theory]
+ [WithFile(MultiframeLzwPredictor, PixelTypes.Rgba32)]
+ public void TiffEncoder_EncodeMultiframe_RemoveFrames(TestImageProvider provider)
+ where TPixel : unmanaged, IPixel
+ {
+ using Image image = provider.GetImage();
+ Assert.True(image.Frames.Count > 1);
+
+ image.Frames.RemoveFrame(0);
+
+ TiffBitsPerPixel bitsPerPixel = TiffBitsPerPixel.Bit24;
+ var encoder = new TiffEncoder
+ {
+ PhotometricInterpretation = TiffPhotometricInterpretation.Rgb,
+ BitsPerPixel = bitsPerPixel,
+ Compression = TiffCompression.Deflate
+ };
+
+ image.VerifyEncoder(
+ provider,
+ "tiff",
+ bitsPerPixel,
+ encoder,
+ ImageComparer.Exact);
+ }
+
+ [Theory]
+ [WithFile(TestImages.Png.Bike, PixelTypes.Rgba32)]
+ public void TiffEncoder_EncodeMultiframe_AddFrames(TestImageProvider provider)
+ where TPixel : unmanaged, IPixel
+ {
+ using Image image = provider.GetImage();
+ Assert.Equal(1, image.Frames.Count);
+
+ using var image1 = new Image(image.Width, image.Height, Color.Green.ToRgba32());
+
+ using var image2 = new Image(image.Width, image.Height, Color.Yellow.ToRgba32());
+
+ image.Frames.AddFrame(image1.Frames.RootFrame);
+ image.Frames.AddFrame(image2.Frames.RootFrame);
+
+ TiffBitsPerPixel bitsPerPixel = TiffBitsPerPixel.Bit24;
+ var encoder = new TiffEncoder
+ {
+ PhotometricInterpretation = TiffPhotometricInterpretation.Rgb,
+ BitsPerPixel = bitsPerPixel,
+ Compression = TiffCompression.Deflate
+ };
+
+ using (var ms = new System.IO.MemoryStream())
+ {
+ image.Save(ms, encoder);
+
+ ms.Position = 0;
+ using var output = Image.Load(ms);
+
+ Assert.Equal(3, output.Frames.Count);
+
+ ImageFrame frame1 = output.Frames[1];
+ ImageFrame frame2 = output.Frames[2];
+
+ Assert.Equal(Color.Green.ToRgba32(), frame1[10, 10]);
+ Assert.Equal(Color.Yellow.ToRgba32(), frame2[10, 10]);
+
+ Assert.Equal(TiffCompression.Deflate, frame1.Metadata.GetTiffMetadata().Compression);
+ Assert.Equal(TiffCompression.Deflate, frame1.Metadata.GetTiffMetadata().Compression);
+
+ Assert.Equal(TiffPhotometricInterpretation.Rgb, frame1.Metadata.GetTiffMetadata().PhotometricInterpretation);
+ Assert.Equal(TiffPhotometricInterpretation.Rgb, frame2.Metadata.GetTiffMetadata().PhotometricInterpretation);
+ }
+
+ image.VerifyEncoder(
+ provider,
+ "tiff",
+ bitsPerPixel,
+ encoder,
+ ImageComparer.Exact);
+ }
+
+ [Theory]
+ [WithBlankImages(100, 100, PixelTypes.Rgba32)]
+ public void TiffEncoder_EncodeMultiframe_Create(TestImageProvider provider)
+ where TPixel : unmanaged, IPixel
+ {
+ using Image image = provider.GetImage();
+
+ using var image0 = new Image(image.Width, image.Height, Color.Red.ToRgba32());
+
+ using var image1 = new Image(image.Width, image.Height, Color.Green.ToRgba32());
+
+ using var image2 = new Image(image.Width, image.Height, Color.Yellow.ToRgba32());
+
+ image.Frames.AddFrame(image0.Frames.RootFrame);
+ image.Frames.AddFrame(image1.Frames.RootFrame);
+ image.Frames.AddFrame(image2.Frames.RootFrame);
+ image.Frames.RemoveFrame(0);
+
+ TiffBitsPerPixel bitsPerPixel = TiffBitsPerPixel.Bit8;
+ var encoder = new TiffEncoder
+ {
+ PhotometricInterpretation = TiffPhotometricInterpretation.PaletteColor,
+ BitsPerPixel = bitsPerPixel,
+ Compression = TiffCompression.Lzw
+ };
+
+ using (var ms = new System.IO.MemoryStream())
+ {
+ image.Save(ms, encoder);
+
+ ms.Position = 0;
+ using var output = Image.Load(ms);
+
+ Assert.Equal(3, output.Frames.Count);
+
+ ImageFrame frame0 = output.Frames[0];
+ ImageFrame frame1 = output.Frames[1];
+ ImageFrame frame2 = output.Frames[2];
+
+ Assert.Equal(Color.Red.ToRgba32(), frame0[10, 10]);
+ Assert.Equal(Color.Green.ToRgba32(), frame1[10, 10]);
+ Assert.Equal(Color.Yellow.ToRgba32(), frame2[10, 10]);
+
+ Assert.Equal(TiffCompression.Lzw, frame0.Metadata.GetTiffMetadata().Compression);
+ Assert.Equal(TiffCompression.Lzw, frame1.Metadata.GetTiffMetadata().Compression);
+ Assert.Equal(TiffCompression.Lzw, frame1.Metadata.GetTiffMetadata().Compression);
+
+ Assert.Equal(TiffPhotometricInterpretation.PaletteColor, frame0.Metadata.GetTiffMetadata().PhotometricInterpretation);
+ Assert.Equal(TiffPhotometricInterpretation.PaletteColor, frame1.Metadata.GetTiffMetadata().PhotometricInterpretation);
+ Assert.Equal(TiffPhotometricInterpretation.PaletteColor, frame2.Metadata.GetTiffMetadata().PhotometricInterpretation);
+ }
+
+ image.VerifyEncoder(
+ provider,
+ "tiff",
+ bitsPerPixel,
+ encoder,
+ ImageComparer.Exact);
+ }
+ }
+}
diff --git a/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderTests.cs
index 0286671ae..d85ed16a7 100644
--- a/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderTests.cs
@@ -2,27 +2,19 @@
// Licensed under the Apache License, Version 2.0.
using System.IO;
-
-using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.Formats.Tiff;
using SixLabors.ImageSharp.Formats.Tiff.Constants;
-using SixLabors.ImageSharp.Metadata.Profiles.Exif;
using SixLabors.ImageSharp.PixelFormats;
-using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison;
-using SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs;
using Xunit;
-
using static SixLabors.ImageSharp.Tests.TestImages.Tiff;
namespace SixLabors.ImageSharp.Tests.Formats.Tiff
{
[Collection("RunSerial")]
[Trait("Format", "Tiff")]
- public class TiffEncoderTests
+ public class TiffEncoderTests : TiffEncoderBaseTester
{
- private static readonly IImageDecoder ReferenceDecoder = new MagickReferenceDecoder();
-
[Theory]
[InlineData(null, TiffBitsPerPixel.Bit24)]
[InlineData(TiffPhotometricInterpretation.Rgb, TiffBitsPerPixel.Bit24)]
@@ -121,10 +113,14 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff
[InlineData(TiffPhotometricInterpretation.BlackIsZero, TiffCompression.Ccitt1D, TiffBitsPerPixel.Bit1, TiffCompression.Ccitt1D)]
[InlineData(TiffPhotometricInterpretation.Rgb, TiffCompression.ItuTRecT43, TiffBitsPerPixel.Bit24, TiffCompression.None)]
[InlineData(TiffPhotometricInterpretation.Rgb, TiffCompression.ItuTRecT82, TiffBitsPerPixel.Bit24, TiffCompression.None)]
- [InlineData(TiffPhotometricInterpretation.Rgb, TiffCompression.Jpeg, TiffBitsPerPixel.Bit24, TiffCompression.None)]
+ [InlineData(TiffPhotometricInterpretation.Rgb, TiffCompression.Jpeg, TiffBitsPerPixel.Bit24, TiffCompression.Jpeg)]
[InlineData(TiffPhotometricInterpretation.Rgb, TiffCompression.OldDeflate, TiffBitsPerPixel.Bit24, TiffCompression.None)]
[InlineData(TiffPhotometricInterpretation.Rgb, TiffCompression.OldJpeg, TiffBitsPerPixel.Bit24, TiffCompression.None)]
- public void EncoderOptions_SetPhotometricInterpretationAndCompression_Works(TiffPhotometricInterpretation? photometricInterpretation, TiffCompression compression, TiffBitsPerPixel expectedBitsPerPixel, TiffCompression expectedCompression)
+ public void EncoderOptions_SetPhotometricInterpretationAndCompression_Works(
+ TiffPhotometricInterpretation? photometricInterpretation,
+ TiffCompression compression,
+ TiffBitsPerPixel expectedBitsPerPixel,
+ TiffCompression expectedCompression)
{
// arrange
var tiffEncoder = new TiffEncoder { PhotometricInterpretation = photometricInterpretation, Compression = compression };
@@ -291,6 +287,11 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff
public void TiffEncoder_EncodeRgb_WithPackBitsCompression_Works(TestImageProvider provider)
where TPixel : unmanaged, IPixel => TestTiffEncoderCore(provider, TiffBitsPerPixel.Bit24, TiffPhotometricInterpretation.Rgb, TiffCompression.PackBits);
+ [Theory]
+ [WithFile(Calliphora_RgbUncompressed, PixelTypes.Rgba32)]
+ public void TiffEncoder_EncodeRgb_WithJpegCompression_Works(TestImageProvider provider)
+ where TPixel : unmanaged, IPixel => TestTiffEncoderCore(provider, TiffBitsPerPixel.Bit24, TiffPhotometricInterpretation.Rgb, TiffCompression.Jpeg, useExactComparer: false, compareTolerance: 0.012f);
+
[Theory]
[WithFile(Calliphora_GrayscaleUncompressed, PixelTypes.Rgba32)]
public void TiffEncoder_EncodeGray_Works(TestImageProvider provider)
@@ -451,96 +452,5 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff
var encoder = new TiffEncoder { PhotometricInterpretation = photometricInterpretation };
image.DebugSave(provider, encoder);
}
-
- private static void TestStripLength(
- TestImageProvider provider,
- TiffPhotometricInterpretation photometricInterpretation,
- TiffCompression compression,
- bool useExactComparer = true,
- float compareTolerance = 0.01f)
- where TPixel : unmanaged, IPixel
- {
- // arrange
- var tiffEncoder = new TiffEncoder() { PhotometricInterpretation = photometricInterpretation, Compression = compression };
- using Image input = provider.GetImage();
- using var memStream = new MemoryStream();
- TiffFrameMetadata inputMeta = input.Frames.RootFrame.Metadata.GetTiffMetadata();
- TiffCompression inputCompression = inputMeta.Compression ?? TiffCompression.None;
-
- // act
- input.Save(memStream, tiffEncoder);
-
- // assert
- memStream.Position = 0;
- using var output = Image.Load(memStream);
- ExifProfile exifProfileOutput = output.Frames.RootFrame.Metadata.ExifProfile;
- TiffFrameMetadata outputMeta = output.Frames.RootFrame.Metadata.GetTiffMetadata();
- ImageFrame rootFrame = output.Frames.RootFrame;
-
- Number rowsPerStrip = exifProfileOutput.GetValue(ExifTag.RowsPerStrip) != null ? exifProfileOutput.GetValue(ExifTag.RowsPerStrip).Value : TiffConstants.RowsPerStripInfinity;
- Assert.True(output.Height > (int)rowsPerStrip);
- Assert.True(exifProfileOutput.GetValue(ExifTag.StripOffsets)?.Value.Length > 1);
- Number[] stripByteCounts = exifProfileOutput.GetValue(ExifTag.StripByteCounts)?.Value;
- Assert.NotNull(stripByteCounts);
- Assert.True(stripByteCounts.Length > 1);
- Assert.NotNull(outputMeta.BitsPerPixel);
-
- foreach (Number sz in stripByteCounts)
- {
- Assert.True((uint)sz <= TiffConstants.DefaultStripSize);
- }
-
- // For uncompressed more accurate test.
- if (compression == TiffCompression.None)
- {
- for (int i = 0; i < stripByteCounts.Length - 1; i++)
- {
- // The difference must be less than one row.
- int stripBytes = (int)stripByteCounts[i];
- int widthBytes = ((int)outputMeta.BitsPerPixel + 7) / 8 * rootFrame.Width;
-
- Assert.True((TiffConstants.DefaultStripSize - stripBytes) < widthBytes);
- }
- }
-
- // Compare with reference.
- TestTiffEncoderCore(
- provider,
- inputMeta.BitsPerPixel,
- photometricInterpretation,
- inputCompression,
- useExactComparer: useExactComparer,
- compareTolerance: compareTolerance);
- }
-
- private static void TestTiffEncoderCore(
- TestImageProvider provider,
- TiffBitsPerPixel? bitsPerPixel,
- TiffPhotometricInterpretation photometricInterpretation,
- TiffCompression compression = TiffCompression.None,
- TiffPredictor predictor = TiffPredictor.None,
- bool useExactComparer = true,
- float compareTolerance = 0.001f,
- IImageDecoder imageDecoder = null)
- where TPixel : unmanaged, IPixel
- {
- using Image image = provider.GetImage();
- var encoder = new TiffEncoder
- {
- PhotometricInterpretation = photometricInterpretation,
- BitsPerPixel = bitsPerPixel,
- Compression = compression,
- HorizontalPredictor = predictor
- };
-
- // Does DebugSave & load reference CompareToReferenceInput():
- image.VerifyEncoder(
- provider,
- "tiff",
- bitsPerPixel,
- encoder,
- useExactComparer ? ImageComparer.Exact : ImageComparer.Tolerant(compareTolerance),
- referenceDecoder: imageDecoder ?? ReferenceDecoder);
- }
}
}
diff --git a/tests/ImageSharp.Tests/Formats/Tiff/TiffMetadataTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/TiffMetadataTests.cs
index c80d9fc16..cdd9616a7 100644
--- a/tests/ImageSharp.Tests/Formats/Tiff/TiffMetadataTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Tiff/TiffMetadataTests.cs
@@ -12,11 +12,11 @@ using SixLabors.ImageSharp.Metadata.Profiles.Iptc;
using SixLabors.ImageSharp.PixelFormats;
using Xunit;
-
using static SixLabors.ImageSharp.Tests.TestImages.Tiff;
namespace SixLabors.ImageSharp.Tests.Formats.Tiff
{
+ [Collection("RunSerial")]
[Trait("Format", "Tiff")]
public class TiffMetadataTests
{
@@ -278,8 +278,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff
PixelResolutionUnit resolutionUnitInput = UnitConverter.ExifProfileToResolutionUnit(exifProfileInput);
PixelResolutionUnit resolutionUnitEncoded = UnitConverter.ExifProfileToResolutionUnit(encodedImageExifProfile);
Assert.Equal(resolutionUnitInput, resolutionUnitEncoded);
- Assert.Equal(exifProfileInput.GetValue(ExifTag.XResolution), encodedImageExifProfile.GetValue(ExifTag.XResolution));
- Assert.Equal(exifProfileInput.GetValue(ExifTag.YResolution), encodedImageExifProfile.GetValue(ExifTag.YResolution));
+ Assert.Equal(exifProfileInput.GetValue(ExifTag.XResolution).Value.ToDouble(), encodedImageExifProfile.GetValue(ExifTag.XResolution).Value.ToDouble());
+ Assert.Equal(exifProfileInput.GetValue(ExifTag.YResolution).Value.ToDouble(), encodedImageExifProfile.GetValue(ExifTag.YResolution).Value.ToDouble());
Assert.Equal(xmpProfileInput, encodedImageXmpProfile);
diff --git a/tests/ImageSharp.Tests/Formats/Tiff/TiffTestUtils.cs b/tests/ImageSharp.Tests/Formats/Tiff/TiffTestUtils.cs
index 5ac2f475e..eacadae2b 100644
--- a/tests/ImageSharp.Tests/Formats/Tiff/TiffTestUtils.cs
+++ b/tests/ImageSharp.Tests/Formats/Tiff/TiffTestUtils.cs
@@ -4,7 +4,6 @@
using System;
using System.Collections.Generic;
using System.IO;
-
using ImageMagick;
using SixLabors.ImageSharp.PixelFormats;
diff --git a/tests/ImageSharp.Tests/Formats/Tiff/Utils/TiffWriterTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/Utils/TiffWriterTests.cs
index 6eea0a1a9..51ad9498d 100644
--- a/tests/ImageSharp.Tests/Formats/Tiff/Utils/TiffWriterTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Tiff/Utils/TiffWriterTests.cs
@@ -106,12 +106,13 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff.Utils
Assert.Equal(
new byte[]
- {
- 0x11, 0x11, 0x11, 0x11,
- 0x78, 0x56, 0x34, 0x12,
- 0x33, 0x33, 0x33, 0x33,
- 0x44, 0x44, 0x44, 0x44
- }, stream.ToArray());
+ {
+ 0x11, 0x11, 0x11, 0x11,
+ 0x78, 0x56, 0x34, 0x12,
+ 0x33, 0x33, 0x33, 0x33,
+ 0x44, 0x44, 0x44, 0x44
+ },
+ stream.ToArray());
}
}
}
diff --git a/tests/ImageSharp.Tests/Formats/WebP/DominantCostRangeTests.cs b/tests/ImageSharp.Tests/Formats/WebP/DominantCostRangeTests.cs
new file mode 100644
index 000000000..417b9fed5
--- /dev/null
+++ b/tests/ImageSharp.Tests/Formats/WebP/DominantCostRangeTests.cs
@@ -0,0 +1,79 @@
+// Copyright (c) Six Labors.
+// Licensed under the Apache License, Version 2.0.
+
+using SixLabors.ImageSharp.Formats.Webp.Lossless;
+using Xunit;
+
+namespace SixLabors.ImageSharp.Tests.Formats.Webp
+{
+ [Trait("Format", "Webp")]
+ public class DominantCostRangeTests
+ {
+ [Fact]
+ public void DominantCost_Constructor()
+ {
+ var dominantCostRange = new DominantCostRange();
+ Assert.Equal(0, dominantCostRange.LiteralMax);
+ Assert.Equal(double.MaxValue, dominantCostRange.LiteralMin);
+ Assert.Equal(0, dominantCostRange.RedMax);
+ Assert.Equal(double.MaxValue, dominantCostRange.RedMin);
+ Assert.Equal(0, dominantCostRange.BlueMax);
+ Assert.Equal(double.MaxValue, dominantCostRange.BlueMin);
+ }
+
+ [Fact]
+ public void UpdateDominantCostRange_Works()
+ {
+ // arrange
+ var dominantCostRange = new DominantCostRange();
+ var histogram = new Vp8LHistogram(10)
+ {
+ LiteralCost = 1.0d,
+ RedCost = 2.0d,
+ BlueCost = 3.0d
+ };
+
+ // act
+ dominantCostRange.UpdateDominantCostRange(histogram);
+
+ // assert
+ Assert.Equal(1.0d, dominantCostRange.LiteralMax);
+ Assert.Equal(1.0d, dominantCostRange.LiteralMin);
+ Assert.Equal(2.0d, dominantCostRange.RedMax);
+ Assert.Equal(2.0d, dominantCostRange.RedMin);
+ Assert.Equal(3.0d, dominantCostRange.BlueMax);
+ Assert.Equal(3.0d, dominantCostRange.BlueMin);
+ }
+
+ [Theory]
+ [InlineData(3, 19)]
+ [InlineData(4, 34)]
+ public void GetHistoBinIndex_Works(int partitions, int expectedIndex)
+ {
+ // arrange
+ var dominantCostRange = new DominantCostRange()
+ {
+ BlueMax = 253.4625,
+ BlueMin = 109.0,
+ LiteralMax = 285.0,
+ LiteralMin = 133.0,
+ RedMax = 191.0,
+ RedMin = 109.0
+ };
+ var histogram = new Vp8LHistogram(6)
+ {
+ LiteralCost = 247.0d,
+ RedCost = 112.0d,
+ BlueCost = 202.0d,
+ BitCost = 733.0d
+ };
+ dominantCostRange.UpdateDominantCostRange(histogram);
+
+ // act
+ int binIndex = dominantCostRange.GetHistoBinIndex(histogram, partitions);
+
+ // assert
+ Assert.Equal(expectedIndex, binIndex);
+ }
+ }
+}
diff --git a/tests/ImageSharp.Tests/Formats/WebP/ImageExtensionsTests.cs b/tests/ImageSharp.Tests/Formats/WebP/ImageExtensionsTests.cs
new file mode 100644
index 000000000..a17248612
--- /dev/null
+++ b/tests/ImageSharp.Tests/Formats/WebP/ImageExtensionsTests.cs
@@ -0,0 +1,156 @@
+// Copyright (c) Six Labors.
+// Licensed under the Apache License, Version 2.0.
+
+using System.IO;
+using System.Threading.Tasks;
+using SixLabors.ImageSharp.Formats;
+using SixLabors.ImageSharp.Formats.Webp;
+using SixLabors.ImageSharp.PixelFormats;
+using Xunit;
+
+namespace SixLabors.ImageSharp.Tests.Formats.Webp
+{
+ [Trait("Format", "Webp")]
+ public class ImageExtensionsTests
+ {
+ [Fact]
+ public void SaveAsWebp_Path()
+ {
+ string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageExtensionsTests));
+ string file = Path.Combine(dir, "SaveAsWebp_Path.webp");
+
+ using (var image = new Image(10, 10))
+ {
+ image.SaveAsWebp(file);
+ }
+
+ using (Image.Load(file, out IImageFormat mime))
+ {
+ Assert.Equal("image/webp", mime.DefaultMimeType);
+ }
+ }
+
+ [Fact]
+ public async Task SaveAsWebpAsync_Path()
+ {
+ string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageExtensionsTests));
+ string file = Path.Combine(dir, "SaveAsWebpAsync_Path.webp");
+
+ using (var image = new Image(10, 10))
+ {
+ await image.SaveAsWebpAsync(file);
+ }
+
+ using (Image.Load(file, out IImageFormat mime))
+ {
+ Assert.Equal("image/webp", mime.DefaultMimeType);
+ }
+ }
+
+ [Fact]
+ public void SaveAsWebp_Path_Encoder()
+ {
+ string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageExtensions));
+ string file = Path.Combine(dir, "SaveAsWebp_Path_Encoder.webp");
+
+ using (var image = new Image(10, 10))
+ {
+ image.SaveAsWebp(file, new WebpEncoder());
+ }
+
+ using (Image.Load(file, out IImageFormat mime))
+ {
+ Assert.Equal("image/webp", mime.DefaultMimeType);
+ }
+ }
+
+ [Fact]
+ public async Task SaveAsWebpAsync_Path_Encoder()
+ {
+ string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageExtensions));
+ string file = Path.Combine(dir, "SaveAsWebpAsync_Path_Encoder.webp");
+
+ using (var image = new Image(10, 10))
+ {
+ await image.SaveAsWebpAsync(file, new WebpEncoder());
+ }
+
+ using (Image.Load(file, out IImageFormat mime))
+ {
+ Assert.Equal("image/webp", mime.DefaultMimeType);
+ }
+ }
+
+ [Fact]
+ public void SaveAsWebp_Stream()
+ {
+ using var memoryStream = new MemoryStream();
+
+ using (var image = new Image(10, 10))
+ {
+ image.SaveAsWebp(memoryStream);
+ }
+
+ memoryStream.Position = 0;
+
+ using (Image.Load(memoryStream, out IImageFormat mime))
+ {
+ Assert.Equal("image/webp", mime.DefaultMimeType);
+ }
+ }
+
+ [Fact]
+ public async Task SaveAsWebpAsync_StreamAsync()
+ {
+ using var memoryStream = new MemoryStream();
+
+ using (var image = new Image(10, 10))
+ {
+ await image.SaveAsWebpAsync(memoryStream);
+ }
+
+ memoryStream.Position = 0;
+
+ using (Image.Load(memoryStream, out IImageFormat mime))
+ {
+ Assert.Equal("image/webp", mime.DefaultMimeType);
+ }
+ }
+
+ [Fact]
+ public void SaveAsWebp_Stream_Encoder()
+ {
+ using var memoryStream = new MemoryStream();
+
+ using (var image = new Image(10, 10))
+ {
+ image.SaveAsWebp(memoryStream, new WebpEncoder());
+ }
+
+ memoryStream.Position = 0;
+
+ using (Image.Load(memoryStream, out IImageFormat mime))
+ {
+ Assert.Equal("image/webp", mime.DefaultMimeType);
+ }
+ }
+
+ [Fact]
+ public async Task SaveAsWebpAsync_Stream_Encoder()
+ {
+ using var memoryStream = new MemoryStream();
+
+ using (var image = new Image(10, 10))
+ {
+ await image.SaveAsWebpAsync(memoryStream, new WebpEncoder());
+ }
+
+ memoryStream.Position = 0;
+
+ using (Image.Load(memoryStream, out IImageFormat mime))
+ {
+ Assert.Equal("image/webp", mime.DefaultMimeType);
+ }
+ }
+ }
+}
diff --git a/tests/ImageSharp.Tests/Formats/WebP/LosslessUtilsTests.cs b/tests/ImageSharp.Tests/Formats/WebP/LosslessUtilsTests.cs
new file mode 100644
index 000000000..c70f332ef
--- /dev/null
+++ b/tests/ImageSharp.Tests/Formats/WebP/LosslessUtilsTests.cs
@@ -0,0 +1,267 @@
+// Copyright (c) Six Labors.
+// Licensed under the Apache License, Version 2.0.
+
+using SixLabors.ImageSharp.Formats.Webp.Lossless;
+using SixLabors.ImageSharp.Tests.TestUtilities;
+using Xunit;
+
+namespace SixLabors.ImageSharp.Tests.Formats.Webp
+{
+ [Trait("Format", "Webp")]
+ public class LosslessUtilsTests
+ {
+ private static void RunSubtractGreenTest()
+ {
+ uint[] pixelData =
+ {
+ 4293035898, 4293101432, 4292903793, 4292838511, 4292837995, 4292771950, 4292903791, 4293299316,
+ 4293563769, 4293629303, 4293363312, 4291913575, 4289282905, 4288692313, 4289349210, 4289809240,
+ 4289743703, 4289874775, 4289940567, 4289743701, 4290137943, 4290860378, 4291058267, 4291386715,
+ 4291583836, 4291715937, 4291585379, 4291650657, 4291650143, 4291584863, 4291716451, 4291847521,
+ 4291913571, 4292044130, 4291978850, 4291847521, 4291847524, 4291847779, 4291913571, 4291848293,
+ 4291651689, 4291585895, 4291519584, 4291715936, 4291520355, 4291650658, 4291847263, 4291913313,
+ 4291847777, 4291781731, 4291783015
+ };
+
+ uint[] expectedOutput =
+ {
+ 4284188659, 4284254193, 4284318702, 4284187883, 4284318441, 4284383470, 4284318700, 4284124392,
+ 4283799012, 4283864546, 4284581610, 4285163264, 4284891926, 4284497945, 4284761620, 4284893965,
+ 4284828428, 4284959500, 4284959755, 4284828426, 4284960520, 4285289733, 4285159937, 4285292030,
+ 4285358077, 4285228030, 4284966398, 4285097213, 4285227773, 4285096956, 4285097470, 4285228540,
+ 4285163516, 4285425149, 4285294332, 4285228540, 4285228543, 4285163261, 4285163516, 4285032701,
+ 4284835841, 4284835584, 4284966140, 4285228029, 4284770300, 4285097214, 4285293819, 4285228795,
+ 4285163259, 4285228287, 4284901886
+ };
+
+ LosslessUtils.SubtractGreenFromBlueAndRed(pixelData);
+
+ Assert.Equal(expectedOutput, pixelData);
+ }
+
+ private static void RunAddGreenToBlueAndRedTest()
+ {
+ uint[] pixelData =
+ {
+ 4284188659, 4284254193, 4284318702, 4284187883, 4284318441, 4284383470, 4284318700, 4284124392,
+ 4283799012, 4283864546, 4284581610, 4285163264, 4284891926, 4284497945, 4284761620, 4284893965,
+ 4284828428, 4284959500, 4284959755, 4284828426, 4284960520, 4285289733, 4285159937, 4285292030,
+ 4285358077, 4285228030, 4284966398, 4285097213, 4285227773, 4285096956, 4285097470, 4285228540,
+ 4285163516, 4285425149, 4285294332, 4285228540, 4285228543, 4285163261, 4285163516, 4285032701,
+ 4284835841, 4284835584, 4284966140, 4285228029, 4284770300, 4285097214, 4285293819, 4285228795,
+ 4285163259, 4285228287, 4284901886
+ };
+
+ uint[] expectedOutput =
+ {
+ 4293035898, 4293101432, 4292903793, 4292838511, 4292837995, 4292771950, 4292903791, 4293299316,
+ 4293563769, 4293629303, 4293363312, 4291913575, 4289282905, 4288692313, 4289349210, 4289809240,
+ 4289743703, 4289874775, 4289940567, 4289743701, 4290137943, 4290860378, 4291058267, 4291386715,
+ 4291583836, 4291715937, 4291585379, 4291650657, 4291650143, 4291584863, 4291716451, 4291847521,
+ 4291913571, 4292044130, 4291978850, 4291847521, 4291847524, 4291847779, 4291913571, 4291848293,
+ 4291651689, 4291585895, 4291519584, 4291715936, 4291520355, 4291650658, 4291847263, 4291913313,
+ 4291847777, 4291781731, 4291783015
+ };
+
+ LosslessUtils.AddGreenToBlueAndRed(pixelData);
+
+ Assert.Equal(expectedOutput, pixelData);
+ }
+
+ private static void RunTransformColorTest()
+ {
+ uint[] pixelData =
+ {
+ 5998579, 65790, 130301, 16646653, 196350, 130565, 16712702, 16583164, 16452092, 65790, 782600,
+ 647446, 16571414, 16448771, 263931, 132601, 16711935, 131072, 511, 16711679, 132350, 329469,
+ 16647676, 132093, 66303, 16647169, 16515584, 196607, 196096, 16646655, 514, 131326, 16712192,
+ 327169, 16646655, 16776960, 3, 16712190, 511, 16646401, 16580612, 65535, 196092, 327425, 16319743,
+ 392450, 196861, 16712192, 16711680, 130564, 16451071
+ };
+
+ var m = new Vp8LMultipliers()
+ {
+ GreenToBlue = 240,
+ GreenToRed = 232,
+ RedToBlue = 0
+ };
+
+ uint[] expectedOutput =
+ {
+ 100279, 65790, 16710907, 16712190, 130813, 65028, 131840, 264449, 133377, 65790, 61697, 15917319,
+ 14801924, 16317698, 591614, 394748, 16711935, 131072, 65792, 16711679, 328704, 656896, 132607,
+ 328703, 197120, 66563, 16646657, 196607, 130815, 16711936, 131587, 131326, 66049, 261632, 16711936,
+ 16776960, 3, 511, 65792, 16711938, 16580612, 65535, 65019, 327425, 16516097, 261377, 196861, 66049,
+ 16711680, 65027, 16712962
+ };
+
+ LosslessUtils.TransformColor(m, pixelData, pixelData.Length);
+
+ Assert.Equal(expectedOutput, pixelData);
+ }
+
+ private static void RunTransformColorInverseTest()
+ {
+ uint[] pixelData =
+ {
+ 100279, 65790, 16710907, 16712190, 130813, 65028, 131840, 264449, 133377, 65790, 61697, 15917319,
+ 14801924, 16317698, 591614, 394748, 16711935, 131072, 65792, 16711679, 328704, 656896, 132607,
+ 328703, 197120, 66563, 16646657, 196607, 130815, 16711936, 131587, 131326, 66049, 261632, 16711936,
+ 16776960, 3, 511, 65792, 16711938, 16580612, 65535, 65019, 327425, 16516097, 261377, 196861, 66049,
+ 16711680, 65027, 16712962
+ };
+
+ var m = new Vp8LMultipliers()
+ {
+ GreenToBlue = 240,
+ GreenToRed = 232,
+ RedToBlue = 0
+ };
+
+ uint[] expectedOutput =
+ {
+ 5998579, 65790, 130301, 16646653, 196350, 130565, 16712702, 16583164, 16452092, 65790, 782600,
+ 647446, 16571414, 16448771, 263931, 132601, 16711935, 131072, 511, 16711679, 132350, 329469,
+ 16647676, 132093, 66303, 16647169, 16515584, 196607, 196096, 16646655, 514, 131326, 16712192,
+ 327169, 16646655, 16776960, 3, 16712190, 511, 16646401, 16580612, 65535, 196092, 327425, 16319743,
+ 392450, 196861, 16712192, 16711680, 130564, 16451071
+ };
+
+ LosslessUtils.TransformColorInverse(m, pixelData);
+
+ Assert.Equal(expectedOutput, pixelData);
+ }
+
+ private static void RunPredictor11Test()
+ {
+ // arrange
+ uint[] topData = { 4278258949, 4278258949 };
+ uint left = 4294839812;
+ short[] scratch = new short[8];
+ uint expectedResult = 4294839812;
+
+ // act
+ unsafe
+ {
+ fixed (uint* top = &topData[1])
+ {
+ uint actual = LosslessUtils.Predictor11(left, top, scratch);
+
+ // assert
+ Assert.Equal(expectedResult, actual);
+ }
+ }
+ }
+
+ private static void RunPredictor12Test()
+ {
+ // arrange
+ uint[] topData = { 4294844413, 4294779388 };
+ uint left = 4294844413;
+ uint expectedResult = 4294779388;
+
+ // act
+ unsafe
+ {
+ fixed (uint* top = &topData[1])
+ {
+ uint actual = LosslessUtils.Predictor12(left, top);
+
+ // assert
+ Assert.Equal(expectedResult, actual);
+ }
+ }
+ }
+
+ private static void RunPredictor13Test()
+ {
+ // arrange
+ uint[] topData = { 4278193922, 4278193666 };
+ uint left = 4278193410;
+ uint expectedResult = 4278193154;
+
+ // act
+ unsafe
+ {
+ fixed (uint* top = &topData[1])
+ {
+ uint actual = LosslessUtils.Predictor13(left, top);
+
+ // assert
+ Assert.Equal(expectedResult, actual);
+ }
+ }
+ }
+
+ [Fact]
+ public void Predictor11_Works() => RunPredictor11Test();
+
+ [Fact]
+ public void Predictor12_Works() => RunPredictor12Test();
+
+ [Fact]
+ public void Predictor13_Works() => RunPredictor13Test();
+
+ [Fact]
+ public void SubtractGreen_Works() => RunSubtractGreenTest();
+
+ [Fact]
+ public void AddGreenToBlueAndRed_Works() => RunAddGreenToBlueAndRedTest();
+
+ [Fact]
+ public void TransformColor_Works() => RunTransformColorTest();
+
+ [Fact]
+ public void TransformColorInverse_Works() => RunTransformColorInverseTest();
+
+#if SUPPORTS_RUNTIME_INTRINSICS
+ [Fact]
+ public void Predictor11_WithHardwareIntrinsics_Works() => FeatureTestRunner.RunWithHwIntrinsicsFeature(RunPredictor11Test, HwIntrinsics.AllowAll);
+
+ [Fact]
+ public void Predictor11_WithoutSSE2_Works() => FeatureTestRunner.RunWithHwIntrinsicsFeature(RunPredictor11Test, HwIntrinsics.DisableSSE2);
+
+ [Fact]
+ public void Predictor12_WithHardwareIntrinsics_Works() => FeatureTestRunner.RunWithHwIntrinsicsFeature(RunPredictor12Test, HwIntrinsics.AllowAll);
+
+ [Fact]
+ public void Predictor12_WithoutSSE2_Works() => FeatureTestRunner.RunWithHwIntrinsicsFeature(RunPredictor12Test, HwIntrinsics.DisableSSE2);
+
+ [Fact]
+ public void Predictor13_WithHardwareIntrinsics_Works() => FeatureTestRunner.RunWithHwIntrinsicsFeature(RunPredictor13Test, HwIntrinsics.AllowAll);
+
+ [Fact]
+ public void Predictor13_WithoutSSE2_Works() => FeatureTestRunner.RunWithHwIntrinsicsFeature(RunPredictor13Test, HwIntrinsics.DisableSSE2);
+
+ [Fact]
+ public void SubtractGreen_WithHardwareIntrinsics_Works() => FeatureTestRunner.RunWithHwIntrinsicsFeature(RunSubtractGreenTest, HwIntrinsics.AllowAll);
+
+ [Fact]
+ public void SubtractGreen_WithoutAvx_Works() => FeatureTestRunner.RunWithHwIntrinsicsFeature(RunSubtractGreenTest, HwIntrinsics.DisableAVX);
+
+ [Fact]
+ public void SubtractGreen_WithoutAvxOrSSSE3_Works() => FeatureTestRunner.RunWithHwIntrinsicsFeature(RunSubtractGreenTest, HwIntrinsics.DisableAVX | HwIntrinsics.DisableSSSE3);
+
+ [Fact]
+ public void AddGreenToBlueAndRed_WithHardwareIntrinsics_Works() => FeatureTestRunner.RunWithHwIntrinsicsFeature(RunAddGreenToBlueAndRedTest, HwIntrinsics.AllowAll);
+
+ [Fact]
+ public void AddGreenToBlueAndRed_WithoutAvx_Works() => FeatureTestRunner.RunWithHwIntrinsicsFeature(RunAddGreenToBlueAndRedTest, HwIntrinsics.DisableAVX);
+
+ [Fact]
+ public void AddGreenToBlueAndRed_WithoutAvxOrSSSE3_Works() => FeatureTestRunner.RunWithHwIntrinsicsFeature(RunAddGreenToBlueAndRedTest, HwIntrinsics.DisableAVX | HwIntrinsics.DisableSSE2 | HwIntrinsics.DisableSSSE3);
+
+ [Fact]
+ public void TransformColor_WithHardwareIntrinsics_Works() => FeatureTestRunner.RunWithHwIntrinsicsFeature(RunTransformColorTest, HwIntrinsics.AllowAll);
+
+ [Fact]
+ public void TransformColor_WithoutSSE2_Works() => FeatureTestRunner.RunWithHwIntrinsicsFeature(RunTransformColorTest, HwIntrinsics.DisableSSE2);
+
+ [Fact]
+ public void TransformColorInverse_WithHardwareIntrinsics_Works() => FeatureTestRunner.RunWithHwIntrinsicsFeature(RunTransformColorInverseTest, HwIntrinsics.AllowAll);
+
+ [Fact]
+ public void TransformColorInverse_WithoutSSE2_Works() => FeatureTestRunner.RunWithHwIntrinsicsFeature(RunTransformColorInverseTest, HwIntrinsics.DisableSSE2);
+#endif
+ }
+}
diff --git a/tests/ImageSharp.Tests/Formats/WebP/LossyUtilsTests.cs b/tests/ImageSharp.Tests/Formats/WebP/LossyUtilsTests.cs
new file mode 100644
index 000000000..f8b488fde
--- /dev/null
+++ b/tests/ImageSharp.Tests/Formats/WebP/LossyUtilsTests.cs
@@ -0,0 +1,52 @@
+// Copyright (c) Six Labors.
+// Licensed under the Apache License, Version 2.0.
+
+using SixLabors.ImageSharp.Formats.Webp.Lossy;
+using SixLabors.ImageSharp.Tests.TestUtilities;
+using Xunit;
+
+namespace SixLabors.ImageSharp.Tests.Formats.WebP
+{
+ [Trait("Format", "Webp")]
+ public class LossyUtilsTests
+ {
+ private static void RunHadamardTransformTest()
+ {
+ byte[] a =
+ {
+ 27, 27, 28, 29, 29, 28, 27, 27, 27, 28, 28, 29, 29, 28, 28, 27, 129, 129, 129, 129, 129, 129, 129,
+ 129, 128, 128, 128, 128, 128, 128, 128, 128, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28, 28, 29, 29, 28,
+ 28, 27, 129, 129, 129, 129, 129, 129, 129, 129, 128, 128, 128, 128, 128, 128, 128, 128, 27, 27, 26,
+ 26, 26, 26, 27, 27, 27, 28, 28, 29, 29, 28, 28, 27, 129, 129, 129, 129, 129, 129, 129, 129, 128,
+ 128, 128, 128, 128, 128, 128, 128, 28, 27, 27, 26, 26, 27, 27, 28, 27, 28, 28, 29, 29, 28, 28, 27
+ };
+
+ byte[] b =
+ {
+ 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 204, 204, 204, 204, 204, 204, 204,
+ 204, 204, 204, 204, 204, 204, 204, 204, 204, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+ 28, 28, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 28, 28, 28,
+ 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 204, 204, 204, 204, 204, 204, 204, 204, 204,
+ 204, 204, 204, 204, 204, 204, 204, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28
+ };
+
+ ushort[] w = { 38, 32, 20, 9, 32, 28, 17, 7, 20, 17, 10, 4, 9, 7, 4, 2 };
+ int expected = 2;
+
+ int actual = LossyUtils.Vp8Disto4X4(a, b, w, new int[16]);
+ Assert.Equal(expected, actual);
+ }
+
+ [Fact]
+ public void HadamardTransform_Works() => RunHadamardTransformTest();
+
+#if SUPPORTS_RUNTIME_INTRINSICS
+ [Fact]
+ public void HadamardTransform_WithHardwareIntrinsics_Works() => FeatureTestRunner.RunWithHwIntrinsicsFeature(RunHadamardTransformTest, HwIntrinsics.AllowAll);
+
+ [Fact]
+ public void HadamardTransform_WithoutHardwareIntrinsics_Works() => FeatureTestRunner.RunWithHwIntrinsicsFeature(RunHadamardTransformTest, HwIntrinsics.DisableHWIntrinsic);
+#endif
+
+ }
+}
diff --git a/tests/ImageSharp.Tests/Formats/WebP/PredictorEncoderTests.cs b/tests/ImageSharp.Tests/Formats/WebP/PredictorEncoderTests.cs
new file mode 100644
index 000000000..d78f7e2f2
--- /dev/null
+++ b/tests/ImageSharp.Tests/Formats/WebP/PredictorEncoderTests.cs
@@ -0,0 +1,161 @@
+// Copyright (c) Six Labors.
+// Licensed under the Apache License, Version 2.0.
+
+using System;
+using System.IO;
+using SixLabors.ImageSharp.Formats.Webp;
+using SixLabors.ImageSharp.Formats.Webp.Lossless;
+using SixLabors.ImageSharp.PixelFormats;
+#if SUPPORTS_RUNTIME_INTRINSICS
+using SixLabors.ImageSharp.Tests.TestUtilities;
+#endif
+using Xunit;
+
+namespace SixLabors.ImageSharp.Tests.Formats.Webp
+{
+ [Trait("Format", "Webp")]
+ public class PredictorEncoderTests
+ {
+ [Fact]
+ public static void ColorSpaceTransform_WithBikeImage_ProducesExpectedData()
+ => RunColorSpaceTransformTestWithBikeImage();
+
+ [Fact]
+ public static void ColorSpaceTransform_WithPeakImage_ProducesExpectedData()
+ => RunColorSpaceTransformTestWithPeakImage();
+
+#if SUPPORTS_RUNTIME_INTRINSICS
+ [Fact]
+ public void ColorSpaceTransform_WithPeakImage_WithHardwareIntrinsics_Works()
+ => FeatureTestRunner.RunWithHwIntrinsicsFeature(ColorSpaceTransform_WithPeakImage_ProducesExpectedData, HwIntrinsics.AllowAll);
+
+ [Fact]
+ public void ColorSpaceTransform_WithPeakImage_WithoutSSE41_Works()
+ => FeatureTestRunner.RunWithHwIntrinsicsFeature(ColorSpaceTransform_WithPeakImage_ProducesExpectedData, HwIntrinsics.DisableSSE41);
+
+ [Fact]
+ public void ColorSpaceTransform_WithBikeImage_WithHardwareIntrinsics_Works()
+ => FeatureTestRunner.RunWithHwIntrinsicsFeature(ColorSpaceTransform_WithBikeImage_ProducesExpectedData, HwIntrinsics.AllowAll);
+
+ [Fact]
+ public void ColorSpaceTransform_WithBikeImage_WithoutSSE41_Works()
+ => FeatureTestRunner.RunWithHwIntrinsicsFeature(ColorSpaceTransform_WithBikeImage_ProducesExpectedData, HwIntrinsics.DisableSSE41);
+#endif
+
+ private static void RunColorSpaceTransformTestWithPeakImage()
+ {
+ // arrange
+ uint[] expectedData =
+ {
+ 4278191104, 4278191104, 4278191104, 4278191104, 4278191104, 4278191104, 4278191104, 4294577152,
+ 4294707200, 4294707200, 4294707200, 4294707200, 4294837248, 4294837248, 4293926912, 4294316544,
+ 4278191104, 4278191104, 4294837248, 4294837248, 4280287232, 4280350720, 4294447104, 4294707200,
+ 4294838272, 4278516736, 4294837248, 4294837248, 4278516736, 4294707200, 4279298048, 4294837248,
+ 4294837248, 4294837248, 4294837248, 4280287232, 4280287232, 4292670464, 4279633408, 4294838272,
+ 4294837248, 4278516736, 4278516736, 4278516736, 4278516736, 4278516736, 4278778880, 4278193152,
+ 4278191104, 4280287232, 4280287232, 4280287232, 4280287232, 4293971968, 4280612864, 4292802560,
+ 4294837760, 4278516736, 4278516736, 4294837760, 4294707712, 4278516736, 4294837248, 4278193152,
+ 4280287232, 4278984704, 4280287232, 4278243328, 4280287232, 4278244352, 4280287232, 4280025088,
+ 4280025088, 4294837760, 4278192128, 4294838784, 4294837760, 4294707712, 4278778880, 4278324224,
+ 4280287232, 4280287232, 4278202368, 4279115776, 4280287232, 4278243328, 4280287232, 4280287232,
+ 4280025088, 4280287232, 4278192128, 4294838272, 4294838272, 4294837760, 4278190592, 4278778880,
+ 4280875008, 4280287232, 4279896576, 4281075712, 4281075712, 4280287232, 4280287232, 4280287232,
+ 4280287232, 4280287232, 4278190592, 4294709248, 4278516736, 4278516736, 4278584832, 4278909440,
+ 4280287232, 4280287232, 4294367744, 4294621184, 4279115776, 4280287232, 4280287232, 4280351744,
+ 4280287232, 4280287232, 4280287232, 4278513664, 4278516736, 4278716416, 4278584832, 4280291328,
+ 4293062144, 4280287232, 4280287232, 4280287232, 4294456320, 4280291328, 4280287232, 4280287232,
+ 4280287232, 4280287232, 4280287232, 4280287232, 4278513152, 4278716416, 4278584832, 4280291328,
+ 4278198272, 4278198272, 4278589952, 4278198272, 4278198272, 4280287232, 4278765568, 4280287232,
+ 4280287232, 4280287232, 4280287232, 4294712832, 4278513152, 4278716640, 4279300608, 4278584832,
+ 4280156672, 4279373312, 4278589952, 4279373312, 4278328832, 4278328832, 4278328832, 4279634432,
+ 4280287232, 4280287232, 4280287232, 4280287232, 4278457344, 4280483328, 4278584832, 4278385664,
+ 4279634432, 4279373312, 4279634432, 4280287232, 4280287232, 4280156672, 4278589952, 4278328832,
+ 4278198272, 4280156672, 4280483328, 4294363648, 4280287232, 4278376448, 4280287232, 4278647808,
+ 4280287232, 4280287232, 4279373312, 4280287232, 4280287232, 4280156672, 4280287232, 4278198272,
+ 4278198272, 4280156672, 4280287232, 4280287232, 4293669888, 4278765568, 4278765568, 4280287232,
+ 4280287232, 4280287232, 4279634432, 4279634432, 4280287232, 4280287232, 4280287232, 4280287232,
+ 4280287232, 4280287232, 4280287232, 4280287232, 4279373312, 4279764992, 4293539328, 4279896576,
+ 4280287232, 4280287232, 4280287232, 4279634432, 4278198272, 4279634432, 4280287232, 4280287232,
+ 4280287232, 4280287232, 4280287232, 4280287232, 4280287232, 4279503872, 4279503872, 4280288256,
+ 4280287232, 4280287232, 4280287232, 4280287232, 4280287232, 4280287232, 4280287232, 4280287232,
+ 4280287232, 4280287232, 4280287232, 4280287232, 4280287232, 4280287232, 4280287232, 4280287232
+ };
+
+ // Convert image pixels to bgra array.
+ byte[] imgBytes = File.ReadAllBytes(TestImageFullPath(TestImages.Webp.Peak));
+ using var image = Image.Load(imgBytes);
+ uint[] bgra = ToBgra(image);
+
+ int colorTransformBits = 3;
+ int transformWidth = LosslessUtils.SubSampleSize(image.Width, colorTransformBits);
+ int transformHeight = LosslessUtils.SubSampleSize(image.Height, colorTransformBits);
+ uint[] transformData = new uint[transformWidth * transformHeight];
+ int[] scratch = new int[256];
+
+ // act
+ PredictorEncoder.ColorSpaceTransform(image.Width, image.Height, colorTransformBits, 75, bgra, transformData, scratch);
+
+ // assert
+ Assert.Equal(expectedData, transformData);
+ }
+
+ private static void RunColorSpaceTransformTestWithBikeImage()
+ {
+ // arrange
+ uint[] expectedData =
+ {
+ 4278714368, 4278192876, 4278198304, 4278198304, 4278190304, 4278190080, 4278190080, 4278198272,
+ 4278197760, 4278198816, 4278197794, 4278197774, 4278190080, 4278190080, 4278198816, 4278197281,
+ 4278197280, 4278197792, 4278200353, 4278191343, 4278190304, 4294713873, 4278198784, 4294844416,
+ 4278201578, 4278200044, 4278191343, 4278190288, 4294705200, 4294717139, 4278203628, 4278201064,
+ 4278201586, 4278197792, 4279240909
+ };
+
+ // Convert image pixels to bgra array.
+ byte[] imgBytes = File.ReadAllBytes(TestImageFullPath(TestImages.Webp.Lossy.BikeSmall));
+ using var image = Image.Load(imgBytes, new WebpDecoder());
+ uint[] bgra = ToBgra(image);
+
+ int colorTransformBits = 4;
+ int transformWidth = LosslessUtils.SubSampleSize(image.Width, colorTransformBits);
+ int transformHeight = LosslessUtils.SubSampleSize(image.Height, colorTransformBits);
+ uint[] transformData = new uint[transformWidth * transformHeight];
+ int[] scratch = new int[256];
+
+ // act
+ PredictorEncoder.ColorSpaceTransform(image.Width, image.Height, colorTransformBits, 75, bgra, transformData, scratch);
+
+ // assert
+ Assert.Equal(expectedData, transformData);
+ }
+
+ private static uint[] ToBgra(Image image)
+ where TPixel : unmanaged, IPixel
+ {
+ uint[] bgra = new uint[image.Width * image.Height];
+ int idx = 0;
+ for (int y = 0; y < image.Height; y++)
+ {
+ Span rowSpan = image.GetPixelRowSpan(y);
+ for (int x = 0; x < rowSpan.Length; x++)
+ {
+ bgra[idx++] = ToBgra32(rowSpan[x]).PackedValue;
+ }
+ }
+
+ return bgra;
+ }
+
+ private static Bgra32 ToBgra32(TPixel color)
+ where TPixel : unmanaged, IPixel
+ {
+ Rgba32 rgba = default;
+ color.ToRgba32(ref rgba);
+ var bgra = new Bgra32(rgba.R, rgba.G, rgba.B, rgba.A);
+ return bgra;
+ }
+
+ private static string TestImageFullPath(string path)
+ => Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, path);
+ }
+}
diff --git a/tests/ImageSharp.Tests/Formats/WebP/QuantEncTests.cs b/tests/ImageSharp.Tests/Formats/WebP/QuantEncTests.cs
new file mode 100644
index 000000000..55738199b
--- /dev/null
+++ b/tests/ImageSharp.Tests/Formats/WebP/QuantEncTests.cs
@@ -0,0 +1,53 @@
+// Copyright (c) Six Labors.
+// Licensed under the Apache License, Version 2.0.
+
+using System.Linq;
+using SixLabors.ImageSharp.Formats.Webp.Lossy;
+using SixLabors.ImageSharp.Tests.TestUtilities;
+using Xunit;
+
+namespace SixLabors.ImageSharp.Tests.Formats.WebP
+{
+ [Trait("Format", "Webp")]
+ public class QuantEncTests
+ {
+ private static unsafe void RunQuantizeBlockTest()
+ {
+ // arrange
+ short[] input = { 378, 777, -851, 888, 259, 148, 0, -111, -185, -185, -74, -37, 148, 74, 111, 74 };
+ short[] output = new short[16];
+ ushort[] q = { 42, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37 };
+ ushort[] iq = { 3120, 3542, 3542, 3542, 3542, 3542, 3542, 3542, 3542, 3542, 3542, 3542, 3542, 3542, 3542, 3542 };
+ uint[] bias = { 49152, 55296, 55296, 55296, 55296, 55296, 55296, 55296, 55296, 55296, 55296, 55296, 55296, 55296, 55296, 55296 };
+ uint[] zthresh = { 26, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21 };
+ short[] expectedOutput = { 9, 21, 7, -5, 4, -23, 24, 0, -5, 4, 2, -2, -3, -1, 3, 2 };
+ int expectedResult = 1;
+ Vp8Matrix vp8Matrix = default;
+ for (int i = 0; i < 16; i++)
+ {
+ vp8Matrix.Q[i] = q[i];
+ vp8Matrix.IQ[i] = iq[i];
+ vp8Matrix.Bias[i] = bias[i];
+ vp8Matrix.ZThresh[i] = zthresh[i];
+ }
+
+ // act
+ int actualResult = QuantEnc.QuantizeBlock(input, output, ref vp8Matrix);
+
+ // assert
+ Assert.True(output.SequenceEqual(expectedOutput));
+ Assert.Equal(expectedResult, actualResult);
+ }
+
+ [Fact]
+ public void QuantizeBlock_Works() => RunQuantizeBlockTest();
+
+#if SUPPORTS_RUNTIME_INTRINSICS
+ [Fact]
+ public void QuantizeBlock_WithHardwareIntrinsics_Works() => FeatureTestRunner.RunWithHwIntrinsicsFeature(RunQuantizeBlockTest, HwIntrinsics.AllowAll);
+
+ [Fact]
+ public void QuantizeBlock_WithoutHardwareIntrinsics_Works() => FeatureTestRunner.RunWithHwIntrinsicsFeature(RunQuantizeBlockTest, HwIntrinsics.DisableHWIntrinsic);
+#endif
+ }
+}
diff --git a/tests/ImageSharp.Tests/Formats/WebP/Vp8HistogramTests.cs b/tests/ImageSharp.Tests/Formats/WebP/Vp8HistogramTests.cs
new file mode 100644
index 000000000..4ff42f4ee
--- /dev/null
+++ b/tests/ImageSharp.Tests/Formats/WebP/Vp8HistogramTests.cs
@@ -0,0 +1,115 @@
+// Copyright (c) Six Labors.
+// Licensed under the Apache License, Version 2.0.
+
+using System.Collections.Generic;
+using SixLabors.ImageSharp.Formats.Webp.Lossy;
+using Xunit;
+
+namespace SixLabors.ImageSharp.Tests.Formats.Webp
+{
+ [Trait("Format", "Webp")]
+ public class Vp8HistogramTests
+ {
+ public static IEnumerable