diff --git a/.editorconfig b/.editorconfig index 2e3045fb17..c28089d720 100644 --- a/.editorconfig +++ b/.editorconfig @@ -172,6 +172,8 @@ dotnet_diagnostic.IDE0063.severity = suggestion csharp_using_directive_placement = outside_namespace:warning # Modifier preferences csharp_prefer_static_local_function = true:warning +# Primary constructor preferences +csharp_style_prefer_primary_constructors = false:none ########################################## # Unnecessary Code Rules diff --git a/.gitattributes b/.gitattributes index 3647a7063d..b5f742ab47 100644 --- a/.gitattributes +++ b/.gitattributes @@ -133,3 +133,6 @@ *.pnm filter=lfs diff=lfs merge=lfs -text *.wbmp filter=lfs diff=lfs merge=lfs -text *.exr filter=lfs diff=lfs merge=lfs -text +*.ico filter=lfs diff=lfs merge=lfs -text +*.cur filter=lfs diff=lfs merge=lfs -text +*.ani filter=lfs diff=lfs merge=lfs -text diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index e17b8d724e..a450aebf43 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -20,42 +20,23 @@ jobs: - ${{ contains(github.event.pull_request.labels.*.name, 'arch:arm32') || contains(github.event.pull_request.labels.*.name, 'arch:arm64') }} options: - os: ubuntu-latest - framework: net7.0 - sdk: 7.0.x - sdk-preview: true + framework: net8.0 + sdk: 8.0.x runtime: -x64 codecov: false - os: macos-13 # macos-latest runs on arm64 runners where libgdiplus is unavailable - framework: net7.0 - sdk: 7.0.x - sdk-preview: true + framework: net8.0 + sdk: 8.0.x runtime: -x64 codecov: false - os: windows-latest - framework: net7.0 - sdk: 7.0.x - sdk-preview: true + framework: net8.0 + sdk: 8.0.x runtime: -x64 codecov: false - os: buildjet-4vcpu-ubuntu-2204-arm - framework: net7.0 - sdk: 7.0.x - sdk-preview: true - runtime: -x64 - codecov: false - - os: ubuntu-latest - framework: net6.0 - sdk: 6.0.x - runtime: -x64 - codecov: false - - os: macos-13 # macos-latest runs on arm64 runners where libgdiplus is unavailable - framework: net6.0 - sdk: 6.0.x - runtime: -x64 - codecov: false - - os: windows-latest - framework: net6.0 - sdk: 6.0.x + framework: net8.0 + sdk: 8.0.x runtime: -x64 codecov: false exclude: @@ -87,7 +68,7 @@ jobs: run: git lfs ls-files -l | cut -d' ' -f1 | sort > .lfs-assets-id - name: Git Setup LFS Cache - uses: actions/cache@v3 + uses: actions/cache@v4 id: lfs-cache with: path: .git/lfs @@ -97,10 +78,10 @@ jobs: run: git lfs pull - name: NuGet Install - uses: NuGet/setup-nuget@v1 + uses: NuGet/setup-nuget@v2 - name: NuGet Setup Cache - uses: actions/cache@v3 + uses: actions/cache@v4 id: nuget-cache with: path: ~/.nuget @@ -109,17 +90,17 @@ jobs: - name: DotNet Setup if: ${{ matrix.options.sdk-preview != true }} - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@v4 with: dotnet-version: | - 6.0.x + 8.0.x - name: DotNet Setup Preview if: ${{ matrix.options.sdk-preview == true }} - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@v4 with: dotnet-version: | - 7.0.x + 8.0.x - name: DotNet Build if: ${{ matrix.options.sdk-preview != true }} @@ -152,7 +133,7 @@ jobs: XUNIT_PATH: .\tests\ImageSharp.Tests # Required for xunit - name: Export Failed Output - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: failure() with: name: actual_output_${{ runner.os }}_${{ matrix.options.framework }}${{ matrix.options.runtime }}.zip @@ -179,10 +160,10 @@ jobs: submodules: recursive - name: NuGet Install - uses: NuGet/setup-nuget@v1 + uses: NuGet/setup-nuget@v2 - name: NuGet Setup Cache - uses: actions/cache@v3 + uses: actions/cache@v4 id: nuget-cache with: path: ~/.nuget diff --git a/.github/workflows/code-coverage.yml b/.github/workflows/code-coverage.yml index e551afbd6d..cd22fe5e58 100644 --- a/.github/workflows/code-coverage.yml +++ b/.github/workflows/code-coverage.yml @@ -10,7 +10,7 @@ jobs: matrix: options: - os: ubuntu-latest - framework: net6.0 + framework: net8.0 runtime: -x64 codecov: true @@ -34,7 +34,7 @@ jobs: run: git lfs ls-files -l | cut -d' ' -f1 | sort > .lfs-assets-id - name: Git Setup LFS Cache - uses: actions/cache@v3 + uses: actions/cache@v4 id: lfs-cache with: path: .git/lfs @@ -44,10 +44,10 @@ jobs: run: git lfs pull - name: NuGet Install - uses: NuGet/setup-nuget@v1 + uses: NuGet/setup-nuget@v2 - name: NuGet Setup Cache - uses: actions/cache@v3 + uses: actions/cache@v4 id: nuget-cache with: path: ~/.nuget @@ -55,10 +55,10 @@ jobs: restore-keys: ${{ runner.os }}-nuget- - name: DotNet Setup - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@v4 with: dotnet-version: | - 6.0.x + 8.0.x - name: DotNet Build shell: pwsh @@ -74,14 +74,14 @@ jobs: XUNIT_PATH: .\tests\ImageSharp.Tests # Required for xunit - name: Export Failed Output - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: failure() with: name: actual_output_${{ runner.os }}_${{ matrix.options.framework }}${{ matrix.options.runtime }}.zip path: tests/Images/ActualOutput/ - name: Codecov Update - uses: codecov/codecov-action@v3 + uses: codecov/codecov-action@v4 if: matrix.options.codecov == true && startsWith(github.repository, 'SixLabors') with: flags: unittests diff --git a/ImageSharp.sln b/ImageSharp.sln index 2967acb8ff..7ccd92c07d 100644 --- a/ImageSharp.sln +++ b/ImageSharp.sln @@ -38,6 +38,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{815C0625-CD3 src\Directory.Build.props = src\Directory.Build.props src\Directory.Build.targets = src\Directory.Build.targets src\README.md = src\README.md + src\ImageSharp.ruleset = src\ImageSharp.ruleset EndProjectSection EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ImageSharp", "src\ImageSharp\ImageSharp.csproj", "{2AA31A1F-142C-43F4-8687-09ABCA4B3A26}" @@ -237,6 +238,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "issues", "issues", "{5C9B68 tests\Images\Input\Jpg\issues\issue750-exif-tranform.jpg = tests\Images\Input\Jpg\issues\issue750-exif-tranform.jpg tests\Images\Input\Jpg\issues\Issue845-Incorrect-Quality99.jpg = tests\Images\Input\Jpg\issues\Issue845-Incorrect-Quality99.jpg tests\Images\Input\Jpg\issues\issue855-incorrect-colorspace.jpg = tests\Images\Input\Jpg\issues\issue855-incorrect-colorspace.jpg + tests\Images\Input\Jpg\issues\issue-2067-comment.jpg = tests\Images\Input\Jpg\issues\issue-2067-comment.jpg EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "fuzz", "fuzz", "{516A3532-6AC2-417B-AD79-9BD5D0D378A0}" @@ -659,6 +661,12 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Qoi", "Qoi", "{E801B508-493 tests\Images\Input\Qoi\wikipedia_008.qoi = tests\Images\Input\Qoi\wikipedia_008.qoi EndProjectSection EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Icon", "Icon", "{95E45DDE-A67D-48AD-BBA8-5FAA151B860D}" + ProjectSection(SolutionItems) = preProject + tests\Images\Input\Icon\aero_arrow.cur = tests\Images\Input\Icon\aero_arrow.cur + tests\Images\Input\Icon\flutter.ico = tests\Images\Input\Icon\flutter.ico + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -712,6 +720,7 @@ Global {670DD46C-82E9-499A-B2D2-00A802ED0141} = {E1C42A6F-913B-4A7B-B1A8-2BB62843B254} {5DFC394F-136F-4B76-9BCA-3BA786515EFC} = {9DA226A1-8656-49A8-A58A-A8B5C081AD66} {E801B508-4935-41CD-BA85-CF11BFF55A45} = {9DA226A1-8656-49A8-A58A-A8B5C081AD66} + {95E45DDE-A67D-48AD-BBA8-5FAA151B860D} = {9DA226A1-8656-49A8-A58A-A8B5C081AD66} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {5F8B9D1F-CD8B-4CC5-8216-D531E25BD795} diff --git a/README.md b/README.md index fa51d57cdf..cf58b6b14b 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ Designed to simplify image processing, ImageSharp brings you an incredibly power ImageSharp is designed from the ground up to be flexible and extensible. The library provides API endpoints for common image processing operations and the building blocks to allow for the development of additional operations. -Built against [.NET 6](https://docs.microsoft.com/en-us/dotnet/standard/net-standard), ImageSharp can be used in device, cloud, and embedded/IoT scenarios. +Built against [.NET 8](https://docs.microsoft.com/en-us/dotnet/standard/net-standard), ImageSharp can be used in device, cloud, and embedded/IoT scenarios. ## License @@ -64,7 +64,7 @@ If you prefer, you can compile ImageSharp yourself (please do and help!) - Using [Visual Studio 2022](https://visualstudio.microsoft.com/vs/) - Make sure you have the latest version installed - - Make sure you have [the .NET 7 SDK](https://www.microsoft.com/net/core#windows) installed + - Make sure you have [the .NET 8 SDK](https://www.microsoft.com/net/core#windows) installed Alternatively, you can work from command line and/or with a lightweight editor on **both Linux/Unix and Windows**: diff --git a/shared-infrastructure b/shared-infrastructure index 353b9afe32..1dbfb576c8 160000 --- a/shared-infrastructure +++ b/shared-infrastructure @@ -1 +1 @@ -Subproject commit 353b9afe32a8000410312d17263407cd7bb82d19 +Subproject commit 1dbfb576c83507645265c79e03369b66cdc0379f diff --git a/src/ImageSharp.ruleset b/src/ImageSharp.ruleset index e88c43f838..b609890200 100644 --- a/src/ImageSharp.ruleset +++ b/src/ImageSharp.ruleset @@ -1,7 +1,4 @@  - - - \ No newline at end of file diff --git a/src/ImageSharp/Advanced/ParallelRowIterator.Wrappers.cs b/src/ImageSharp/Advanced/ParallelRowIterator.Wrappers.cs index 9629b0097e..a959faa3b6 100644 --- a/src/ImageSharp/Advanced/ParallelRowIterator.Wrappers.cs +++ b/src/ImageSharp/Advanced/ParallelRowIterator.Wrappers.cs @@ -51,7 +51,7 @@ public void Invoke(int i) for (int y = yMin; y < yMax; y++) { // Skip the safety copy when invoking a potentially impure method on a readonly field - Unsafe.AsRef(this.action).Invoke(y); + Unsafe.AsRef(in this.action).Invoke(y); } } } @@ -102,7 +102,7 @@ public void Invoke(int i) for (int y = yMin; y < yMax; y++) { - Unsafe.AsRef(this.action).Invoke(y, span); + Unsafe.AsRef(in this.action).Invoke(y, span); } } } diff --git a/src/ImageSharp/Advanced/ParallelRowIterator.cs b/src/ImageSharp/Advanced/ParallelRowIterator.cs index 657654a84b..1284a3a898 100644 --- a/src/ImageSharp/Advanced/ParallelRowIterator.cs +++ b/src/ImageSharp/Advanced/ParallelRowIterator.cs @@ -58,7 +58,7 @@ public static void IterateRows( { for (int y = top; y < bottom; y++) { - Unsafe.AsRef(operation).Invoke(y); + Unsafe.AsRef(in operation).Invoke(y); } return; @@ -118,7 +118,7 @@ public static void IterateRows( int maxSteps = DivideCeil(width * (long)height, parallelSettings.MinimumPixelsProcessedPerTask); int numOfSteps = Math.Min(parallelSettings.MaxDegreeOfParallelism, maxSteps); MemoryAllocator allocator = parallelSettings.MemoryAllocator; - int bufferLength = Unsafe.AsRef(operation).GetRequiredBufferLength(rectangle); + int bufferLength = Unsafe.AsRef(in operation).GetRequiredBufferLength(rectangle); // Avoid TPL overhead in this trivial case: if (numOfSteps == 1) @@ -128,7 +128,7 @@ public static void IterateRows( for (int y = top; y < bottom; y++) { - Unsafe.AsRef(operation).Invoke(y, span); + Unsafe.AsRef(in operation).Invoke(y, span); } return; @@ -245,7 +245,7 @@ public static void IterateRowIntervals( int maxSteps = DivideCeil(width * (long)height, parallelSettings.MinimumPixelsProcessedPerTask); int numOfSteps = Math.Min(parallelSettings.MaxDegreeOfParallelism, maxSteps); MemoryAllocator allocator = parallelSettings.MemoryAllocator; - int bufferLength = Unsafe.AsRef(operation).GetRequiredBufferLength(rectangle); + int bufferLength = Unsafe.AsRef(in operation).GetRequiredBufferLength(rectangle); // Avoid TPL overhead in this trivial case: if (numOfSteps == 1) @@ -253,7 +253,7 @@ public static void IterateRowIntervals( var rows = new RowInterval(top, bottom); using IMemoryOwner buffer = allocator.Allocate(bufferLength); - Unsafe.AsRef(operation).Invoke(in rows, buffer.Memory.Span); + Unsafe.AsRef(in operation).Invoke(in rows, buffer.Memory.Span); return; } diff --git a/src/ImageSharp/Color/Color.Conversions.cs b/src/ImageSharp/Color/Color.Conversions.cs deleted file mode 100644 index 309ab83ec4..0000000000 --- a/src/ImageSharp/Color/Color.Conversions.cs +++ /dev/null @@ -1,240 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Numerics; -using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.PixelFormats; - -namespace SixLabors.ImageSharp; - -/// -/// Contains constructors and implicit conversion methods. -/// -public readonly partial struct Color -{ - /// - /// Initializes a new instance of the struct. - /// - /// The containing the color information. - [MethodImpl(InliningOptions.ShortMethod)] - public Color(Rgba64 pixel) - { - this.data = pixel; - this.boxedHighPrecisionPixel = null; - } - - /// - /// Initializes a new instance of the struct. - /// - /// The containing the color information. - [MethodImpl(InliningOptions.ShortMethod)] - public Color(Rgb48 pixel) - { - this.data = new Rgba64(pixel.R, pixel.G, pixel.B, ushort.MaxValue); - this.boxedHighPrecisionPixel = null; - } - - /// - /// Initializes a new instance of the struct. - /// - /// The containing the color information. - [MethodImpl(InliningOptions.ShortMethod)] - public Color(La32 pixel) - { - this.data = new Rgba64(pixel.L, pixel.L, pixel.L, pixel.A); - this.boxedHighPrecisionPixel = null; - } - - /// - /// Initializes a new instance of the struct. - /// - /// The containing the color information. - [MethodImpl(InliningOptions.ShortMethod)] - public Color(L16 pixel) - { - this.data = new Rgba64(pixel.PackedValue, pixel.PackedValue, pixel.PackedValue, ushort.MaxValue); - this.boxedHighPrecisionPixel = null; - } - - /// - /// Initializes a new instance of the struct. - /// - /// The containing the color information. - [MethodImpl(InliningOptions.ShortMethod)] - public Color(Rgba32 pixel) - { - this.data = new Rgba64(pixel); - this.boxedHighPrecisionPixel = null; - } - - /// - /// Initializes a new instance of the struct. - /// - /// The containing the color information. - [MethodImpl(InliningOptions.ShortMethod)] - public Color(Argb32 pixel) - { - this.data = new Rgba64(pixel); - this.boxedHighPrecisionPixel = null; - } - - /// - /// Initializes a new instance of the struct. - /// - /// The containing the color information. - [MethodImpl(InliningOptions.ShortMethod)] - public Color(Bgra32 pixel) - { - this.data = new Rgba64(pixel); - this.boxedHighPrecisionPixel = null; - } - - /// - /// Initializes a new instance of the struct. - /// - /// The containing the color information. - [MethodImpl(InliningOptions.ShortMethod)] - public Color(Abgr32 pixel) - { - this.data = new Rgba64(pixel); - this.boxedHighPrecisionPixel = null; - } - - /// - /// Initializes a new instance of the struct. - /// - /// The containing the color information. - [MethodImpl(InliningOptions.ShortMethod)] - public Color(Rgb24 pixel) - { - this.data = new Rgba64(pixel); - this.boxedHighPrecisionPixel = null; - } - - /// - /// Initializes a new instance of the struct. - /// - /// The containing the color information. - [MethodImpl(InliningOptions.ShortMethod)] - public Color(Bgr24 pixel) - { - this.data = new Rgba64(pixel); - this.boxedHighPrecisionPixel = null; - } - - /// - /// Initializes a new instance of the struct. - /// - /// The containing the color information. - [MethodImpl(InliningOptions.ShortMethod)] - public Color(Vector4 vector) - { - vector = Numerics.Clamp(vector, Vector4.Zero, Vector4.One); - this.boxedHighPrecisionPixel = new RgbaVector(vector.X, vector.Y, vector.Z, vector.W); - this.data = default; - } - - /// - /// Converts a to . - /// - /// The . - /// The . - public static explicit operator Vector4(Color color) => color.ToScaledVector4(); - - /// - /// Converts an to . - /// - /// The . - /// The . - [MethodImpl(InliningOptions.ShortMethod)] - public static explicit operator Color(Vector4 source) => new(source); - - [MethodImpl(InliningOptions.ShortMethod)] - internal Rgba32 ToRgba32() - { - if (this.boxedHighPrecisionPixel is null) - { - return this.data.ToRgba32(); - } - - Rgba32 value = default; - this.boxedHighPrecisionPixel.ToRgba32(ref value); - return value; - } - - [MethodImpl(InliningOptions.ShortMethod)] - internal Bgra32 ToBgra32() - { - if (this.boxedHighPrecisionPixel is null) - { - return this.data.ToBgra32(); - } - - Bgra32 value = default; - value.FromScaledVector4(this.boxedHighPrecisionPixel.ToScaledVector4()); - return value; - } - - [MethodImpl(InliningOptions.ShortMethod)] - internal Argb32 ToArgb32() - { - if (this.boxedHighPrecisionPixel is null) - { - return this.data.ToArgb32(); - } - - Argb32 value = default; - value.FromScaledVector4(this.boxedHighPrecisionPixel.ToScaledVector4()); - return value; - } - - [MethodImpl(InliningOptions.ShortMethod)] - internal Abgr32 ToAbgr32() - { - if (this.boxedHighPrecisionPixel is null) - { - return this.data.ToAbgr32(); - } - - Abgr32 value = default; - value.FromScaledVector4(this.boxedHighPrecisionPixel.ToScaledVector4()); - return value; - } - - [MethodImpl(InliningOptions.ShortMethod)] - internal Rgb24 ToRgb24() - { - if (this.boxedHighPrecisionPixel is null) - { - return this.data.ToRgb24(); - } - - Rgb24 value = default; - value.FromScaledVector4(this.boxedHighPrecisionPixel.ToScaledVector4()); - return value; - } - - [MethodImpl(InliningOptions.ShortMethod)] - internal Bgr24 ToBgr24() - { - if (this.boxedHighPrecisionPixel is null) - { - return this.data.ToBgr24(); - } - - Bgr24 value = default; - value.FromScaledVector4(this.boxedHighPrecisionPixel.ToScaledVector4()); - return value; - } - - [MethodImpl(InliningOptions.ShortMethod)] - internal Vector4 ToScaledVector4() - { - if (this.boxedHighPrecisionPixel is null) - { - return this.data.ToScaledVector4(); - } - - return this.boxedHighPrecisionPixel.ToScaledVector4(); - } -} diff --git a/src/ImageSharp/Color/Color.NamedColors.cs b/src/ImageSharp/Color/Color.NamedColors.cs index f8b4c90fd6..00130dd904 100644 --- a/src/ImageSharp/Color/Color.NamedColors.cs +++ b/src/ImageSharp/Color/Color.NamedColors.cs @@ -1,6 +1,8 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. +using SixLabors.ImageSharp.PixelFormats; + namespace SixLabors.ImageSharp; /// @@ -9,107 +11,107 @@ namespace SixLabors.ImageSharp; /// public readonly partial struct Color { - private static readonly Lazy> NamedColorsLookupLazy = new Lazy>(CreateNamedColorsLookup, true); + private static readonly Lazy> NamedColorsLookupLazy = new(CreateNamedColorsLookup, true); /// /// Represents a matching the W3C definition that has an hex value of #F0F8FF. /// - public static readonly Color AliceBlue = FromRgba(240, 248, 255, 255); + public static readonly Color AliceBlue = FromPixel(new Rgba32(240, 248, 255, 255)); /// /// Represents a matching the W3C definition that has an hex value of #FAEBD7. /// - public static readonly Color AntiqueWhite = FromRgba(250, 235, 215, 255); + public static readonly Color AntiqueWhite = FromPixel(new Rgba32(250, 235, 215, 255)); /// /// Represents a matching the W3C definition that has an hex value of #00FFFF. /// - public static readonly Color Aqua = FromRgba(0, 255, 255, 255); + public static readonly Color Aqua = FromPixel(new Rgba32(0, 255, 255, 255)); /// /// Represents a matching the W3C definition that has an hex value of #7FFFD4. /// - public static readonly Color Aquamarine = FromRgba(127, 255, 212, 255); + public static readonly Color Aquamarine = FromPixel(new Rgba32(127, 255, 212, 255)); /// /// Represents a matching the W3C definition that has an hex value of #F0FFFF. /// - public static readonly Color Azure = FromRgba(240, 255, 255, 255); + public static readonly Color Azure = FromPixel(new Rgba32(240, 255, 255, 255)); /// /// Represents a matching the W3C definition that has an hex value of #F5F5DC. /// - public static readonly Color Beige = FromRgba(245, 245, 220, 255); + public static readonly Color Beige = FromPixel(new Rgba32(245, 245, 220, 255)); /// /// Represents a matching the W3C definition that has an hex value of #FFE4C4. /// - public static readonly Color Bisque = FromRgba(255, 228, 196, 255); + public static readonly Color Bisque = FromPixel(new Rgba32(255, 228, 196, 255)); /// /// Represents a matching the W3C definition that has an hex value of #000000. /// - public static readonly Color Black = FromRgba(0, 0, 0, 255); + public static readonly Color Black = FromPixel(new Rgba32(0, 0, 0, 255)); /// /// Represents a matching the W3C definition that has an hex value of #FFEBCD. /// - public static readonly Color BlanchedAlmond = FromRgba(255, 235, 205, 255); + public static readonly Color BlanchedAlmond = FromPixel(new Rgba32(255, 235, 205, 255)); /// /// Represents a matching the W3C definition that has an hex value of #0000FF. /// - public static readonly Color Blue = FromRgba(0, 0, 255, 255); + public static readonly Color Blue = FromPixel(new Rgba32(0, 0, 255, 255)); /// /// Represents a matching the W3C definition that has an hex value of #8A2BE2. /// - public static readonly Color BlueViolet = FromRgba(138, 43, 226, 255); + public static readonly Color BlueViolet = FromPixel(new Rgba32(138, 43, 226, 255)); /// /// Represents a matching the W3C definition that has an hex value of #A52A2A. /// - public static readonly Color Brown = FromRgba(165, 42, 42, 255); + public static readonly Color Brown = FromPixel(new Rgba32(165, 42, 42, 255)); /// /// Represents a matching the W3C definition that has an hex value of #DEB887. /// - public static readonly Color BurlyWood = FromRgba(222, 184, 135, 255); + public static readonly Color BurlyWood = FromPixel(new Rgba32(222, 184, 135, 255)); /// /// Represents a matching the W3C definition that has an hex value of #5F9EA0. /// - public static readonly Color CadetBlue = FromRgba(95, 158, 160, 255); + public static readonly Color CadetBlue = FromPixel(new Rgba32(95, 158, 160, 255)); /// /// Represents a matching the W3C definition that has an hex value of #7FFF00. /// - public static readonly Color Chartreuse = FromRgba(127, 255, 0, 255); + public static readonly Color Chartreuse = FromPixel(new Rgba32(127, 255, 0, 255)); /// /// Represents a matching the W3C definition that has an hex value of #D2691E. /// - public static readonly Color Chocolate = FromRgba(210, 105, 30, 255); + public static readonly Color Chocolate = FromPixel(new Rgba32(210, 105, 30, 255)); /// /// Represents a matching the W3C definition that has an hex value of #FF7F50. /// - public static readonly Color Coral = FromRgba(255, 127, 80, 255); + public static readonly Color Coral = FromPixel(new Rgba32(255, 127, 80, 255)); /// /// Represents a matching the W3C definition that has an hex value of #6495ED. /// - public static readonly Color CornflowerBlue = FromRgba(100, 149, 237, 255); + public static readonly Color CornflowerBlue = FromPixel(new Rgba32(100, 149, 237, 255)); /// /// Represents a matching the W3C definition that has an hex value of #FFF8DC. /// - public static readonly Color Cornsilk = FromRgba(255, 248, 220, 255); + public static readonly Color Cornsilk = FromPixel(new Rgba32(255, 248, 220, 255)); /// /// Represents a matching the W3C definition that has an hex value of #DC143C. /// - public static readonly Color Crimson = FromRgba(220, 20, 60, 255); + public static readonly Color Crimson = FromPixel(new Rgba32(220, 20, 60, 255)); /// /// Represents a matching the W3C definition that has an hex value of #00FFFF. @@ -119,27 +121,27 @@ public readonly partial struct Color /// /// Represents a matching the W3C definition that has an hex value of #00008B. /// - public static readonly Color DarkBlue = FromRgba(0, 0, 139, 255); + public static readonly Color DarkBlue = FromPixel(new Rgba32(0, 0, 139, 255)); /// /// Represents a matching the W3C definition that has an hex value of #008B8B. /// - public static readonly Color DarkCyan = FromRgba(0, 139, 139, 255); + public static readonly Color DarkCyan = FromPixel(new Rgba32(0, 139, 139, 255)); /// /// Represents a matching the W3C definition that has an hex value of #B8860B. /// - public static readonly Color DarkGoldenrod = FromRgba(184, 134, 11, 255); + public static readonly Color DarkGoldenrod = FromPixel(new Rgba32(184, 134, 11, 255)); /// /// Represents a matching the W3C definition that has an hex value of #A9A9A9. /// - public static readonly Color DarkGray = FromRgba(169, 169, 169, 255); + public static readonly Color DarkGray = FromPixel(new Rgba32(169, 169, 169, 255)); /// /// Represents a matching the W3C definition that has an hex value of #006400. /// - public static readonly Color DarkGreen = FromRgba(0, 100, 0, 255); + public static readonly Color DarkGreen = FromPixel(new Rgba32(0, 100, 0, 255)); /// /// Represents a matching the W3C definition that has an hex value of #A9A9A9. @@ -149,52 +151,52 @@ public readonly partial struct Color /// /// Represents a matching the W3C definition that has an hex value of #BDB76B. /// - public static readonly Color DarkKhaki = FromRgba(189, 183, 107, 255); + public static readonly Color DarkKhaki = FromPixel(new Rgba32(189, 183, 107, 255)); /// /// Represents a matching the W3C definition that has an hex value of #8B008B. /// - public static readonly Color DarkMagenta = FromRgba(139, 0, 139, 255); + public static readonly Color DarkMagenta = FromPixel(new Rgba32(139, 0, 139, 255)); /// /// Represents a matching the W3C definition that has an hex value of #556B2F. /// - public static readonly Color DarkOliveGreen = FromRgba(85, 107, 47, 255); + public static readonly Color DarkOliveGreen = FromPixel(new Rgba32(85, 107, 47, 255)); /// /// Represents a matching the W3C definition that has an hex value of #FF8C00. /// - public static readonly Color DarkOrange = FromRgba(255, 140, 0, 255); + public static readonly Color DarkOrange = FromPixel(new Rgba32(255, 140, 0, 255)); /// /// Represents a matching the W3C definition that has an hex value of #9932CC. /// - public static readonly Color DarkOrchid = FromRgba(153, 50, 204, 255); + public static readonly Color DarkOrchid = FromPixel(new Rgba32(153, 50, 204, 255)); /// /// Represents a matching the W3C definition that has an hex value of #8B0000. /// - public static readonly Color DarkRed = FromRgba(139, 0, 0, 255); + public static readonly Color DarkRed = FromPixel(new Rgba32(139, 0, 0, 255)); /// /// Represents a matching the W3C definition that has an hex value of #E9967A. /// - public static readonly Color DarkSalmon = FromRgba(233, 150, 122, 255); + public static readonly Color DarkSalmon = FromPixel(new Rgba32(233, 150, 122, 255)); /// /// Represents a matching the W3C definition that has an hex value of #8FBC8F. /// - public static readonly Color DarkSeaGreen = FromRgba(143, 188, 143, 255); + public static readonly Color DarkSeaGreen = FromPixel(new Rgba32(143, 188, 143, 255)); /// /// Represents a matching the W3C definition that has an hex value of #483D8B. /// - public static readonly Color DarkSlateBlue = FromRgba(72, 61, 139, 255); + public static readonly Color DarkSlateBlue = FromPixel(new Rgba32(72, 61, 139, 255)); /// /// Represents a matching the W3C definition that has an hex value of #2F4F4F. /// - public static readonly Color DarkSlateGray = FromRgba(47, 79, 79, 255); + public static readonly Color DarkSlateGray = FromPixel(new Rgba32(47, 79, 79, 255)); /// /// Represents a matching the W3C definition that has an hex value of #2F4F4F. @@ -204,27 +206,27 @@ public readonly partial struct Color /// /// Represents a matching the W3C definition that has an hex value of #00CED1. /// - public static readonly Color DarkTurquoise = FromRgba(0, 206, 209, 255); + public static readonly Color DarkTurquoise = FromPixel(new Rgba32(0, 206, 209, 255)); /// /// Represents a matching the W3C definition that has an hex value of #9400D3. /// - public static readonly Color DarkViolet = FromRgba(148, 0, 211, 255); + public static readonly Color DarkViolet = FromPixel(new Rgba32(148, 0, 211, 255)); /// /// Represents a matching the W3C definition that has an hex value of #FF1493. /// - public static readonly Color DeepPink = FromRgba(255, 20, 147, 255); + public static readonly Color DeepPink = FromPixel(new Rgba32(255, 20, 147, 255)); /// /// Represents a matching the W3C definition that has an hex value of #00BFFF. /// - public static readonly Color DeepSkyBlue = FromRgba(0, 191, 255, 255); + public static readonly Color DeepSkyBlue = FromPixel(new Rgba32(0, 191, 255, 255)); /// /// Represents a matching the W3C definition that has an hex value of #696969. /// - public static readonly Color DimGray = FromRgba(105, 105, 105, 255); + public static readonly Color DimGray = FromPixel(new Rgba32(105, 105, 105, 255)); /// /// Represents a matching the W3C definition that has an hex value of #696969. @@ -234,62 +236,62 @@ public readonly partial struct Color /// /// Represents a matching the W3C definition that has an hex value of #1E90FF. /// - public static readonly Color DodgerBlue = FromRgba(30, 144, 255, 255); + public static readonly Color DodgerBlue = FromPixel(new Rgba32(30, 144, 255, 255)); /// /// Represents a matching the W3C definition that has an hex value of #B22222. /// - public static readonly Color Firebrick = FromRgba(178, 34, 34, 255); + public static readonly Color Firebrick = FromPixel(new Rgba32(178, 34, 34, 255)); /// /// Represents a matching the W3C definition that has an hex value of #FFFAF0. /// - public static readonly Color FloralWhite = FromRgba(255, 250, 240, 255); + public static readonly Color FloralWhite = FromPixel(new Rgba32(255, 250, 240, 255)); /// /// Represents a matching the W3C definition that has an hex value of #228B22. /// - public static readonly Color ForestGreen = FromRgba(34, 139, 34, 255); + public static readonly Color ForestGreen = FromPixel(new Rgba32(34, 139, 34, 255)); /// /// Represents a matching the W3C definition that has an hex value of #FF00FF. /// - public static readonly Color Fuchsia = FromRgba(255, 0, 255, 255); + public static readonly Color Fuchsia = FromPixel(new Rgba32(255, 0, 255, 255)); /// /// Represents a matching the W3C definition that has an hex value of #DCDCDC. /// - public static readonly Color Gainsboro = FromRgba(220, 220, 220, 255); + public static readonly Color Gainsboro = FromPixel(new Rgba32(220, 220, 220, 255)); /// /// Represents a matching the W3C definition that has an hex value of #F8F8FF. /// - public static readonly Color GhostWhite = FromRgba(248, 248, 255, 255); + public static readonly Color GhostWhite = FromPixel(new Rgba32(248, 248, 255, 255)); /// /// Represents a matching the W3C definition that has an hex value of #FFD700. /// - public static readonly Color Gold = FromRgba(255, 215, 0, 255); + public static readonly Color Gold = FromPixel(new Rgba32(255, 215, 0, 255)); /// /// Represents a matching the W3C definition that has an hex value of #DAA520. /// - public static readonly Color Goldenrod = FromRgba(218, 165, 32, 255); + public static readonly Color Goldenrod = FromPixel(new Rgba32(218, 165, 32, 255)); /// /// Represents a matching the W3C definition that has an hex value of #808080. /// - public static readonly Color Gray = FromRgba(128, 128, 128, 255); + public static readonly Color Gray = FromPixel(new Rgba32(128, 128, 128, 255)); /// /// Represents a matching the W3C definition that has an hex value of #008000. /// - public static readonly Color Green = FromRgba(0, 128, 0, 255); + public static readonly Color Green = FromPixel(new Rgba32(0, 128, 0, 255)); /// /// Represents a matching the W3C definition that has an hex value of #ADFF2F. /// - public static readonly Color GreenYellow = FromRgba(173, 255, 47, 255); + public static readonly Color GreenYellow = FromPixel(new Rgba32(173, 255, 47, 255)); /// /// Represents a matching the W3C definition that has an hex value of #808080. @@ -299,82 +301,82 @@ public readonly partial struct Color /// /// Represents a matching the W3C definition that has an hex value of #F0FFF0. /// - public static readonly Color Honeydew = FromRgba(240, 255, 240, 255); + public static readonly Color Honeydew = FromPixel(new Rgba32(240, 255, 240, 255)); /// /// Represents a matching the W3C definition that has an hex value of #FF69B4. /// - public static readonly Color HotPink = FromRgba(255, 105, 180, 255); + public static readonly Color HotPink = FromPixel(new Rgba32(255, 105, 180, 255)); /// /// Represents a matching the W3C definition that has an hex value of #CD5C5C. /// - public static readonly Color IndianRed = FromRgba(205, 92, 92, 255); + public static readonly Color IndianRed = FromPixel(new Rgba32(205, 92, 92, 255)); /// /// Represents a matching the W3C definition that has an hex value of #4B0082. /// - public static readonly Color Indigo = FromRgba(75, 0, 130, 255); + public static readonly Color Indigo = FromPixel(new Rgba32(75, 0, 130, 255)); /// /// Represents a matching the W3C definition that has an hex value of #FFFFF0. /// - public static readonly Color Ivory = FromRgba(255, 255, 240, 255); + public static readonly Color Ivory = FromPixel(new Rgba32(255, 255, 240, 255)); /// /// Represents a matching the W3C definition that has an hex value of #F0E68C. /// - public static readonly Color Khaki = FromRgba(240, 230, 140, 255); + public static readonly Color Khaki = FromPixel(new Rgba32(240, 230, 140, 255)); /// /// Represents a matching the W3C definition that has an hex value of #E6E6FA. /// - public static readonly Color Lavender = FromRgba(230, 230, 250, 255); + public static readonly Color Lavender = FromPixel(new Rgba32(230, 230, 250, 255)); /// /// Represents a matching the W3C definition that has an hex value of #FFF0F5. /// - public static readonly Color LavenderBlush = FromRgba(255, 240, 245, 255); + public static readonly Color LavenderBlush = FromPixel(new Rgba32(255, 240, 245, 255)); /// /// Represents a matching the W3C definition that has an hex value of #7CFC00. /// - public static readonly Color LawnGreen = FromRgba(124, 252, 0, 255); + public static readonly Color LawnGreen = FromPixel(new Rgba32(124, 252, 0, 255)); /// /// Represents a matching the W3C definition that has an hex value of #FFFACD. /// - public static readonly Color LemonChiffon = FromRgba(255, 250, 205, 255); + public static readonly Color LemonChiffon = FromPixel(new Rgba32(255, 250, 205, 255)); /// /// Represents a matching the W3C definition that has an hex value of #ADD8E6. /// - public static readonly Color LightBlue = FromRgba(173, 216, 230, 255); + public static readonly Color LightBlue = FromPixel(new Rgba32(173, 216, 230, 255)); /// /// Represents a matching the W3C definition that has an hex value of #F08080. /// - public static readonly Color LightCoral = FromRgba(240, 128, 128, 255); + public static readonly Color LightCoral = FromPixel(new Rgba32(240, 128, 128, 255)); /// /// Represents a matching the W3C definition that has an hex value of #E0FFFF. /// - public static readonly Color LightCyan = FromRgba(224, 255, 255, 255); + public static readonly Color LightCyan = FromPixel(new Rgba32(224, 255, 255, 255)); /// /// Represents a matching the W3C definition that has an hex value of #FAFAD2. /// - public static readonly Color LightGoldenrodYellow = FromRgba(250, 250, 210, 255); + public static readonly Color LightGoldenrodYellow = FromPixel(new Rgba32(250, 250, 210, 255)); /// /// Represents a matching the W3C definition that has an hex value of #D3D3D3. /// - public static readonly Color LightGray = FromRgba(211, 211, 211, 255); + public static readonly Color LightGray = FromPixel(new Rgba32(211, 211, 211, 255)); /// /// Represents a matching the W3C definition that has an hex value of #90EE90. /// - public static readonly Color LightGreen = FromRgba(144, 238, 144, 255); + public static readonly Color LightGreen = FromPixel(new Rgba32(144, 238, 144, 255)); /// /// Represents a matching the W3C definition that has an hex value of #D3D3D3. @@ -384,27 +386,27 @@ public readonly partial struct Color /// /// Represents a matching the W3C definition that has an hex value of #FFB6C1. /// - public static readonly Color LightPink = FromRgba(255, 182, 193, 255); + public static readonly Color LightPink = FromPixel(new Rgba32(255, 182, 193, 255)); /// /// Represents a matching the W3C definition that has an hex value of #FFA07A. /// - public static readonly Color LightSalmon = FromRgba(255, 160, 122, 255); + public static readonly Color LightSalmon = FromPixel(new Rgba32(255, 160, 122, 255)); /// /// Represents a matching the W3C definition that has an hex value of #20B2AA. /// - public static readonly Color LightSeaGreen = FromRgba(32, 178, 170, 255); + public static readonly Color LightSeaGreen = FromPixel(new Rgba32(32, 178, 170, 255)); /// /// Represents a matching the W3C definition that has an hex value of #87CEFA. /// - public static readonly Color LightSkyBlue = FromRgba(135, 206, 250, 255); + public static readonly Color LightSkyBlue = FromPixel(new Rgba32(135, 206, 250, 255)); /// /// Represents a matching the W3C definition that has an hex value of #778899. /// - public static readonly Color LightSlateGray = FromRgba(119, 136, 153, 255); + public static readonly Color LightSlateGray = FromPixel(new Rgba32(119, 136, 153, 255)); /// /// Represents a matching the W3C definition that has an hex value of #778899. @@ -414,27 +416,27 @@ public readonly partial struct Color /// /// Represents a matching the W3C definition that has an hex value of #B0C4DE. /// - public static readonly Color LightSteelBlue = FromRgba(176, 196, 222, 255); + public static readonly Color LightSteelBlue = FromPixel(new Rgba32(176, 196, 222, 255)); /// /// Represents a matching the W3C definition that has an hex value of #FFFFE0. /// - public static readonly Color LightYellow = FromRgba(255, 255, 224, 255); + public static readonly Color LightYellow = FromPixel(new Rgba32(255, 255, 224, 255)); /// /// Represents a matching the W3C definition that has an hex value of #00FF00. /// - public static readonly Color Lime = FromRgba(0, 255, 0, 255); + public static readonly Color Lime = FromPixel(new Rgba32(0, 255, 0, 255)); /// /// Represents a matching the W3C definition that has an hex value of #32CD32. /// - public static readonly Color LimeGreen = FromRgba(50, 205, 50, 255); + public static readonly Color LimeGreen = FromPixel(new Rgba32(50, 205, 50, 255)); /// /// Represents a matching the W3C definition that has an hex value of #FAF0E6. /// - public static readonly Color Linen = FromRgba(250, 240, 230, 255); + public static readonly Color Linen = FromPixel(new Rgba32(250, 240, 230, 255)); /// /// Represents a matching the W3C definition that has an hex value of #FF00FF. @@ -444,237 +446,237 @@ public readonly partial struct Color /// /// Represents a matching the W3C definition that has an hex value of #800000. /// - public static readonly Color Maroon = FromRgba(128, 0, 0, 255); + public static readonly Color Maroon = FromPixel(new Rgba32(128, 0, 0, 255)); /// /// Represents a matching the W3C definition that has an hex value of #66CDAA. /// - public static readonly Color MediumAquamarine = FromRgba(102, 205, 170, 255); + public static readonly Color MediumAquamarine = FromPixel(new Rgba32(102, 205, 170, 255)); /// /// Represents a matching the W3C definition that has an hex value of #0000CD. /// - public static readonly Color MediumBlue = FromRgba(0, 0, 205, 255); + public static readonly Color MediumBlue = FromPixel(new Rgba32(0, 0, 205, 255)); /// /// Represents a matching the W3C definition that has an hex value of #BA55D3. /// - public static readonly Color MediumOrchid = FromRgba(186, 85, 211, 255); + public static readonly Color MediumOrchid = FromPixel(new Rgba32(186, 85, 211, 255)); /// /// Represents a matching the W3C definition that has an hex value of #9370DB. /// - public static readonly Color MediumPurple = FromRgba(147, 112, 219, 255); + public static readonly Color MediumPurple = FromPixel(new Rgba32(147, 112, 219, 255)); /// /// Represents a matching the W3C definition that has an hex value of #3CB371. /// - public static readonly Color MediumSeaGreen = FromRgba(60, 179, 113, 255); + public static readonly Color MediumSeaGreen = FromPixel(new Rgba32(60, 179, 113, 255)); /// /// Represents a matching the W3C definition that has an hex value of #7B68EE. /// - public static readonly Color MediumSlateBlue = FromRgba(123, 104, 238, 255); + public static readonly Color MediumSlateBlue = FromPixel(new Rgba32(123, 104, 238, 255)); /// /// Represents a matching the W3C definition that has an hex value of #00FA9A. /// - public static readonly Color MediumSpringGreen = FromRgba(0, 250, 154, 255); + public static readonly Color MediumSpringGreen = FromPixel(new Rgba32(0, 250, 154, 255)); /// /// Represents a matching the W3C definition that has an hex value of #48D1CC. /// - public static readonly Color MediumTurquoise = FromRgba(72, 209, 204, 255); + public static readonly Color MediumTurquoise = FromPixel(new Rgba32(72, 209, 204, 255)); /// /// Represents a matching the W3C definition that has an hex value of #C71585. /// - public static readonly Color MediumVioletRed = FromRgba(199, 21, 133, 255); + public static readonly Color MediumVioletRed = FromPixel(new Rgba32(199, 21, 133, 255)); /// /// Represents a matching the W3C definition that has an hex value of #191970. /// - public static readonly Color MidnightBlue = FromRgba(25, 25, 112, 255); + public static readonly Color MidnightBlue = FromPixel(new Rgba32(25, 25, 112, 255)); /// /// Represents a matching the W3C definition that has an hex value of #F5FFFA. /// - public static readonly Color MintCream = FromRgba(245, 255, 250, 255); + public static readonly Color MintCream = FromPixel(new Rgba32(245, 255, 250, 255)); /// /// Represents a matching the W3C definition that has an hex value of #FFE4E1. /// - public static readonly Color MistyRose = FromRgba(255, 228, 225, 255); + public static readonly Color MistyRose = FromPixel(new Rgba32(255, 228, 225, 255)); /// /// Represents a matching the W3C definition that has an hex value of #FFE4B5. /// - public static readonly Color Moccasin = FromRgba(255, 228, 181, 255); + public static readonly Color Moccasin = FromPixel(new Rgba32(255, 228, 181, 255)); /// /// Represents a matching the W3C definition that has an hex value of #FFDEAD. /// - public static readonly Color NavajoWhite = FromRgba(255, 222, 173, 255); + public static readonly Color NavajoWhite = FromPixel(new Rgba32(255, 222, 173, 255)); /// /// Represents a matching the W3C definition that has an hex value of #000080. /// - public static readonly Color Navy = FromRgba(0, 0, 128, 255); + public static readonly Color Navy = FromPixel(new Rgba32(0, 0, 128, 255)); /// /// Represents a matching the W3C definition that has an hex value of #FDF5E6. /// - public static readonly Color OldLace = FromRgba(253, 245, 230, 255); + public static readonly Color OldLace = FromPixel(new Rgba32(253, 245, 230, 255)); /// /// Represents a matching the W3C definition that has an hex value of #808000. /// - public static readonly Color Olive = FromRgba(128, 128, 0, 255); + public static readonly Color Olive = FromPixel(new Rgba32(128, 128, 0, 255)); /// /// Represents a matching the W3C definition that has an hex value of #6B8E23. /// - public static readonly Color OliveDrab = FromRgba(107, 142, 35, 255); + public static readonly Color OliveDrab = FromPixel(new Rgba32(107, 142, 35, 255)); /// /// Represents a matching the W3C definition that has an hex value of #FFA500. /// - public static readonly Color Orange = FromRgba(255, 165, 0, 255); + public static readonly Color Orange = FromPixel(new Rgba32(255, 165, 0, 255)); /// /// Represents a matching the W3C definition that has an hex value of #FF4500. /// - public static readonly Color OrangeRed = FromRgba(255, 69, 0, 255); + public static readonly Color OrangeRed = FromPixel(new Rgba32(255, 69, 0, 255)); /// /// Represents a matching the W3C definition that has an hex value of #DA70D6. /// - public static readonly Color Orchid = FromRgba(218, 112, 214, 255); + public static readonly Color Orchid = FromPixel(new Rgba32(218, 112, 214, 255)); /// /// Represents a matching the W3C definition that has an hex value of #EEE8AA. /// - public static readonly Color PaleGoldenrod = FromRgba(238, 232, 170, 255); + public static readonly Color PaleGoldenrod = FromPixel(new Rgba32(238, 232, 170, 255)); /// /// Represents a matching the W3C definition that has an hex value of #98FB98. /// - public static readonly Color PaleGreen = FromRgba(152, 251, 152, 255); + public static readonly Color PaleGreen = FromPixel(new Rgba32(152, 251, 152, 255)); /// /// Represents a matching the W3C definition that has an hex value of #AFEEEE. /// - public static readonly Color PaleTurquoise = FromRgba(175, 238, 238, 255); + public static readonly Color PaleTurquoise = FromPixel(new Rgba32(175, 238, 238, 255)); /// /// Represents a matching the W3C definition that has an hex value of #DB7093. /// - public static readonly Color PaleVioletRed = FromRgba(219, 112, 147, 255); + public static readonly Color PaleVioletRed = FromPixel(new Rgba32(219, 112, 147, 255)); /// /// Represents a matching the W3C definition that has an hex value of #FFEFD5. /// - public static readonly Color PapayaWhip = FromRgba(255, 239, 213, 255); + public static readonly Color PapayaWhip = FromPixel(new Rgba32(255, 239, 213, 255)); /// /// Represents a matching the W3C definition that has an hex value of #FFDAB9. /// - public static readonly Color PeachPuff = FromRgba(255, 218, 185, 255); + public static readonly Color PeachPuff = FromPixel(new Rgba32(255, 218, 185, 255)); /// /// Represents a matching the W3C definition that has an hex value of #CD853F. /// - public static readonly Color Peru = FromRgba(205, 133, 63, 255); + public static readonly Color Peru = FromPixel(new Rgba32(205, 133, 63, 255)); /// /// Represents a matching the W3C definition that has an hex value of #FFC0CB. /// - public static readonly Color Pink = FromRgba(255, 192, 203, 255); + public static readonly Color Pink = FromPixel(new Rgba32(255, 192, 203, 255)); /// /// Represents a matching the W3C definition that has an hex value of #DDA0DD. /// - public static readonly Color Plum = FromRgba(221, 160, 221, 255); + public static readonly Color Plum = FromPixel(new Rgba32(221, 160, 221, 255)); /// /// Represents a matching the W3C definition that has an hex value of #B0E0E6. /// - public static readonly Color PowderBlue = FromRgba(176, 224, 230, 255); + public static readonly Color PowderBlue = FromPixel(new Rgba32(176, 224, 230, 255)); /// /// Represents a matching the W3C definition that has an hex value of #800080. /// - public static readonly Color Purple = FromRgba(128, 0, 128, 255); + public static readonly Color Purple = FromPixel(new Rgba32(128, 0, 128, 255)); /// /// Represents a matching the W3C definition that has an hex value of #663399. /// - public static readonly Color RebeccaPurple = FromRgba(102, 51, 153, 255); + public static readonly Color RebeccaPurple = FromPixel(new Rgba32(102, 51, 153, 255)); /// /// Represents a matching the W3C definition that has an hex value of #FF0000. /// - public static readonly Color Red = FromRgba(255, 0, 0, 255); + public static readonly Color Red = FromPixel(new Rgba32(255, 0, 0, 255)); /// /// Represents a matching the W3C definition that has an hex value of #BC8F8F. /// - public static readonly Color RosyBrown = FromRgba(188, 143, 143, 255); + public static readonly Color RosyBrown = FromPixel(new Rgba32(188, 143, 143, 255)); /// /// Represents a matching the W3C definition that has an hex value of #4169E1. /// - public static readonly Color RoyalBlue = FromRgba(65, 105, 225, 255); + public static readonly Color RoyalBlue = FromPixel(new Rgba32(65, 105, 225, 255)); /// /// Represents a matching the W3C definition that has an hex value of #8B4513. /// - public static readonly Color SaddleBrown = FromRgba(139, 69, 19, 255); + public static readonly Color SaddleBrown = FromPixel(new Rgba32(139, 69, 19, 255)); /// /// Represents a matching the W3C definition that has an hex value of #FA8072. /// - public static readonly Color Salmon = FromRgba(250, 128, 114, 255); + public static readonly Color Salmon = FromPixel(new Rgba32(250, 128, 114, 255)); /// /// Represents a matching the W3C definition that has an hex value of #F4A460. /// - public static readonly Color SandyBrown = FromRgba(244, 164, 96, 255); + public static readonly Color SandyBrown = FromPixel(new Rgba32(244, 164, 96, 255)); /// /// Represents a matching the W3C definition that has an hex value of #2E8B57. /// - public static readonly Color SeaGreen = FromRgba(46, 139, 87, 255); + public static readonly Color SeaGreen = FromPixel(new Rgba32(46, 139, 87, 255)); /// /// Represents a matching the W3C definition that has an hex value of #FFF5EE. /// - public static readonly Color SeaShell = FromRgba(255, 245, 238, 255); + public static readonly Color SeaShell = FromPixel(new Rgba32(255, 245, 238, 255)); /// /// Represents a matching the W3C definition that has an hex value of #A0522D. /// - public static readonly Color Sienna = FromRgba(160, 82, 45, 255); + public static readonly Color Sienna = FromPixel(new Rgba32(160, 82, 45, 255)); /// /// Represents a matching the W3C definition that has an hex value of #C0C0C0. /// - public static readonly Color Silver = FromRgba(192, 192, 192, 255); + public static readonly Color Silver = FromPixel(new Rgba32(192, 192, 192, 255)); /// /// Represents a matching the W3C definition that has an hex value of #87CEEB. /// - public static readonly Color SkyBlue = FromRgba(135, 206, 235, 255); + public static readonly Color SkyBlue = FromPixel(new Rgba32(135, 206, 235, 255)); /// /// Represents a matching the W3C definition that has an hex value of #6A5ACD. /// - public static readonly Color SlateBlue = FromRgba(106, 90, 205, 255); + public static readonly Color SlateBlue = FromPixel(new Rgba32(106, 90, 205, 255)); /// /// Represents a matching the W3C definition that has an hex value of #708090. /// - public static readonly Color SlateGray = FromRgba(112, 128, 144, 255); + public static readonly Color SlateGray = FromPixel(new Rgba32(112, 128, 144, 255)); /// /// Represents a matching the W3C definition that has an hex value of #708090. @@ -684,81 +686,80 @@ public readonly partial struct Color /// /// Represents a matching the W3C definition that has an hex value of #FFFAFA. /// - public static readonly Color Snow = FromRgba(255, 250, 250, 255); + public static readonly Color Snow = FromPixel(new Rgba32(255, 250, 250, 255)); /// /// Represents a matching the W3C definition that has an hex value of #00FF7F. /// - public static readonly Color SpringGreen = FromRgba(0, 255, 127, 255); + public static readonly Color SpringGreen = FromPixel(new Rgba32(0, 255, 127, 255)); /// /// Represents a matching the W3C definition that has an hex value of #4682B4. /// - public static readonly Color SteelBlue = FromRgba(70, 130, 180, 255); + public static readonly Color SteelBlue = FromPixel(new Rgba32(70, 130, 180, 255)); /// /// Represents a matching the W3C definition that has an hex value of #D2B48C. /// - public static readonly Color Tan = FromRgba(210, 180, 140, 255); + public static readonly Color Tan = FromPixel(new Rgba32(210, 180, 140, 255)); /// /// Represents a matching the W3C definition that has an hex value of #008080. /// - public static readonly Color Teal = FromRgba(0, 128, 128, 255); + public static readonly Color Teal = FromPixel(new Rgba32(0, 128, 128, 255)); /// /// Represents a matching the W3C definition that has an hex value of #D8BFD8. /// - public static readonly Color Thistle = FromRgba(216, 191, 216, 255); + public static readonly Color Thistle = FromPixel(new Rgba32(216, 191, 216, 255)); /// /// Represents a matching the W3C definition that has an hex value of #FF6347. /// - public static readonly Color Tomato = FromRgba(255, 99, 71, 255); + public static readonly Color Tomato = FromPixel(new Rgba32(255, 99, 71, 255)); /// /// Represents a matching the W3C definition that has an hex value of #00000000. /// - public static readonly Color Transparent = FromRgba(0, 0, 0, 0); + public static readonly Color Transparent = FromPixel(new Rgba32(0, 0, 0, 0)); /// /// Represents a matching the W3C definition that has an hex value of #40E0D0. /// - public static readonly Color Turquoise = FromRgba(64, 224, 208, 255); + public static readonly Color Turquoise = FromPixel(new Rgba32(64, 224, 208, 255)); /// /// Represents a matching the W3C definition that has an hex value of #EE82EE. /// - public static readonly Color Violet = FromRgba(238, 130, 238, 255); + public static readonly Color Violet = FromPixel(new Rgba32(238, 130, 238, 255)); /// /// Represents a matching the W3C definition that has an hex value of #F5DEB3. /// - public static readonly Color Wheat = FromRgba(245, 222, 179, 255); + public static readonly Color Wheat = FromPixel(new Rgba32(245, 222, 179, 255)); /// /// Represents a matching the W3C definition that has an hex value of #FFFFFF. /// - public static readonly Color White = FromRgba(255, 255, 255, 255); + public static readonly Color White = FromPixel(new Rgba32(255, 255, 255, 255)); /// /// Represents a matching the W3C definition that has an hex value of #F5F5F5. /// - public static readonly Color WhiteSmoke = FromRgba(245, 245, 245, 255); + public static readonly Color WhiteSmoke = FromPixel(new Rgba32(245, 245, 245, 255)); /// /// Represents a matching the W3C definition that has an hex value of #FFFF00. /// - public static readonly Color Yellow = FromRgba(255, 255, 0, 255); + public static readonly Color Yellow = FromPixel(new Rgba32(255, 255, 0, 255)); /// /// Represents a matching the W3C definition that has an hex value of #9ACD32. /// - public static readonly Color YellowGreen = FromRgba(154, 205, 50, 255); + public static readonly Color YellowGreen = FromPixel(new Rgba32(154, 205, 50, 255)); private static Dictionary CreateNamedColorsLookup() - { - return new Dictionary(StringComparer.OrdinalIgnoreCase) + => new(StringComparer.OrdinalIgnoreCase) { { nameof(AliceBlue), AliceBlue }, { nameof(AntiqueWhite), AntiqueWhite }, @@ -910,5 +911,4 @@ private static Dictionary CreateNamedColorsLookup() { nameof(Yellow), Yellow }, { nameof(YellowGreen), YellowGreen } }; - } } diff --git a/src/ImageSharp/Color/Color.cs b/src/ImageSharp/Color/Color.cs index cebceabe09..8f54680ec4 100644 --- a/src/ImageSharp/Color/Color.cs +++ b/src/ImageSharp/Color/Color.cs @@ -18,34 +18,25 @@ namespace SixLabors.ImageSharp; /// public readonly partial struct Color : IEquatable { - private readonly Rgba64 data; + private readonly Vector4 data; private readonly IPixel? boxedHighPrecisionPixel; - [MethodImpl(InliningOptions.ShortMethod)] - private Color(byte r, byte g, byte b, byte a) - { - this.data = new Rgba64( - ColorNumerics.UpscaleFrom8BitTo16Bit(r), - ColorNumerics.UpscaleFrom8BitTo16Bit(g), - ColorNumerics.UpscaleFrom8BitTo16Bit(b), - ColorNumerics.UpscaleFrom8BitTo16Bit(a)); - - this.boxedHighPrecisionPixel = null; - } - - [MethodImpl(InliningOptions.ShortMethod)] - private Color(byte r, byte g, byte b) + /// + /// Initializes a new instance of the struct. + /// + /// The containing the color information. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private Color(Vector4 vector) { - this.data = new Rgba64( - ColorNumerics.UpscaleFrom8BitTo16Bit(r), - ColorNumerics.UpscaleFrom8BitTo16Bit(g), - ColorNumerics.UpscaleFrom8BitTo16Bit(b), - ushort.MaxValue); - + this.data = Numerics.Clamp(vector, Vector4.Zero, Vector4.One); this.boxedHighPrecisionPixel = null; } - [MethodImpl(InliningOptions.ShortMethod)] + /// + /// Initializes a new instance of the struct. + /// + /// The pixel containing color information. + [MethodImpl(MethodImplOptions.AggressiveInlining)] private Color(IPixel pixel) { this.boxedHighPrecisionPixel = pixel; @@ -61,7 +52,7 @@ private Color(IPixel pixel) /// True if the parameter is equal to the parameter; /// otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Color left, Color right) => left.Equals(right); /// @@ -73,66 +64,64 @@ private Color(IPixel pixel) /// True if the parameter is not equal to the parameter; /// otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Color left, Color right) => !left.Equals(right); /// - /// Creates a from RGBA bytes. + /// Creates a from the given . /// - /// The red component (0-255). - /// The green component (0-255). - /// The blue component (0-255). - /// The alpha component (0-255). + /// The pixel to convert from. + /// The pixel format. /// The . - [MethodImpl(InliningOptions.ShortMethod)] - public static Color FromRgba(byte r, byte g, byte b, byte a) => new(r, g, b, a); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Color FromPixel(TPixel source) + where TPixel : unmanaged, IPixel + { + // Avoid boxing in case we can convert to Vector4 safely and efficiently + PixelTypeInfo info = TPixel.GetPixelTypeInfo(); + if (info.ComponentInfo.HasValue && info.ComponentInfo.Value.GetMaximumComponentPrecision() <= (int)PixelComponentBitDepth.Bit32) + { + return new(source.ToScaledVector4()); + } + + return new(source); + } /// - /// Creates a from RGB bytes. + /// Creates a from a generic scaled . /// - /// The red component (0-255). - /// The green component (0-255). - /// The blue component (0-255). + /// The vector to load the pixel from. /// The . - [MethodImpl(InliningOptions.ShortMethod)] - public static Color FromRgb(byte r, byte g, byte b) => new(r, g, b); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Color FromScaledVector(Vector4 source) => new(source); /// - /// Creates a from the given . + /// Bulk converts a span of a specified type to a span of . /// - /// The pixel to convert from. - /// The pixel format. - /// The . - [MethodImpl(InliningOptions.ShortMethod)] - public static Color FromPixel(TPixel pixel) + /// The pixel type to convert to. + /// The source pixel span. + /// The destination color span. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void FromPixel(ReadOnlySpan source, Span destination) where TPixel : unmanaged, IPixel { - // Avoid boxing in case we can convert to Rgba64 safely and efficently - if (typeof(TPixel) == typeof(Rgba64)) - { - return new((Rgba64)(object)pixel); - } - else if (typeof(TPixel) == typeof(Rgb48)) - { - return new((Rgb48)(object)pixel); - } - else if (typeof(TPixel) == typeof(La32)) - { - return new((La32)(object)pixel); - } - else if (typeof(TPixel) == typeof(L16)) - { - return new((L16)(object)pixel); - } - else if (Unsafe.SizeOf() <= Unsafe.SizeOf()) + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + + // Avoid boxing in case we can convert to Vector4 safely and efficiently + PixelTypeInfo info = TPixel.GetPixelTypeInfo(); + if (info.ComponentInfo.HasValue && info.ComponentInfo.Value.GetMaximumComponentPrecision() <= (int)PixelComponentBitDepth.Bit32) { - Rgba32 p = default; - pixel.ToRgba32(ref p); - return new(p); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = FromScaledVector(source[i].ToScaledVector4()); + } } else { - return new(pixel); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = new(source[i]); + } } } @@ -147,12 +136,11 @@ public static Color FromPixel(TPixel pixel) /// /// The . /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Color ParseHex(string hex) { Rgba32 rgba = Rgba32.ParseHex(hex); - - return new Color(rgba); + return FromPixel(rgba); } /// @@ -167,14 +155,14 @@ public static Color ParseHex(string hex) /// /// The . /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool TryParseHex(string hex, out Color result) { result = default; if (Rgba32.TryParseHex(hex, out Rgba32 rgba)) { - result = new Color(rgba); + result = FromPixel(rgba); return true; } @@ -241,26 +229,24 @@ public static bool TryParse(string input, out Color result) /// The color having it's alpha channel altered. public Color WithAlpha(float alpha) { - Vector4 v = (Vector4)this; + Vector4 v = this.ToScaledVector4(); v.W = alpha; - return new Color(v); + return FromScaledVector(v); } /// /// Gets the hexadecimal representation of the color instance in rrggbbaa form. /// /// A hexadecimal string representation of the value. - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public string ToHex() { if (this.boxedHighPrecisionPixel is not null) { - Rgba32 rgba = default; - this.boxedHighPrecisionPixel.ToRgba32(ref rgba); - return rgba.ToHex(); + return this.boxedHighPrecisionPixel.ToRgba32().ToHex(); } - return this.data.ToRgba32().ToHex(); + return Rgba32.FromScaledVector4(this.data).ToHex(); } /// @@ -270,8 +256,8 @@ public string ToHex() /// Converts the color instance to a specified type. /// /// The pixel type to convert to. - /// The pixel value. - [MethodImpl(InliningOptions.ShortMethod)] + /// The . + [MethodImpl(MethodImplOptions.AggressiveInlining)] public TPixel ToPixel() where TPixel : unmanaged, IPixel { @@ -282,14 +268,27 @@ public TPixel ToPixel() if (this.boxedHighPrecisionPixel is null) { - pixel = default; - pixel.FromRgba64(this.data); - return pixel; + return TPixel.FromScaledVector4(this.data); + } + + return TPixel.FromScaledVector4(this.boxedHighPrecisionPixel.ToScaledVector4()); + } + + /// + /// Expands the color into a generic ("scaled") representation + /// with values scaled and clamped between 0 and 1. + /// The vector components are typically expanded in least to greatest significance order. + /// + /// The . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Vector4 ToScaledVector4() + { + if (this.boxedHighPrecisionPixel is null) + { + return this.data; } - pixel = default; - pixel.FromScaledVector4(this.boxedHighPrecisionPixel.ToScaledVector4()); - return pixel; + return this.boxedHighPrecisionPixel.ToScaledVector4(); } /// @@ -298,11 +297,12 @@ public TPixel ToPixel() /// The pixel type to convert to. /// The source color span. /// The destination pixel span. - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void ToPixel(ReadOnlySpan source, Span destination) where TPixel : unmanaged, IPixel { - // TODO: Investigate bulk operations utilizing configuration parameter here. + // We cannot use bulk pixel operations here as there is no guarantee that the source colors are + // created from pixel formats which fit into the unboxed vector data. Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); for (int i = 0; i < source.Length; i++) { @@ -311,12 +311,12 @@ public static void ToPixel(ReadOnlySpan source, Span dest } /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals(Color other) { if (this.boxedHighPrecisionPixel is null && other.boxedHighPrecisionPixel is null) { - return this.data.PackedValue == other.data.PackedValue; + return this.data == other.data; } return this.boxedHighPrecisionPixel?.Equals(other.boxedHighPrecisionPixel) == true; @@ -326,12 +326,12 @@ public bool Equals(Color other) public override bool Equals(object? obj) => obj is Color other && this.Equals(other); /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public override int GetHashCode() { if (this.boxedHighPrecisionPixel is null) { - return this.data.PackedValue.GetHashCode(); + return this.data.GetHashCode(); } return this.boxedHighPrecisionPixel.GetHashCode(); diff --git a/src/ImageSharp/ColorProfiles/ChromaticAdaptionWhitePointSource.cs b/src/ImageSharp/ColorProfiles/ChromaticAdaptionWhitePointSource.cs new file mode 100644 index 0000000000..7e4a9c413b --- /dev/null +++ b/src/ImageSharp/ColorProfiles/ChromaticAdaptionWhitePointSource.cs @@ -0,0 +1,20 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +namespace SixLabors.ImageSharp.ColorProfiles; + +/// +/// Enumerate the possible sources of the white point used in chromatic adaptation. +/// +public enum ChromaticAdaptionWhitePointSource +{ + /// + /// The white point of the source color space. + /// + WhitePoint, + + /// + /// The white point of the source working space. + /// + RgbWorkingSpace +} diff --git a/src/ImageSharp/ColorSpaces/Conversion/CieConstants.cs b/src/ImageSharp/ColorProfiles/CieConstants.cs similarity index 67% rename from src/ImageSharp/ColorSpaces/Conversion/CieConstants.cs rename to src/ImageSharp/ColorProfiles/CieConstants.cs index 7c87944043..d13a84450f 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/CieConstants.cs +++ b/src/ImageSharp/ColorProfiles/CieConstants.cs @@ -1,7 +1,7 @@ -// Copyright (c) Six Labors. +// Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; +namespace SixLabors.ImageSharp.ColorProfiles; /// /// Constants use for Cie conversion calculations @@ -12,10 +12,10 @@ internal static class CieConstants /// /// 216F / 24389F /// - public const float Epsilon = 0.008856452F; + public const float Epsilon = 216f / 24389f; /// /// 24389F / 27F /// - public const float Kappa = 903.2963F; + public const float Kappa = 24389f / 27f; } diff --git a/src/ImageSharp/ColorProfiles/CieLab.cs b/src/ImageSharp/ColorProfiles/CieLab.cs new file mode 100644 index 0000000000..377cc20a99 --- /dev/null +++ b/src/ImageSharp/ColorProfiles/CieLab.cs @@ -0,0 +1,178 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace SixLabors.ImageSharp.ColorProfiles; + +/// +/// Represents a CIE L*a*b* 1976 color. +/// +/// +[StructLayout(LayoutKind.Sequential)] +public readonly struct CieLab : IProfileConnectingSpace +{ + /// + /// Initializes a new instance of the struct. + /// + /// The lightness dimension. + /// The a (green - magenta) component. + /// The b (blue - yellow) component. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public CieLab(float l, float a, float b) + { + // Not clamping as documentation about this space only indicates "usual" ranges + this.L = l; + this.A = a; + this.B = b; + } + + /// + /// Initializes a new instance of the struct. + /// + /// The vector representing the l, a, b components. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public CieLab(Vector3 vector) + : this() + { + this.L = vector.X; + this.A = vector.Y; + this.B = vector.Z; + } + + /// + /// Gets the lightness dimension. + /// A value usually ranging between 0 (black), 100 (diffuse white) or higher (specular white). + /// + public float L { get; } + + /// + /// Gets the a color component. + /// A value usually ranging from -100 to 100. Negative is green, positive magenta. + /// + public float A { get; } + + /// + /// Gets the b color component. + /// A value usually ranging from -100 to 100. Negative is blue, positive is yellow + /// + public float B { get; } + + /// + /// Compares two objects for equality. + /// + /// The on the left side of the operand. + /// The on the right side of the operand. + /// + /// True if the current left is equal to the parameter; otherwise, false. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator ==(CieLab left, CieLab right) => left.Equals(right); + + /// + /// Compares two objects for inequality + /// + /// The on the left side of the operand. + /// The on the right side of the operand. + /// + /// True if the current left is unequal to the parameter; otherwise, false. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator !=(CieLab left, CieLab right) => !left.Equals(right); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static CieLab FromProfileConnectingSpace(ColorConversionOptions options, in CieXyz source) + { + // Conversion algorithm described here: + // http://www.brucelindbloom.com/index.html?Eqn_XYZ_to_Lab.html + CieXyz whitePoint = options.TargetWhitePoint; + float wx = whitePoint.X, wy = whitePoint.Y, wz = whitePoint.Z; + + float xr = source.X / wx, yr = source.Y / wy, zr = source.Z / wz; + + const float inv116 = 1 / 116F; + + float fx = xr > CieConstants.Epsilon ? MathF.Pow(xr, 0.3333333F) : ((CieConstants.Kappa * xr) + 16F) * inv116; + float fy = yr > CieConstants.Epsilon ? MathF.Pow(yr, 0.3333333F) : ((CieConstants.Kappa * yr) + 16F) * inv116; + float fz = zr > CieConstants.Epsilon ? MathF.Pow(zr, 0.3333333F) : ((CieConstants.Kappa * zr) + 16F) * inv116; + + float l = (116F * fy) - 16F; + float a = 500F * (fx - fy); + float b = 200F * (fy - fz); + + return new CieLab(l, a, b); + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void FromProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan source, Span destination) + { + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + + for (int i = 0; i < source.Length; i++) + { + CieXyz xyz = source[i]; + destination[i] = FromProfileConnectingSpace(options, in xyz); + } + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public CieXyz ToProfileConnectingSpace(ColorConversionOptions options) + { + // Conversion algorithm described here: http://www.brucelindbloom.com/index.html?Eqn_Lab_to_XYZ.html + float l = this.L, a = this.A, b = this.B; + float fy = (l + 16) / 116F; + float fx = (a / 500F) + fy; + float fz = fy - (b / 200F); + + float fx3 = Numerics.Pow3(fx); + float fz3 = Numerics.Pow3(fz); + + float xr = fx3 > CieConstants.Epsilon ? fx3 : ((116F * fx) - 16F) / CieConstants.Kappa; + float yr = l > CieConstants.Kappa * CieConstants.Epsilon ? Numerics.Pow3((l + 16F) / 116F) : l / CieConstants.Kappa; + float zr = fz3 > CieConstants.Epsilon ? fz3 : ((116F * fz) - 16F) / CieConstants.Kappa; + + CieXyz whitePoint = options.WhitePoint; + Vector3 wxyz = new(whitePoint.X, whitePoint.Y, whitePoint.Z); + Vector3 xyzr = new(xr, yr, zr); + + return new(xyzr * wxyz); + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void ToProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan source, Span destination) + { + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + + for (int i = 0; i < source.Length; i++) + { + CieLab lab = source[i]; + destination[i] = lab.ToProfileConnectingSpace(options); + } + } + + /// + public static ChromaticAdaptionWhitePointSource GetChromaticAdaptionWhitePointSource() + => ChromaticAdaptionWhitePointSource.WhitePoint; + + /// + public override int GetHashCode() => HashCode.Combine(this.L, this.A, this.B); + + /// + public override string ToString() => FormattableString.Invariant($"CieLab({this.L:#0.##}, {this.A:#0.##}, {this.B:#0.##})"); + + /// + public override bool Equals(object? obj) => obj is CieLab other && this.Equals(other); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Equals(CieLab other) + => this.AsVector3Unsafe() == other.AsVector3Unsafe(); + + private Vector3 AsVector3Unsafe() => Unsafe.As(ref Unsafe.AsRef(in this)); +} diff --git a/src/ImageSharp/ColorSpaces/CieLch.cs b/src/ImageSharp/ColorProfiles/CieLch.cs similarity index 50% rename from src/ImageSharp/ColorSpaces/CieLch.cs rename to src/ImageSharp/ColorProfiles/CieLch.cs index 48e8e2c6d9..1319783406 100644 --- a/src/ImageSharp/ColorSpaces/CieLch.cs +++ b/src/ImageSharp/ColorProfiles/CieLch.cs @@ -3,21 +3,17 @@ using System.Numerics; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; -namespace SixLabors.ImageSharp.ColorSpaces; +namespace SixLabors.ImageSharp.ColorProfiles; /// /// Represents the CIE L*C*h°, cylindrical form of the CIE L*a*b* 1976 color. /// /// -public readonly struct CieLch : IEquatable +[StructLayout(LayoutKind.Sequential)] +public readonly struct CieLch : IColorProfile { - /// - /// D50 standard illuminant. - /// Used when reference white is not specified explicitly. - /// - public static readonly CieXyz DefaultWhitePoint = Illuminants.D50; - private static readonly Vector3 Min = new(0, -200, 0); private static readonly Vector3 Max = new(100, 200, 360); @@ -27,23 +23,9 @@ namespace SixLabors.ImageSharp.ColorSpaces; /// The lightness dimension. /// The chroma, relative saturation. /// The hue in degrees. - /// Uses as white point. - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public CieLch(float l, float c, float h) - : this(l, c, h, DefaultWhitePoint) - { - } - - /// - /// Initializes a new instance of the struct. - /// - /// The lightness dimension. - /// The chroma, relative saturation. - /// The hue in degrees. - /// The reference white point. - [MethodImpl(InliningOptions.ShortMethod)] - public CieLch(float l, float c, float h, CieXyz whitePoint) - : this(new Vector3(l, c, h), whitePoint) + : this(new Vector3(l, c, h)) { } @@ -51,50 +33,32 @@ public CieLch(float l, float c, float h, CieXyz whitePoint) /// Initializes a new instance of the struct. /// /// The vector representing the l, c, h components. - /// Uses as white point. - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public CieLch(Vector3 vector) - : this(vector, DefaultWhitePoint) - { - } - - /// - /// Initializes a new instance of the struct. - /// - /// The vector representing the l, c, h components. - /// The reference white point. - [MethodImpl(InliningOptions.ShortMethod)] - public CieLch(Vector3 vector, CieXyz whitePoint) { vector = Vector3.Clamp(vector, Min, Max); this.L = vector.X; this.C = vector.Y; this.H = vector.Z; - this.WhitePoint = whitePoint; } /// /// Gets the lightness dimension. /// A value ranging between 0 (black), 100 (diffuse white) or higher (specular white). /// - public readonly float L { get; } + public float L { get; } /// /// Gets the a chroma component. /// A value ranging from 0 to 200. /// - public readonly float C { get; } + public float C { get; } /// /// Gets the h° hue component in degrees. /// A value ranging from 0 to 360. /// - public readonly float H { get; } - - /// - /// Gets the reference white point of this color - /// - public readonly CieXyz WhitePoint { get; } + public float H { get; } /// /// Compares two objects for equality. @@ -104,7 +68,7 @@ public CieLch(Vector3 vector, CieXyz whitePoint) /// /// True if the current left is equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(CieLch left, CieLch right) => left.Equals(right); /// @@ -115,45 +79,88 @@ public CieLch(Vector3 vector, CieXyz whitePoint) /// /// True if the current left is unequal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(CieLch left, CieLch right) => !left.Equals(right); /// - public override int GetHashCode() - => HashCode.Combine(this.L, this.C, this.H, this.WhitePoint); + public static CieLch FromProfileConnectingSpace(ColorConversionOptions options, in CieLab source) + { + // Conversion algorithm described here: + // https://en.wikipedia.org/wiki/Lab_color_space#Cylindrical_representation:_CIELCh_or_CIEHLC + float l = source.L, a = source.A, b = source.B; + float c = MathF.Sqrt((a * a) + (b * b)); + float hRadians = MathF.Atan2(b, a); + float hDegrees = GeometryUtilities.RadianToDegree(hRadians); + + // Wrap the angle round at 360. + hDegrees %= 360; + + // Make sure it's not negative. + while (hDegrees < 0) + { + hDegrees += 360; + } - /// - public override string ToString() => FormattableString.Invariant($"CieLch({this.L:#0.##}, {this.C:#0.##}, {this.H:#0.##})"); + return new CieLch(l, c, hDegrees); + } /// - [MethodImpl(InliningOptions.ShortMethod)] - public override bool Equals(object? obj) => obj is CieLch other && this.Equals(other); + public static void FromProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan source, Span destination) + { + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + + for (int i = 0; i < source.Length; i++) + { + CieLab lab = source[i]; + destination[i] = FromProfileConnectingSpace(options, in lab); + } + } /// - [MethodImpl(InliningOptions.ShortMethod)] - public bool Equals(CieLch other) - => this.L.Equals(other.L) - && this.C.Equals(other.C) - && this.H.Equals(other.H) - && this.WhitePoint.Equals(other.WhitePoint); + public CieLab ToProfileConnectingSpace(ColorConversionOptions options) + { + // Conversion algorithm described here: + // https://en.wikipedia.org/wiki/Lab_color_space#Cylindrical_representation:_CIELCh_or_CIEHLC + float l = this.L, c = this.C, hDegrees = this.H; + float hRadians = GeometryUtilities.DegreeToRadian(hDegrees); - /// - /// Computes the saturation of the color (chroma normalized by lightness) - /// - /// - /// A value ranging from 0 to 100. - /// - /// The - [MethodImpl(InliningOptions.ShortMethod)] - public float Saturation() + float a = c * MathF.Cos(hRadians); + float b = c * MathF.Sin(hRadians); + + return new CieLab(l, a, b); + } + + /// + public static void ToProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan source, Span destination) { - float result = 100 * (this.C / this.L); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - if (float.IsNaN(result)) + for (int i = 0; i < source.Length; i++) { - return 0; + CieLch lch = source[i]; + destination[i] = lch.ToProfileConnectingSpace(options); } - - return result; } + + /// + public static ChromaticAdaptionWhitePointSource GetChromaticAdaptionWhitePointSource() + => ChromaticAdaptionWhitePointSource.WhitePoint; + + /// + public override int GetHashCode() + => HashCode.Combine(this.L, this.C, this.H); + + /// + public override string ToString() => FormattableString.Invariant($"CieLch({this.L:#0.##}, {this.C:#0.##}, {this.H:#0.##})"); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override bool Equals(object? obj) => obj is CieLch other && this.Equals(other); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Equals(CieLch other) + => this.AsVector3Unsafe() == other.AsVector3Unsafe(); + + private Vector3 AsVector3Unsafe() => Unsafe.As(ref Unsafe.AsRef(in this)); } diff --git a/src/ImageSharp/ColorProfiles/CieLchuv.cs b/src/ImageSharp/ColorProfiles/CieLchuv.cs new file mode 100644 index 0000000000..7fd95feb19 --- /dev/null +++ b/src/ImageSharp/ColorProfiles/CieLchuv.cs @@ -0,0 +1,167 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace SixLabors.ImageSharp.ColorProfiles; + +/// +/// Represents the CIE L*C*h°, cylindrical form of the CIE L*u*v* 1976 color. +/// +/// +[StructLayout(LayoutKind.Sequential)] +public readonly struct CieLchuv : IColorProfile +{ + private static readonly Vector3 Min = new(0, -200, 0); + private static readonly Vector3 Max = new(100, 200, 360); + + /// + /// Initializes a new instance of the struct. + /// + /// The lightness dimension. + /// The chroma, relative saturation. + /// The hue in degrees. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public CieLchuv(float l, float c, float h) + : this(new Vector3(l, c, h)) + { + } + + /// + /// Initializes a new instance of the struct. + /// + /// The vector representing the l, c, h components. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public CieLchuv(Vector3 vector) + : this() + { + vector = Vector3.Clamp(vector, Min, Max); + this.L = vector.X; + this.C = vector.Y; + this.H = vector.Z; + } + + /// + /// Gets the lightness dimension. + /// A value ranging between 0 (black), 100 (diffuse white) or higher (specular white). + /// + public float L { get; } + + /// + /// Gets the a chroma component. + /// A value ranging from 0 to 200. + /// + public float C { get; } + + /// + /// Gets the h° hue component in degrees. + /// A value ranging from 0 to 360. + /// + public float H { get; } + + /// + /// Compares two objects for equality. + /// + /// The on the left side of the operand. + /// The on the right side of the operand. + /// + /// True if the current left is equal to the parameter; otherwise, false. + /// + public static bool operator ==(CieLchuv left, CieLchuv right) => left.Equals(right); + + /// + /// Compares two objects for inequality + /// + /// The on the left side of the operand. + /// The on the right side of the operand. + /// + /// True if the current left is unequal to the parameter; otherwise, false. + /// + public static bool operator !=(CieLchuv left, CieLchuv right) => !left.Equals(right); + + /// + public static CieLchuv FromProfileConnectingSpace(ColorConversionOptions options, in CieXyz source) + { + CieLuv luv = CieLuv.FromProfileConnectingSpace(options, source); + + // Conversion algorithm described here: + // https://en.wikipedia.org/wiki/CIELUV#Cylindrical_representation_.28CIELCH.29 + float l = luv.L, u = luv.U, v = luv.V; + float c = MathF.Sqrt((u * u) + (v * v)); + float hRadians = MathF.Atan2(v, u); + float hDegrees = GeometryUtilities.RadianToDegree(hRadians); + + // Wrap the angle round at 360. + hDegrees %= 360; + + // Make sure it's not negative. + while (hDegrees < 0) + { + hDegrees += 360; + } + + return new CieLchuv(l, c, hDegrees); + } + + /// + public static void FromProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan source, Span destination) + { + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + for (int i = 0; i < source.Length; i++) + { + CieXyz xyz = source[i]; + destination[i] = FromProfileConnectingSpace(options, in xyz); + } + } + + /// + public CieXyz ToProfileConnectingSpace(ColorConversionOptions options) + { + // Conversion algorithm described here: + // https://en.wikipedia.org/wiki/CIELUV#Cylindrical_representation_.28CIELCH.29 + float l = this.L, c = this.C, hDegrees = this.H; + float hRadians = GeometryUtilities.DegreeToRadian(hDegrees); + + float u = c * MathF.Cos(hRadians); + float v = c * MathF.Sin(hRadians); + + CieLuv luv = new(l, u, v); + return luv.ToProfileConnectingSpace(options); + } + + /// + public static void ToProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan source, Span destination) + { + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + for (int i = 0; i < source.Length; i++) + { + CieLchuv lch = source[i]; + destination[i] = lch.ToProfileConnectingSpace(options); + } + } + + /// + public static ChromaticAdaptionWhitePointSource GetChromaticAdaptionWhitePointSource() + => ChromaticAdaptionWhitePointSource.WhitePoint; + + /// + public override int GetHashCode() + => HashCode.Combine(this.L, this.C, this.H); + + /// + public override string ToString() + => FormattableString.Invariant($"CieLchuv({this.L:#0.##}, {this.C:#0.##}, {this.H:#0.##})"); + + /// + public override bool Equals(object? obj) + => obj is CieLchuv other && this.Equals(other); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Equals(CieLchuv other) + => this.AsVector3Unsafe() == other.AsVector3Unsafe(); + + private Vector3 AsVector3Unsafe() => Unsafe.As(ref Unsafe.AsRef(in this)); +} diff --git a/src/ImageSharp/ColorProfiles/CieLuv.cs b/src/ImageSharp/ColorProfiles/CieLuv.cs new file mode 100644 index 0000000000..97e2826f74 --- /dev/null +++ b/src/ImageSharp/ColorProfiles/CieLuv.cs @@ -0,0 +1,221 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace SixLabors.ImageSharp.ColorProfiles; + +/// +/// The CIE 1976 (L*, u*, v*) color space, commonly known by its abbreviation CIELUV, is a color space adopted by the International +/// Commission on Illumination (CIE) in 1976, as a simple-to-compute transformation of the 1931 CIE XYZ color space, but which +/// attempted perceptual uniformity +/// +/// +[StructLayout(LayoutKind.Sequential)] +public readonly struct CieLuv : IColorProfile +{ + /// + /// Initializes a new instance of the struct. + /// + /// The lightness dimension. + /// The blue-yellow chromaticity coordinate of the given white point. + /// The red-green chromaticity coordinate of the given white point. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public CieLuv(float l, float u, float v) + { + // Not clamping as documentation about this space only indicates "usual" ranges + this.L = l; + this.U = u; + this.V = v; + } + + /// + /// Initializes a new instance of the struct. + /// + /// The vector representing the l, u, v components. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public CieLuv(Vector3 vector) + : this() + { + this.L = vector.X; + this.U = vector.Y; + this.V = vector.Z; + } + + /// + /// Gets the lightness dimension + /// A value usually ranging between 0 and 100. + /// + public float L { get; } + + /// + /// Gets the blue-yellow chromaticity coordinate of the given white point. + /// A value usually ranging between -100 and 100. + /// + public float U { get; } + + /// + /// Gets the red-green chromaticity coordinate of the given white point. + /// A value usually ranging between -100 and 100. + /// + public float V { get; } + + /// + /// Compares two objects for equality. + /// + /// The on the left side of the operand. + /// The on the right side of the operand. + /// + /// True if the current left is equal to the parameter; otherwise, false. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator ==(CieLuv left, CieLuv right) => left.Equals(right); + + /// + /// Compares two objects for inequality. + /// + /// The on the left side of the operand. + /// The on the right side of the operand. + /// + /// True if the current left is unequal to the parameter; otherwise, false. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator !=(CieLuv left, CieLuv right) => !left.Equals(right); + + /// + public static CieLuv FromProfileConnectingSpace(ColorConversionOptions options, in CieXyz source) + { + // Use doubles here for accuracy. + // Conversion algorithm described here: + // http://www.brucelindbloom.com/index.html?Eqn_XYZ_to_Luv.html + CieXyz whitePoint = options.TargetWhitePoint; + + double yr = source.Y / whitePoint.Y; + + double den = source.X + (15 * source.Y) + (3 * source.Z); + double up = den > 0 ? ComputeU(in source) : 0; + double vp = den > 0 ? ComputeV(in source) : 0; + double upr = ComputeU(in whitePoint); + double vpr = ComputeV(in whitePoint); + + const double e = 1 / 3d; + double l = yr > CieConstants.Epsilon + ? ((116 * Math.Pow(yr, e)) - 16d) + : (CieConstants.Kappa * yr); + + if (double.IsNaN(l) || l == -0d) + { + l = 0; + } + + double u = 13 * l * (up - upr); + double v = 13 * l * (vp - vpr); + + if (double.IsNaN(u) || u == -0d) + { + u = 0; + } + + if (double.IsNaN(v) || v == -0d) + { + v = 0; + } + + return new CieLuv((float)l, (float)u, (float)v); + } + + /// + public static void FromProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan source, Span destination) + { + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + for (int i = 0; i < source.Length; i++) + { + CieXyz xyz = source[i]; + destination[i] = FromProfileConnectingSpace(options, in xyz); + } + } + + /// + public CieXyz ToProfileConnectingSpace(ColorConversionOptions options) + { + // Use doubles here for accuracy. + // Conversion algorithm described here: + // http://www.brucelindbloom.com/index.html?Eqn_Luv_to_XYZ.html + CieXyz whitePoint = options.WhitePoint; + + double l = this.L, u = this.U, v = this.V; + + double u0 = ComputeU(in whitePoint); + double v0 = ComputeV(in whitePoint); + + double y = l > CieConstants.Kappa * CieConstants.Epsilon + ? Numerics.Pow3((l + 16) / 116d) + : l / CieConstants.Kappa; + + double a = ((52 * l / (u + (13 * l * u0))) - 1) / 3; + double b = -5 * y; + const double c = -1 / 3d; + double d = y * ((39 * l / (v + (13 * l * v0))) - 5); + + double x = (d - b) / (a - c); + double z = (x * a) + b; + + if (double.IsNaN(x) || x == -0d) + { + x = 0; + } + + if (double.IsNaN(y) || y == -0d) + { + y = 0; + } + + if (double.IsNaN(z) || z == -0d) + { + z = 0; + } + + return new CieXyz((float)x, (float)y, (float)z); + } + + /// + public static void ToProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan source, Span destination) + { + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + for (int i = 0; i < source.Length; i++) + { + CieLuv luv = source[i]; + destination[i] = luv.ToProfileConnectingSpace(options); + } + } + + /// + public static ChromaticAdaptionWhitePointSource GetChromaticAdaptionWhitePointSource() + => ChromaticAdaptionWhitePointSource.WhitePoint; + + /// + public override int GetHashCode() => HashCode.Combine(this.L, this.U, this.V); + + /// + public override string ToString() => FormattableString.Invariant($"CieLuv({this.L:#0.##}, {this.U:#0.##}, {this.V:#0.##})"); + + /// + public override bool Equals(object? obj) => obj is CieLuv other && this.Equals(other); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Equals(CieLuv other) + => this.AsVector3Unsafe() == other.AsVector3Unsafe(); + + private Vector3 AsVector3Unsafe() => Unsafe.As(ref Unsafe.AsRef(in this)); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static double ComputeU(in CieXyz source) + => (4 * source.X) / (source.X + (15 * source.Y) + (3 * source.Z)); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static double ComputeV(in CieXyz source) + => (9 * source.Y) / (source.X + (15 * source.Y) + (3 * source.Z)); +} diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyChromaticityCoordinates.cs b/src/ImageSharp/ColorProfiles/CieXyChromaticityCoordinates.cs similarity index 88% rename from src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyChromaticityCoordinates.cs rename to src/ImageSharp/ColorProfiles/CieXyChromaticityCoordinates.cs index 2cc785d53b..fa12b81d22 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyChromaticityCoordinates.cs +++ b/src/ImageSharp/ColorProfiles/CieXyChromaticityCoordinates.cs @@ -1,14 +1,16 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. +using System.Numerics; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; -// ReSharper disable CompareOfFloatsByEqualityOperator -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; +namespace SixLabors.ImageSharp.ColorProfiles; /// /// Represents the coordinates of CIEXY chromaticity space. /// +[StructLayout(LayoutKind.Sequential)] public readonly struct CieXyChromaticityCoordinates : IEquatable { /// @@ -29,7 +31,7 @@ public CieXyChromaticityCoordinates(float x, float y) /// /// Ranges usually from 0 to 1. /// - public readonly float X { get; } + public float X { get; } /// /// Gets the chromaticity Y-coordinate @@ -37,7 +39,7 @@ public CieXyChromaticityCoordinates(float x, float y) /// /// Ranges usually from 0 to 1. /// - public readonly float Y { get; } + public float Y { get; } /// /// Compares two objects for equality. @@ -79,5 +81,7 @@ public override bool Equals(object? obj) /// [MethodImpl(InliningOptions.ShortMethod)] public bool Equals(CieXyChromaticityCoordinates other) - => this.X.Equals(other.X) && this.Y.Equals(other.Y); + => this.AsVector2Unsafe() == other.AsVector2Unsafe(); + + private Vector2 AsVector2Unsafe() => Unsafe.As(ref Unsafe.AsRef(in this)); } diff --git a/src/ImageSharp/ColorSpaces/CieXyy.cs b/src/ImageSharp/ColorProfiles/CieXyy.cs similarity index 51% rename from src/ImageSharp/ColorSpaces/CieXyy.cs rename to src/ImageSharp/ColorProfiles/CieXyy.cs index 6b7d2e6cbd..62873df147 100644 --- a/src/ImageSharp/ColorSpaces/CieXyy.cs +++ b/src/ImageSharp/ColorProfiles/CieXyy.cs @@ -3,14 +3,16 @@ using System.Numerics; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; -namespace SixLabors.ImageSharp.ColorSpaces; +namespace SixLabors.ImageSharp.ColorProfiles; /// /// Represents an CIE xyY 1931 color /// /// -public readonly struct CieXyy : IEquatable +[StructLayout(LayoutKind.Sequential)] +public readonly struct CieXyy : IColorProfile { /// /// Initializes a new instance of the struct. @@ -18,7 +20,7 @@ namespace SixLabors.ImageSharp.ColorSpaces; /// The x chroma component. /// The y chroma component. /// The y luminance component. - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public CieXyy(float x, float y, float yl) { // Not clamping as documentation about this space only indicates "usual" ranges @@ -31,7 +33,7 @@ public CieXyy(float x, float y, float yl) /// Initializes a new instance of the struct. /// /// The vector representing the x, y, Y components. - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public CieXyy(Vector3 vector) : this() { @@ -45,19 +47,19 @@ public CieXyy(Vector3 vector) /// Gets the X chrominance component. /// A value usually ranging between 0 and 1. /// - public readonly float X { get; } + public float X { get; } /// /// Gets the Y chrominance component. /// A value usually ranging between 0 and 1. /// - public readonly float Y { get; } + public float Y { get; } /// /// Gets the Y luminance component. /// A value usually ranging between 0 and 1. /// - public readonly float Yl { get; } + public float Yl { get; } /// /// Compares two objects for equality. @@ -67,7 +69,7 @@ public CieXyy(Vector3 vector) /// /// True if the current left is equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(CieXyy left, CieXyy right) => left.Equals(right); /// @@ -78,22 +80,79 @@ public CieXyy(Vector3 vector) /// /// True if the current left is unequal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(CieXyy left, CieXyy right) => !left.Equals(right); /// - public override int GetHashCode() => HashCode.Combine(this.X, this.Y, this.Yl); + public static CieXyy FromProfileConnectingSpace(ColorConversionOptions options, in CieXyz source) + { + float x = source.X / (source.X + source.Y + source.Z); + float y = source.Y / (source.X + source.Y + source.Z); + + if (float.IsNaN(x) || float.IsNaN(y)) + { + return new CieXyy(0, 0, source.Y); + } + + return new CieXyy(x, y, source.Y); + } + + /// + public static void FromProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan source, Span destination) + { + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + for (int i = 0; i < source.Length; i++) + { + CieXyz xyz = source[i]; + destination[i] = FromProfileConnectingSpace(options, in xyz); + } + } /// - public override string ToString() => FormattableString.Invariant($"CieXyy({this.X:#0.##}, {this.Y:#0.##}, {this.Yl:#0.##})"); + public CieXyz ToProfileConnectingSpace(ColorConversionOptions options) + { + if (MathF.Abs(this.Y) < Constants.Epsilon) + { + return new CieXyz(0, 0, this.Yl); + } + + float x = (this.X * this.Yl) / this.Y; + float y = this.Yl; + float z = ((1 - this.X - this.Y) * y) / this.Y; + + return new CieXyz(x, y, z); + } + + /// + public static void ToProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan source, Span destination) + { + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + for (int i = 0; i < source.Length; i++) + { + CieXyy xyz = source[i]; + destination[i] = xyz.ToProfileConnectingSpace(options); + } + } + + /// + public static ChromaticAdaptionWhitePointSource GetChromaticAdaptionWhitePointSource() + => ChromaticAdaptionWhitePointSource.WhitePoint; + + /// + public override int GetHashCode() + => HashCode.Combine(this.X, this.Y, this.Yl); + + /// + public override string ToString() + => FormattableString.Invariant($"CieXyy({this.X:#0.##}, {this.Y:#0.##}, {this.Yl:#0.##})"); /// public override bool Equals(object? obj) => obj is CieXyy other && this.Equals(other); /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals(CieXyy other) - => this.X.Equals(other.X) - && this.Y.Equals(other.Y) - && this.Yl.Equals(other.Yl); + => this.AsVector3Unsafe() == other.AsVector3Unsafe(); + + private Vector3 AsVector3Unsafe() => Unsafe.As(ref Unsafe.AsRef(in this)); } diff --git a/src/ImageSharp/ColorSpaces/CieXyz.cs b/src/ImageSharp/ColorProfiles/CieXyz.cs similarity index 64% rename from src/ImageSharp/ColorSpaces/CieXyz.cs rename to src/ImageSharp/ColorProfiles/CieXyz.cs index 2ac9c9f286..07f9b47f9b 100644 --- a/src/ImageSharp/ColorSpaces/CieXyz.cs +++ b/src/ImageSharp/ColorProfiles/CieXyz.cs @@ -3,14 +3,16 @@ using System.Numerics; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; -namespace SixLabors.ImageSharp.ColorSpaces; +namespace SixLabors.ImageSharp.ColorProfiles; /// /// Represents an CIE XYZ 1931 color /// /// -public readonly struct CieXyz : IEquatable +[StructLayout(LayoutKind.Sequential)] +public readonly struct CieXyz : IProfileConnectingSpace { /// /// Initializes a new instance of the struct. @@ -18,10 +20,13 @@ namespace SixLabors.ImageSharp.ColorSpaces; /// X is a mix (a linear combination) of cone response curves chosen to be nonnegative /// The y luminance component. /// Z is quasi-equal to blue stimulation, or the S cone of the human eye. - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public CieXyz(float x, float y, float z) - : this(new Vector3(x, y, z)) { + // Not clamping as documentation about this space only indicates "usual" ranges + this.X = x; + this.Y = y; + this.Z = z; } /// @@ -31,7 +36,6 @@ public CieXyz(float x, float y, float z) public CieXyz(Vector3 vector) : this() { - // Not clamping as documentation about this space only indicates "usual" ranges this.X = vector.X; this.Y = vector.Y; this.Z = vector.Z; @@ -41,19 +45,19 @@ public CieXyz(Vector3 vector) /// Gets the X component. A mix (a linear combination) of cone response curves chosen to be nonnegative. /// A value usually ranging between 0 and 1. /// - public readonly float X { get; } + public float X { get; } /// /// Gets the Y luminance component. /// A value usually ranging between 0 and 1. /// - public readonly float Y { get; } + public float Y { get; } /// /// Gets the Z component. Quasi-equal to blue stimulation, or the S cone response. /// A value usually ranging between 0 and 1. /// - public readonly float Z { get; } + public float Z { get; } /// /// Compares two objects for equality. @@ -63,7 +67,7 @@ public CieXyz(Vector3 vector) /// /// True if the current left is equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(CieXyz left, CieXyz right) => left.Equals(right); /// @@ -74,16 +78,41 @@ public CieXyz(Vector3 vector) /// /// True if the current left is unequal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(CieXyz left, CieXyz right) => !left.Equals(right); /// /// Returns a new representing this instance. /// /// The . - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public Vector3 ToVector3() => new(this.X, this.Y, this.Z); + /// + public static CieXyz FromProfileConnectingSpace(ColorConversionOptions options, in CieXyz source) + => new(source.X, source.Y, source.Z); + + /// + public static void FromProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan source, Span destination) + { + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + source.CopyTo(destination[..source.Length]); + } + + /// + public CieXyz ToProfileConnectingSpace(ColorConversionOptions options) + => new(this.X, this.Y, this.Z); + + /// + public static void ToProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan source, Span destination) + { + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + source.CopyTo(destination[..source.Length]); + } + + /// + public static ChromaticAdaptionWhitePointSource GetChromaticAdaptionWhitePointSource() => ChromaticAdaptionWhitePointSource.WhitePoint; + /// public override int GetHashCode() => HashCode.Combine(this.X, this.Y, this.Z); @@ -94,9 +123,9 @@ public CieXyz(Vector3 vector) public override bool Equals(object? obj) => obj is CieXyz other && this.Equals(other); /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals(CieXyz other) - => this.X.Equals(other.X) - && this.Y.Equals(other.Y) - && this.Z.Equals(other.Z); + => this.AsVector3Unsafe() == other.AsVector3Unsafe(); + + private Vector3 AsVector3Unsafe() => Unsafe.As(ref Unsafe.AsRef(in this)); } diff --git a/src/ImageSharp/ColorProfiles/Cmyk.cs b/src/ImageSharp/ColorProfiles/Cmyk.cs new file mode 100644 index 0000000000..e924904497 --- /dev/null +++ b/src/ImageSharp/ColorProfiles/Cmyk.cs @@ -0,0 +1,165 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace SixLabors.ImageSharp.ColorProfiles; + +/// +/// Represents an CMYK (cyan, magenta, yellow, keyline) color. +/// +[StructLayout(LayoutKind.Sequential)] +public readonly struct Cmyk : IColorProfile +{ + private static readonly Vector4 Min = Vector4.Zero; + private static readonly Vector4 Max = Vector4.One; + + /// + /// Initializes a new instance of the struct. + /// + /// The cyan component. + /// The magenta component. + /// The yellow component. + /// The keyline black component. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Cmyk(float c, float m, float y, float k) + : this(new Vector4(c, m, y, k)) + { + } + + /// + /// Initializes a new instance of the struct. + /// + /// The vector representing the c, m, y, k components. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Cmyk(Vector4 vector) + { + vector = Numerics.Clamp(vector, Min, Max); + this.C = vector.X; + this.M = vector.Y; + this.Y = vector.Z; + this.K = vector.W; + } + + /// + /// Gets the cyan color component. + /// A value ranging between 0 and 1. + /// + public float C { get; } + + /// + /// Gets the magenta color component. + /// A value ranging between 0 and 1. + /// + public float M { get; } + + /// + /// Gets the yellow color component. + /// A value ranging between 0 and 1. + /// + public float Y { get; } + + /// + /// Gets the keyline black color component. + /// A value ranging between 0 and 1. + /// + public float K { get; } + + /// + /// Compares two objects for equality. + /// + /// The on the left side of the operand. + /// The on the right side of the operand. + /// + /// True if the current left is equal to the parameter; otherwise, false. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator ==(Cmyk left, Cmyk right) => left.Equals(right); + + /// + /// Compares two objects for inequality. + /// + /// The on the left side of the operand. + /// The on the right side of the operand. + /// + /// True if the current left is unequal to the parameter; otherwise, false. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator !=(Cmyk left, Cmyk right) => !left.Equals(right); + + /// + public static Cmyk FromProfileConnectingSpace(ColorConversionOptions options, in Rgb source) + { + // To CMY + Vector3 cmy = Vector3.One - source.ToScaledVector3(); + + // To CMYK + Vector3 k = new(MathF.Min(cmy.X, MathF.Min(cmy.Y, cmy.Z))); + + if (MathF.Abs(k.X - 1F) < Constants.Epsilon) + { + return new Cmyk(0, 0, 0, 1F); + } + + cmy = (cmy - k) / (Vector3.One - k); + + return new Cmyk(cmy.X, cmy.Y, cmy.Z, k.X); + } + + /// + public static void FromProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan source, Span destination) + { + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + + // TODO: We can optimize this by using SIMD + for (int i = 0; i < source.Length; i++) + { + Rgb rgb = source[i]; + destination[i] = FromProfileConnectingSpace(options, in rgb); + } + } + + /// + public Rgb ToProfileConnectingSpace(ColorConversionOptions options) + { + Vector3 rgb = (Vector3.One - new Vector3(this.C, this.M, this.Y)) * (Vector3.One - new Vector3(this.K)); + return Rgb.FromScaledVector3(rgb); + } + + /// + public static void ToProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan source, Span destination) + { + // TODO: We can possibly optimize this by using SIMD + for (int i = 0; i < source.Length; i++) + { + Cmyk cmyk = source[i]; + destination[i] = cmyk.ToProfileConnectingSpace(options); + } + } + + /// + public static ChromaticAdaptionWhitePointSource GetChromaticAdaptionWhitePointSource() + => ChromaticAdaptionWhitePointSource.RgbWorkingSpace; + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override int GetHashCode() + => HashCode.Combine(this.C, this.M, this.Y, this.K); + + /// + public override string ToString() + => FormattableString.Invariant($"Cmyk({this.C:#0.##}, {this.M:#0.##}, {this.Y:#0.##}, {this.K:#0.##})"); + + /// + public override bool Equals(object? obj) + => obj is Cmyk other && this.Equals(other); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Equals(Cmyk other) + => this.AsVector4Unsafe() == other.AsVector4Unsafe(); + + private Vector4 AsVector4Unsafe() => Unsafe.As(ref Unsafe.AsRef(in this)); +} diff --git a/src/ImageSharp/ColorProfiles/ColorConversionOptions.cs b/src/ImageSharp/ColorProfiles/ColorConversionOptions.cs new file mode 100644 index 0000000000..1eb118834a --- /dev/null +++ b/src/ImageSharp/ColorProfiles/ColorConversionOptions.cs @@ -0,0 +1,63 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Numerics; +using SixLabors.ImageSharp.ColorProfiles.WorkingSpaces; +using SixLabors.ImageSharp.Memory; + +namespace SixLabors.ImageSharp.ColorProfiles; + +/// +/// Provides options for color profile conversion. +/// +public class ColorConversionOptions +{ + private Matrix4x4 adaptationMatrix; + + /// + /// Initializes a new instance of the class. + /// + public ColorConversionOptions() => this.AdaptationMatrix = KnownChromaticAdaptationMatrices.Bradford; + + /// + /// Gets the memory allocator. + /// + public MemoryAllocator MemoryAllocator { get; init; } = MemoryAllocator.Default; + + /// + /// Gets the source white point used for chromatic adaptation in conversions from/to XYZ color space. + /// + public CieXyz WhitePoint { get; init; } = KnownIlluminants.D50; + + /// + /// Gets the destination white point used for chromatic adaptation in conversions from/to XYZ color space. + /// + public CieXyz TargetWhitePoint { get; init; } = KnownIlluminants.D50; + + /// + /// Gets the source working space used for companding in conversions from/to XYZ color space. + /// + public RgbWorkingSpace RgbWorkingSpace { get; init; } = KnownRgbWorkingSpaces.SRgb; + + /// + /// Gets the destination working space used for companding in conversions from/to XYZ color space. + /// + public RgbWorkingSpace TargetRgbWorkingSpace { get; init; } = KnownRgbWorkingSpaces.SRgb; + + /// + /// Gets the transformation matrix used in conversion to perform chromatic adaptation. + /// for further information. Default is Bradford. + /// + public Matrix4x4 AdaptationMatrix + { + get => this.adaptationMatrix; + init + { + this.adaptationMatrix = value; + Matrix4x4.Invert(value, out Matrix4x4 inverted); + this.InverseAdaptationMatrix = inverted; + } + } + + internal Matrix4x4 InverseAdaptationMatrix { get; private set; } +} diff --git a/src/ImageSharp/ColorProfiles/ColorProfileConverter.cs b/src/ImageSharp/ColorProfiles/ColorProfileConverter.cs new file mode 100644 index 0000000000..18b90a622a --- /dev/null +++ b/src/ImageSharp/ColorProfiles/ColorProfileConverter.cs @@ -0,0 +1,45 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +namespace SixLabors.ImageSharp.ColorProfiles; + +/// +/// Allows the conversion of color profiles. +/// +public class ColorProfileConverter +{ + /// + /// Initializes a new instance of the class. + /// + public ColorProfileConverter() + : this(new()) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The color profile conversion options. + public ColorProfileConverter(ColorConversionOptions options) + => this.Options = options; + + /// + /// Gets the color profile conversion options. + /// + public ColorConversionOptions Options { get; } + + internal (CieXyz From, CieXyz To) GetChromaticAdaptionWhitePoints() + where TFrom : struct, IColorProfile + where TTo : struct, IColorProfile + { + CieXyz sourceWhitePoint = TFrom.GetChromaticAdaptionWhitePointSource() == ChromaticAdaptionWhitePointSource.WhitePoint + ? this.Options.WhitePoint + : this.Options.RgbWorkingSpace.WhitePoint; + + CieXyz targetWhitePoint = TTo.GetChromaticAdaptionWhitePointSource() == ChromaticAdaptionWhitePointSource.WhitePoint + ? this.Options.TargetWhitePoint + : this.Options.TargetRgbWorkingSpace.WhitePoint; + + return (sourceWhitePoint, targetWhitePoint); + } +} diff --git a/src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsCieLabCieLab.cs b/src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsCieLabCieLab.cs new file mode 100644 index 0000000000..41ae4b08fa --- /dev/null +++ b/src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsCieLabCieLab.cs @@ -0,0 +1,57 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Buffers; +using SixLabors.ImageSharp.Memory; + +namespace SixLabors.ImageSharp.ColorProfiles; + +internal static class ColorProfileConverterExtensionsCieLabCieLab +{ + public static TTo Convert(this ColorProfileConverter converter, in TFrom source) + where TFrom : struct, IColorProfile + where TTo : struct, IColorProfile + { + ColorConversionOptions options = converter.Options; + + // Convert to input PCS + CieLab pcsFromA = source.ToProfileConnectingSpace(options); + CieXyz pcsFromB = pcsFromA.ToProfileConnectingSpace(options); + + // Adapt to target white point + (CieXyz From, CieXyz To) whitePoints = converter.GetChromaticAdaptionWhitePoints(); + pcsFromB = VonKriesChromaticAdaptation.Transform(in pcsFromB, whitePoints, options.AdaptationMatrix); + + // Convert between PCS + CieLab pcsTo = CieLab.FromProfileConnectingSpace(options, in pcsFromB); + + // Convert to output from PCS + return TTo.FromProfileConnectingSpace(options, in pcsTo); + } + + public static void Convert(this ColorProfileConverter converter, ReadOnlySpan source, Span destination) + where TFrom : struct, IColorProfile + where TTo : struct, IColorProfile + { + ColorConversionOptions options = converter.Options; + + // Convert to input PCS. + using IMemoryOwner pcsFromToOwner = options.MemoryAllocator.Allocate(source.Length); + Span pcsFromTo = pcsFromToOwner.GetSpan(); + TFrom.ToProfileConnectionSpace(options, source, pcsFromTo); + + using IMemoryOwner pcsFromOwner = options.MemoryAllocator.Allocate(source.Length); + Span pcsFrom = pcsFromOwner.GetSpan(); + CieLab.ToProfileConnectionSpace(options, pcsFromTo, pcsFrom); + + // Adapt to target white point + (CieXyz From, CieXyz To) whitePoints = converter.GetChromaticAdaptionWhitePoints(); + VonKriesChromaticAdaptation.Transform(pcsFrom, pcsFrom, whitePoints, options.AdaptationMatrix); + + // Convert between PCS. + CieLab.FromProfileConnectionSpace(options, pcsFrom, pcsFromTo); + + // Convert to output from PCS + TTo.FromProfileConnectionSpace(options, pcsFromTo, destination); + } +} diff --git a/src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsCieLabCieXyz.cs b/src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsCieLabCieXyz.cs new file mode 100644 index 0000000000..04937e927e --- /dev/null +++ b/src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsCieLabCieXyz.cs @@ -0,0 +1,54 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Buffers; +using SixLabors.ImageSharp.Memory; + +namespace SixLabors.ImageSharp.ColorProfiles; + +internal static class ColorProfileConverterExtensionsCieLabCieXyz +{ + public static TTo Convert(this ColorProfileConverter converter, in TFrom source) + where TFrom : struct, IColorProfile + where TTo : struct, IColorProfile + { + ColorConversionOptions options = converter.Options; + + // Convert to input PCS + CieLab pcsFrom = source.ToProfileConnectingSpace(options); + + // Convert between PCS + CieXyz pcsTo = pcsFrom.ToProfileConnectingSpace(options); + + // Adapt to target white point + (CieXyz From, CieXyz To) whitePoints = converter.GetChromaticAdaptionWhitePoints(); + pcsTo = VonKriesChromaticAdaptation.Transform(in pcsTo, whitePoints, options.AdaptationMatrix); + + // Convert to output from PCS + return TTo.FromProfileConnectingSpace(options, in pcsTo); + } + + public static void Convert(this ColorProfileConverter converter, ReadOnlySpan source, Span destination) + where TFrom : struct, IColorProfile + where TTo : struct, IColorProfile + { + ColorConversionOptions options = converter.Options; + + // Convert to input PCS. + using IMemoryOwner pcsFromOwner = options.MemoryAllocator.Allocate(source.Length); + Span pcsFrom = pcsFromOwner.GetSpan(); + TFrom.ToProfileConnectionSpace(options, source, pcsFrom); + + // Convert between PCS. + using IMemoryOwner pcsToOwner = options.MemoryAllocator.Allocate(source.Length); + Span pcsTo = pcsToOwner.GetSpan(); + CieLab.ToProfileConnectionSpace(options, pcsFrom, pcsTo); + + // Adapt to target white point + (CieXyz From, CieXyz To) whitePoints = converter.GetChromaticAdaptionWhitePoints(); + VonKriesChromaticAdaptation.Transform(pcsTo, pcsTo, whitePoints, options.AdaptationMatrix); + + // Convert to output from PCS + TTo.FromProfileConnectionSpace(options, pcsTo, destination); + } +} diff --git a/src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsCieLabRgb.cs b/src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsCieLabRgb.cs new file mode 100644 index 0000000000..47e4d2a80a --- /dev/null +++ b/src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsCieLabRgb.cs @@ -0,0 +1,59 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Buffers; +using SixLabors.ImageSharp.Memory; + +namespace SixLabors.ImageSharp.ColorProfiles; + +internal static class ColorProfileConverterExtensionsCieLabRgb +{ + public static TTo Convert(this ColorProfileConverter converter, in TFrom source) + where TFrom : struct, IColorProfile + where TTo : struct, IColorProfile + { + ColorConversionOptions options = converter.Options; + + // Convert to input PCS + CieLab pcsFromA = source.ToProfileConnectingSpace(options); + CieXyz pcsFromB = pcsFromA.ToProfileConnectingSpace(options); + + // Adapt to target white point + (CieXyz From, CieXyz To) whitePoints = converter.GetChromaticAdaptionWhitePoints(); + pcsFromB = VonKriesChromaticAdaptation.Transform(in pcsFromB, whitePoints, options.AdaptationMatrix); + + // Convert between PCS + Rgb pcsTo = Rgb.FromProfileConnectingSpace(options, in pcsFromB); + + // Convert to output from PCS + return TTo.FromProfileConnectingSpace(options, in pcsTo); + } + + public static void Convert(this ColorProfileConverter converter, ReadOnlySpan source, Span destination) + where TFrom : struct, IColorProfile + where TTo : struct, IColorProfile + { + ColorConversionOptions options = converter.Options; + + // Convert to input PCS. + using IMemoryOwner pcsFromAOwner = options.MemoryAllocator.Allocate(source.Length); + Span pcsFromA = pcsFromAOwner.GetSpan(); + TFrom.ToProfileConnectionSpace(options, source, pcsFromA); + + using IMemoryOwner pcsFromBOwner = options.MemoryAllocator.Allocate(source.Length); + Span pcsFromB = pcsFromBOwner.GetSpan(); + CieLab.ToProfileConnectionSpace(options, pcsFromA, pcsFromB); + + // Adapt to target white point + (CieXyz From, CieXyz To) whitePoints = converter.GetChromaticAdaptionWhitePoints(); + VonKriesChromaticAdaptation.Transform(pcsFromB, pcsFromB, whitePoints, options.AdaptationMatrix); + + // Convert between PCS. + using IMemoryOwner pcsToOwner = options.MemoryAllocator.Allocate(source.Length); + Span pcsTo = pcsToOwner.GetSpan(); + Rgb.FromProfileConnectionSpace(options, pcsFromB, pcsTo); + + // Convert to output from PCS + TTo.FromProfileConnectionSpace(options, pcsTo, destination); + } +} diff --git a/src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsCieXyzCieLab.cs b/src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsCieXyzCieLab.cs new file mode 100644 index 0000000000..6b1575d04c --- /dev/null +++ b/src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsCieXyzCieLab.cs @@ -0,0 +1,54 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Buffers; +using SixLabors.ImageSharp.Memory; + +namespace SixLabors.ImageSharp.ColorProfiles; + +internal static class ColorProfileConverterExtensionsCieXyzCieLab +{ + public static TTo Convert(this ColorProfileConverter converter, in TFrom source) + where TFrom : struct, IColorProfile + where TTo : struct, IColorProfile + { + ColorConversionOptions options = converter.Options; + + // Convert to input PCS + CieXyz pcsFrom = source.ToProfileConnectingSpace(options); + + // Adapt to target white point + (CieXyz From, CieXyz To) whitePoints = converter.GetChromaticAdaptionWhitePoints(); + pcsFrom = VonKriesChromaticAdaptation.Transform(in pcsFrom, whitePoints, options.AdaptationMatrix); + + // Convert between PCS + CieLab pcsTo = CieLab.FromProfileConnectingSpace(options, in pcsFrom); + + // Convert to output from PCS + return TTo.FromProfileConnectingSpace(options, in pcsTo); + } + + public static void Convert(this ColorProfileConverter converter, ReadOnlySpan source, Span destination) + where TFrom : struct, IColorProfile + where TTo : struct, IColorProfile + { + ColorConversionOptions options = converter.Options; + + // Convert to input PCS. + using IMemoryOwner pcsFromOwner = options.MemoryAllocator.Allocate(source.Length); + Span pcsFrom = pcsFromOwner.GetSpan(); + TFrom.ToProfileConnectionSpace(options, source, pcsFrom); + + // Adapt to target white point + (CieXyz From, CieXyz To) whitePoints = converter.GetChromaticAdaptionWhitePoints(); + VonKriesChromaticAdaptation.Transform(pcsFrom, pcsFrom, whitePoints, options.AdaptationMatrix); + + // Convert between PCS. + using IMemoryOwner pcsToOwner = options.MemoryAllocator.Allocate(source.Length); + Span pcsTo = pcsToOwner.GetSpan(); + CieLab.FromProfileConnectionSpace(options, pcsFrom, pcsTo); + + // Convert to output from PCS + TTo.FromProfileConnectionSpace(options, pcsTo, destination); + } +} diff --git a/src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsCieXyzCieXyz.cs b/src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsCieXyzCieXyz.cs new file mode 100644 index 0000000000..8f56a5a663 --- /dev/null +++ b/src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsCieXyzCieXyz.cs @@ -0,0 +1,46 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Buffers; +using SixLabors.ImageSharp.Memory; + +namespace SixLabors.ImageSharp.ColorProfiles; + +internal static class ColorProfileConverterExtensionsCieXyzCieXyz +{ + public static TTo Convert(this ColorProfileConverter converter, in TFrom source) + where TFrom : struct, IColorProfile + where TTo : struct, IColorProfile + { + ColorConversionOptions options = converter.Options; + + // Convert to input PCS + CieXyz pcsFrom = source.ToProfileConnectingSpace(options); + + // Adapt to target white point + (CieXyz From, CieXyz To) whitePoints = converter.GetChromaticAdaptionWhitePoints(); + pcsFrom = VonKriesChromaticAdaptation.Transform(in pcsFrom, whitePoints, options.AdaptationMatrix); + + // Convert to output from PCS + return TTo.FromProfileConnectingSpace(options, in pcsFrom); + } + + public static void Convert(this ColorProfileConverter converter, ReadOnlySpan source, Span destination) + where TFrom : struct, IColorProfile + where TTo : struct, IColorProfile + { + ColorConversionOptions options = converter.Options; + + // Convert to input PCS. + using IMemoryOwner pcsFromOwner = options.MemoryAllocator.Allocate(source.Length); + Span pcsFrom = pcsFromOwner.GetSpan(); + TFrom.ToProfileConnectionSpace(options, source, pcsFrom); + + // Adapt to target white point + (CieXyz From, CieXyz To) whitePoints = converter.GetChromaticAdaptionWhitePoints(); + VonKriesChromaticAdaptation.Transform(pcsFrom, pcsFrom, whitePoints, options.AdaptationMatrix); + + // Convert to output from PCS + TTo.FromProfileConnectionSpace(options, pcsFrom, destination); + } +} diff --git a/src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsCieXyzRgb.cs b/src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsCieXyzRgb.cs new file mode 100644 index 0000000000..9cc0bd9436 --- /dev/null +++ b/src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsCieXyzRgb.cs @@ -0,0 +1,54 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Buffers; +using SixLabors.ImageSharp.Memory; + +namespace SixLabors.ImageSharp.ColorProfiles; + +internal static class ColorProfileConverterExtensionsCieXyzRgb +{ + public static TTo Convert(this ColorProfileConverter converter, in TFrom source) + where TFrom : struct, IColorProfile + where TTo : struct, IColorProfile + { + ColorConversionOptions options = converter.Options; + + // Convert to input PCS + CieXyz pcsFrom = source.ToProfileConnectingSpace(options); + + // Adapt to target white point + (CieXyz From, CieXyz To) whitePoints = converter.GetChromaticAdaptionWhitePoints(); + pcsFrom = VonKriesChromaticAdaptation.Transform(in pcsFrom, whitePoints, options.AdaptationMatrix); + + // Convert between PCS + Rgb pcsTo = Rgb.FromProfileConnectingSpace(options, in pcsFrom); + + // Convert to output from PCS + return TTo.FromProfileConnectingSpace(options, in pcsTo); + } + + public static void Convert(this ColorProfileConverter converter, ReadOnlySpan source, Span destination) + where TFrom : struct, IColorProfile + where TTo : struct, IColorProfile + { + ColorConversionOptions options = converter.Options; + + // Convert to input PCS. + using IMemoryOwner pcsFromOwner = options.MemoryAllocator.Allocate(source.Length); + Span pcsFrom = pcsFromOwner.GetSpan(); + TFrom.ToProfileConnectionSpace(options, source, pcsFrom); + + // Adapt to target white point + (CieXyz From, CieXyz To) whitePoints = converter.GetChromaticAdaptionWhitePoints(); + VonKriesChromaticAdaptation.Transform(pcsFrom, pcsFrom, whitePoints, options.AdaptationMatrix); + + // Convert between PCS. + using IMemoryOwner pcsToOwner = options.MemoryAllocator.Allocate(source.Length); + Span pcsTo = pcsToOwner.GetSpan(); + Rgb.FromProfileConnectionSpace(options, pcsFrom, pcsTo); + + // Convert to output from PCS + TTo.FromProfileConnectionSpace(options, pcsTo, destination); + } +} diff --git a/src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsRgbCieLab.cs b/src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsRgbCieLab.cs new file mode 100644 index 0000000000..415dd94c3f --- /dev/null +++ b/src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsRgbCieLab.cs @@ -0,0 +1,59 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Buffers; +using SixLabors.ImageSharp.Memory; + +namespace SixLabors.ImageSharp.ColorProfiles; + +internal static class ColorProfileConverterExtensionsRgbCieLab +{ + public static TTo Convert(this ColorProfileConverter converter, in TFrom source) + where TFrom : struct, IColorProfile + where TTo : struct, IColorProfile + { + ColorConversionOptions options = converter.Options; + + // Convert to input PCS + Rgb pcsFromA = source.ToProfileConnectingSpace(options); + CieXyz pcsFromB = pcsFromA.ToProfileConnectingSpace(options); + + // Adapt to target white point + (CieXyz From, CieXyz To) whitePoints = converter.GetChromaticAdaptionWhitePoints(); + pcsFromB = VonKriesChromaticAdaptation.Transform(in pcsFromB, whitePoints, options.AdaptationMatrix); + + // Convert between PCS + CieLab pcsTo = CieLab.FromProfileConnectingSpace(options, in pcsFromB); + + // Convert to output from PCS + return TTo.FromProfileConnectingSpace(options, in pcsTo); + } + + public static void Convert(this ColorProfileConverter converter, ReadOnlySpan source, Span destination) + where TFrom : struct, IColorProfile + where TTo : struct, IColorProfile + { + ColorConversionOptions options = converter.Options; + + // Convert to input PCS. + using IMemoryOwner pcsFromAOwner = options.MemoryAllocator.Allocate(source.Length); + Span pcsFromA = pcsFromAOwner.GetSpan(); + TFrom.ToProfileConnectionSpace(options, source, pcsFromA); + + using IMemoryOwner pcsFromBOwner = options.MemoryAllocator.Allocate(source.Length); + Span pcsFromB = pcsFromBOwner.GetSpan(); + Rgb.ToProfileConnectionSpace(options, pcsFromA, pcsFromB); + + // Adapt to target white point + (CieXyz From, CieXyz To) whitePoints = converter.GetChromaticAdaptionWhitePoints(); + VonKriesChromaticAdaptation.Transform(pcsFromB, pcsFromB, whitePoints, options.AdaptationMatrix); + + // Convert between PCS. + using IMemoryOwner pcsToOwner = options.MemoryAllocator.Allocate(source.Length); + Span pcsTo = pcsToOwner.GetSpan(); + CieLab.FromProfileConnectionSpace(options, pcsFromB, pcsTo); + + // Convert to output from PCS + TTo.FromProfileConnectionSpace(options, pcsTo, destination); + } +} diff --git a/src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsRgbCieXyz.cs b/src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsRgbCieXyz.cs new file mode 100644 index 0000000000..a13f645778 --- /dev/null +++ b/src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsRgbCieXyz.cs @@ -0,0 +1,54 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Buffers; +using SixLabors.ImageSharp.Memory; + +namespace SixLabors.ImageSharp.ColorProfiles; + +internal static class ColorProfileConverterExtensionsRgbCieXyz +{ + public static TTo Convert(this ColorProfileConverter converter, in TFrom source) + where TFrom : struct, IColorProfile + where TTo : struct, IColorProfile + { + ColorConversionOptions options = converter.Options; + + // Convert to input PCS + Rgb pcsFrom = source.ToProfileConnectingSpace(options); + + // Convert between PCS + CieXyz pcsTo = pcsFrom.ToProfileConnectingSpace(options); + + // Adapt to target white point + (CieXyz From, CieXyz To) whitePoints = converter.GetChromaticAdaptionWhitePoints(); + pcsTo = VonKriesChromaticAdaptation.Transform(in pcsTo, whitePoints, options.AdaptationMatrix); + + // Convert to output from PCS + return TTo.FromProfileConnectingSpace(options, in pcsTo); + } + + public static void Convert(this ColorProfileConverter converter, ReadOnlySpan source, Span destination) + where TFrom : struct, IColorProfile + where TTo : struct, IColorProfile + { + ColorConversionOptions options = converter.Options; + + // Convert to input PCS. + using IMemoryOwner pcsFromOwner = options.MemoryAllocator.Allocate(source.Length); + Span pcsFrom = pcsFromOwner.GetSpan(); + TFrom.ToProfileConnectionSpace(options, source, pcsFrom); + + // Convert between PCS. + using IMemoryOwner pcsToOwner = options.MemoryAllocator.Allocate(source.Length); + Span pcsTo = pcsToOwner.GetSpan(); + Rgb.ToProfileConnectionSpace(options, pcsFrom, pcsTo); + + // Adapt to target white point + (CieXyz From, CieXyz To) whitePoints = converter.GetChromaticAdaptionWhitePoints(); + VonKriesChromaticAdaptation.Transform(pcsTo, pcsTo, whitePoints, options.AdaptationMatrix); + + // Convert to output from PCS + TTo.FromProfileConnectionSpace(options, pcsTo, destination); + } +} diff --git a/src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsRgbRgb.cs b/src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsRgbRgb.cs new file mode 100644 index 0000000000..c1c75dea1b --- /dev/null +++ b/src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsRgbRgb.cs @@ -0,0 +1,57 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Buffers; +using SixLabors.ImageSharp.Memory; + +namespace SixLabors.ImageSharp.ColorProfiles; + +internal static class ColorProfileConverterExtensionsRgbRgb +{ + public static TTo Convert(this ColorProfileConverter converter, in TFrom source) + where TFrom : struct, IColorProfile + where TTo : struct, IColorProfile + { + ColorConversionOptions options = converter.Options; + + // Convert to input PCS + Rgb pcsFromA = source.ToProfileConnectingSpace(options); + CieXyz pcsFromB = pcsFromA.ToProfileConnectingSpace(options); + + // Adapt to target white point + (CieXyz From, CieXyz To) whitePoints = converter.GetChromaticAdaptionWhitePoints(); + pcsFromB = VonKriesChromaticAdaptation.Transform(in pcsFromB, whitePoints, options.AdaptationMatrix); + + // Convert between PCS + Rgb pcsTo = Rgb.FromProfileConnectingSpace(options, in pcsFromB); + + // Convert to output from PCS + return TTo.FromProfileConnectingSpace(options, in pcsTo); + } + + public static void Convert(this ColorProfileConverter converter, ReadOnlySpan source, Span destination) + where TFrom : struct, IColorProfile + where TTo : struct, IColorProfile + { + ColorConversionOptions options = converter.Options; + + // Convert to input PCS. + using IMemoryOwner pcsFromToOwner = options.MemoryAllocator.Allocate(source.Length); + Span pcsFromTo = pcsFromToOwner.GetSpan(); + TFrom.ToProfileConnectionSpace(options, source, pcsFromTo); + + using IMemoryOwner pcsFromOwner = options.MemoryAllocator.Allocate(source.Length); + Span pcsFrom = pcsFromOwner.GetSpan(); + Rgb.ToProfileConnectionSpace(options, pcsFromTo, pcsFrom); + + // Adapt to target white point + (CieXyz From, CieXyz To) whitePoints = converter.GetChromaticAdaptionWhitePoints(); + VonKriesChromaticAdaptation.Transform(pcsFrom, pcsFrom, whitePoints, options.AdaptationMatrix); + + // Convert between PCS. + Rgb.FromProfileConnectionSpace(options, pcsFrom, pcsFromTo); + + // Convert to output from PCS + TTo.FromProfileConnectionSpace(options, pcsFromTo, destination); + } +} diff --git a/src/ImageSharp/ColorProfiles/Companding/CompandingUtilities.cs b/src/ImageSharp/ColorProfiles/Companding/CompandingUtilities.cs new file mode 100644 index 0000000000..1970e2d949 --- /dev/null +++ b/src/ImageSharp/ColorProfiles/Companding/CompandingUtilities.cs @@ -0,0 +1,182 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Collections.Concurrent; +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; + +namespace SixLabors.ImageSharp.ColorProfiles.Companding; + +/// +/// Companding utilities that allow the accelerated compression-expansion of color channels. +/// +public static class CompandingUtilities +{ + private const int Length = Scale + 2; // 256kb @ 16bit precision. + private const int Scale = (1 << 16) - 1; + private static readonly ConcurrentDictionary<(Type, double), float[]> CompressLookupTables = new(); + private static readonly ConcurrentDictionary<(Type, double), float[]> ExpandLookupTables = new(); + + /// + /// Lazily creates and stores a companding compression lookup table using the given function and modifier. + /// + /// The type of companding function. + /// The companding function. + /// A modifier to pass to the function. + /// The array. + public static float[] GetCompressLookupTable(Func compandingFunction, double modifier = 0) + => CompressLookupTables.GetOrAdd((typeof(T), modifier), args => CreateLookupTableImpl(compandingFunction, args.Item2)); + + /// + /// Lazily creates and stores a companding expanding lookup table using the given function and modifier. + /// + /// The type of companding function. + /// The companding function. + /// A modifier to pass to the function. + /// The array. + public static float[] GetExpandLookupTable(Func compandingFunction, double modifier = 0) + => ExpandLookupTables.GetOrAdd((typeof(T), modifier), args => CreateLookupTableImpl(compandingFunction, args.Item2)); + + /// + /// Creates a companding lookup table using the given function. + /// + /// The companding function. + /// A modifier to pass to the function. + /// The array. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static float[] CreateLookupTableImpl(Func compandingFunction, double modifier = 0) + { + float[] result = new float[Length]; + + for (int i = 0; i < result.Length; i++) + { + double d = (double)i / Scale; + d = compandingFunction(d, modifier); + result[i] = (float)d; + } + + return result; + } + + /// + /// Performs the companding operation on the given vectors using the given table. + /// + /// The span of vectors. + /// The lookup table. + public static void Compand(Span vectors, float[] table) + { + DebugGuard.MustBeGreaterThanOrEqualTo(table.Length, Length, nameof(table)); + + if (Avx2.IsSupported && vectors.Length >= 2) + { + CompandAvx2(vectors, table); + + if (Numerics.Modulo2(vectors.Length) != 0) + { + // Vector4 fits neatly in pairs. Any overlap has to be equal to 1. + ref Vector4 last = ref MemoryMarshal.GetReference(vectors[^1..]); + last = Compand(last, table); + } + } + else + { + CompandScalar(vectors, table); + } + } + + /// + /// Performs the companding operation on the given vector using the given table. + /// + /// The vector. + /// The lookup table. + /// The + public static Vector4 Compand(Vector4 vector, float[] table) + { + DebugGuard.MustBeGreaterThanOrEqualTo(table.Length, Length, nameof(table)); + + Vector4 zero = Vector4.Zero; + Vector4 scale = new(Scale); + + Vector4 multiplied = Numerics.Clamp(vector * Scale, zero, scale); + + float f0 = multiplied.X; + float f1 = multiplied.Y; + float f2 = multiplied.Z; + + uint i0 = (uint)f0; + uint i1 = (uint)f1; + uint i2 = (uint)f2; + + // Alpha is already a linear representation of opacity so we do not want to convert it. + vector.X = Numerics.Lerp(table[i0], table[i0 + 1], f0 - (int)i0); + vector.Y = Numerics.Lerp(table[i1], table[i1 + 1], f1 - (int)i1); + vector.Z = Numerics.Lerp(table[i2], table[i2 + 1], f2 - (int)i2); + + return vector; + } + + private static unsafe void CompandAvx2(Span vectors, float[] table) + { + fixed (float* tablePointer = &MemoryMarshal.GetArrayDataReference(table)) + { + Vector256 scale = Vector256.Create((float)Scale); + Vector256 zero = Vector256.Zero; + Vector256 offset = Vector256.Create(1); + + // Divide by 2 as 4 elements per Vector4 and 8 per Vector256 + ref Vector256 vectorsBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(vectors)); + ref Vector256 vectorsLast = ref Unsafe.Add(ref vectorsBase, (uint)vectors.Length / 2u); + + while (Unsafe.IsAddressLessThan(ref vectorsBase, ref vectorsLast)) + { + Vector256 multiplied = Avx.Multiply(scale, vectorsBase); + multiplied = Avx.Min(Avx.Max(zero, multiplied), scale); + + Vector256 truncated = Avx.ConvertToVector256Int32WithTruncation(multiplied); + Vector256 truncatedF = Avx.ConvertToVector256Single(truncated); + + Vector256 low = Avx2.GatherVector256(tablePointer, truncated, sizeof(float)); + Vector256 high = Avx2.GatherVector256(tablePointer, Avx2.Add(truncated, offset), sizeof(float)); + + // Alpha is already a linear representation of opacity so we do not want to convert it. + Vector256 companded = Numerics.Lerp(low, high, Avx.Subtract(multiplied, truncatedF)); + vectorsBase = Avx.Blend(companded, vectorsBase, Numerics.BlendAlphaControl); + vectorsBase = ref Unsafe.Add(ref vectorsBase, 1); + } + } + } + + private static unsafe void CompandScalar(Span vectors, float[] table) + { + fixed (float* tablePointer = &MemoryMarshal.GetArrayDataReference(table)) + { + Vector4 zero = Vector4.Zero; + Vector4 scale = new(Scale); + ref Vector4 vectorsBase = ref MemoryMarshal.GetReference(vectors); + ref Vector4 vectorsLast = ref Unsafe.Add(ref vectorsBase, (uint)vectors.Length); + + while (Unsafe.IsAddressLessThan(ref vectorsBase, ref vectorsLast)) + { + Vector4 multiplied = Numerics.Clamp(vectorsBase * Scale, zero, scale); + + float f0 = multiplied.X; + float f1 = multiplied.Y; + float f2 = multiplied.Z; + + uint i0 = (uint)f0; + uint i1 = (uint)f1; + uint i2 = (uint)f2; + + // Alpha is already a linear representation of opacity so we do not want to convert it. + vectorsBase.X = Numerics.Lerp(tablePointer[i0], tablePointer[i0 + 1], f0 - (int)i0); + vectorsBase.Y = Numerics.Lerp(tablePointer[i1], tablePointer[i1 + 1], f1 - (int)i1); + vectorsBase.Z = Numerics.Lerp(tablePointer[i2], tablePointer[i2 + 1], f2 - (int)i2); + + vectorsBase = ref Unsafe.Add(ref vectorsBase, 1); + } + } + } +} diff --git a/src/ImageSharp/ColorProfiles/Companding/GammaCompanding.cs b/src/ImageSharp/ColorProfiles/Companding/GammaCompanding.cs new file mode 100644 index 0000000000..34ca8bf5e3 --- /dev/null +++ b/src/ImageSharp/ColorProfiles/Companding/GammaCompanding.cs @@ -0,0 +1,56 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Numerics; + +namespace SixLabors.ImageSharp.ColorProfiles.Companding; + +/// +/// Implements gamma companding. +/// +/// +/// +/// +/// +public static class GammaCompanding +{ + private static Func CompressFunction => (d, m) => Math.Pow(d, 1 / m); + + private static Func ExpandFunction => Math.Pow; + + /// + /// Compresses the linear vectors to their nonlinear equivalents with respect to the energy. + /// + /// The span of vectors. + /// The gamma value. + public static void Compress(Span vectors, double gamma) + => CompandingUtilities.Compand(vectors, CompandingUtilities.GetCompressLookupTable(CompressFunction, gamma)); + + /// + /// Expands the nonlinear vectors to their linear equivalents with respect to the energy. + /// + /// The span of vectors. + /// The gamma value. + public static void Expand(Span vectors, double gamma) + => CompandingUtilities.Compand(vectors, CompandingUtilities.GetExpandLookupTable(ExpandFunction, gamma)); + + /// + /// Compresses the linear vector to its nonlinear equivalent with respect to the energy. + /// + /// The vector. + /// The gamma value. + /// The . + public static Vector4 Compress(Vector4 vector, double gamma) + => CompandingUtilities.Compand(vector, CompandingUtilities.GetCompressLookupTable(CompressFunction, gamma)); + + /// + /// Expands the nonlinear vector to its linear equivalent with respect to the energy. + /// + /// The vector. + /// The gamma value. + /// The . + public static Vector4 Expand(Vector4 vector, double gamma) + => CompandingUtilities.Compand(vector, CompandingUtilities.GetExpandLookupTable(ExpandFunction, gamma)); + + private class GammaCompandingKey; +} diff --git a/src/ImageSharp/ColorProfiles/Companding/LCompanding.cs b/src/ImageSharp/ColorProfiles/Companding/LCompanding.cs new file mode 100644 index 0000000000..4f53830380 --- /dev/null +++ b/src/ImageSharp/ColorProfiles/Companding/LCompanding.cs @@ -0,0 +1,71 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Numerics; + +namespace SixLabors.ImageSharp.ColorProfiles.Companding; + +/// +/// Implements L* companding. +/// +/// +/// For more info see: +/// +/// +/// +public static class LCompanding +{ + private static Func CompressFunction + => (d, _) => + { + if (d <= CieConstants.Epsilon) + { + return (d * CieConstants.Kappa) / 100; + } + + return (1.16 * Math.Pow(d, 0.3333333)) - 0.16; + }; + + private static Func ExpandFunction + => (d, _) => + { + if (d <= 0.08) + { + return (100 * d) / CieConstants.Kappa; + } + + return Numerics.Pow3(((float)(d + 0.16f)) / 1.16f); + }; + + /// + /// Compresses the linear vectors to their nonlinear equivalents with respect to the energy. + /// + /// The span of vectors. + public static void Compress(Span vectors) + => CompandingUtilities.Compand(vectors, CompandingUtilities.GetCompressLookupTable(CompressFunction)); + + /// + /// Expands the nonlinear vectors to their linear equivalents with respect to the energy. + /// + /// The span of vectors. + public static void Expand(Span vectors) + => CompandingUtilities.Compand(vectors, CompandingUtilities.GetExpandLookupTable(ExpandFunction)); + + /// + /// Compresses the linear vector to its nonlinear equivalent with respect to the energy. + /// + /// The vector. + /// The . + public static Vector4 Compress(Vector4 vector) + => CompandingUtilities.Compand(vector, CompandingUtilities.GetCompressLookupTable(CompressFunction)); + + /// + /// Expands the nonlinear vector to its linear equivalent with respect to the energy. + /// + /// The vector. + /// The . + public static Vector4 Expand(Vector4 vector) + => CompandingUtilities.Compand(vector, CompandingUtilities.GetExpandLookupTable(ExpandFunction)); + + private class LCompandingKey; +} diff --git a/src/ImageSharp/ColorProfiles/Companding/Rec2020Companding.cs b/src/ImageSharp/ColorProfiles/Companding/Rec2020Companding.cs new file mode 100644 index 0000000000..1901e64713 --- /dev/null +++ b/src/ImageSharp/ColorProfiles/Companding/Rec2020Companding.cs @@ -0,0 +1,75 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Numerics; + +namespace SixLabors.ImageSharp.ColorProfiles.Companding; + +/// +/// Implements Rec. 2020 companding function. +/// +/// +/// +/// +public static class Rec2020Companding +{ + private const double Alpha = 1.09929682680944; + private const double AlphaMinusOne = Alpha - 1; + private const double Beta = 0.018053968510807; + private const double InverseBeta = Beta * 4.5; + private const double Epsilon = 1 / 0.45; + + private static Func CompressFunction + => (d, _) => + { + if (d < Beta) + { + return 4.5 * d; + } + + return (Alpha * Math.Pow(d, 0.45)) - AlphaMinusOne; + }; + + private static Func ExpandFunction + => (d, _) => + { + if (d < InverseBeta) + { + return d / 4.5; + } + + return Math.Pow((d + AlphaMinusOne) / Alpha, Epsilon); + }; + + /// + /// Compresses the linear vectors to their nonlinear equivalents with respect to the energy. + /// + /// The span of vectors. + public static void Compress(Span vectors) + => CompandingUtilities.Compand(vectors, CompandingUtilities.GetCompressLookupTable(CompressFunction)); + + /// + /// Expands the nonlinear vectors to their linear equivalents with respect to the energy. + /// + /// The span of vectors. + public static void Expand(Span vectors) + => CompandingUtilities.Compand(vectors, CompandingUtilities.GetExpandLookupTable(ExpandFunction)); + + /// + /// Compresses the linear vector to its nonlinear equivalent with respect to the energy. + /// + /// The vector. + /// The . + public static Vector4 Compress(Vector4 vector) + => CompandingUtilities.Compand(vector, CompandingUtilities.GetCompressLookupTable(CompressFunction)); + + /// + /// Expands the nonlinear vector to its linear equivalent with respect to the energy. + /// + /// The vector. + /// The . + public static Vector4 Expand(Vector4 vector) + => CompandingUtilities.Compand(vector, CompandingUtilities.GetExpandLookupTable(ExpandFunction)); + + private class Rec2020CompandingKey; +} diff --git a/src/ImageSharp/ColorProfiles/Companding/Rec709Companding.cs b/src/ImageSharp/ColorProfiles/Companding/Rec709Companding.cs new file mode 100644 index 0000000000..94b17d8d08 --- /dev/null +++ b/src/ImageSharp/ColorProfiles/Companding/Rec709Companding.cs @@ -0,0 +1,71 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Numerics; + +namespace SixLabors.ImageSharp.ColorProfiles.Companding; + +/// +/// Implements the Rec. 709 companding function. +/// +/// +/// http://en.wikipedia.org/wiki/Rec._709 +/// +public static class Rec709Companding +{ + private const double Epsilon = 1 / 0.45; + + private static Func CompressFunction + => (d, _) => + { + if (d < 0.018) + { + return 4.5 * d; + } + + return (1.099 * Math.Pow(d, 0.45)) - 0.099; + }; + + private static Func ExpandFunction + => (d, _) => + { + if (d < 0.081) + { + return d / 4.5; + } + + return Math.Pow((d + 0.099) / 1.099, Epsilon); + }; + + /// + /// Compresses the linear vectors to their nonlinear equivalents with respect to the energy. + /// + /// The span of vectors. + public static void Compress(Span vectors) + => CompandingUtilities.Compand(vectors, CompandingUtilities.GetCompressLookupTable(CompressFunction)); + + /// + /// Expands the nonlinear vectors to their linear equivalents with respect to the energy. + /// + /// The span of vectors. + public static void Expand(Span vectors) + => CompandingUtilities.Compand(vectors, CompandingUtilities.GetExpandLookupTable(ExpandFunction)); + + /// + /// Compresses the linear vector to its nonlinear equivalent with respect to the energy. + /// + /// The vector. + /// The . + public static Vector4 Compress(Vector4 vector) + => CompandingUtilities.Compand(vector, CompandingUtilities.GetCompressLookupTable(CompressFunction)); + + /// + /// Expands the nonlinear vector to its linear equivalent with respect to the energy. + /// + /// The vector. + /// The . + public static Vector4 Expand(Vector4 vector) + => CompandingUtilities.Compand(vector, CompandingUtilities.GetExpandLookupTable(ExpandFunction)); + + private class Rec2020CompandingKey; +} diff --git a/src/ImageSharp/ColorProfiles/Companding/SRgbCompanding.cs b/src/ImageSharp/ColorProfiles/Companding/SRgbCompanding.cs new file mode 100644 index 0000000000..ab27102306 --- /dev/null +++ b/src/ImageSharp/ColorProfiles/Companding/SRgbCompanding.cs @@ -0,0 +1,71 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Numerics; + +namespace SixLabors.ImageSharp.ColorProfiles.Companding; + +/// +/// Implements sRGB companding. +/// +/// +/// For more info see: +/// +/// +/// +public static class SRgbCompanding +{ + private static Func CompressFunction + => (d, _) => + { + if (d <= (0.04045 / 12.92)) + { + return d * 12.92; + } + + return (1.055 * Math.Pow(d, 1.0 / 2.4)) - 0.055; + }; + + private static Func ExpandFunction + => (d, _) => + { + if (d <= 0.04045) + { + return d / 12.92; + } + + return Math.Pow((d + 0.055) / 1.055, 2.4); + }; + + /// + /// Compresses the linear vectors to their nonlinear equivalents with respect to the energy. + /// + /// The span of vectors. + public static void Compress(Span vectors) + => CompandingUtilities.Compand(vectors, CompandingUtilities.GetCompressLookupTable(CompressFunction)); + + /// + /// Expands the nonlinear vectors to their linear equivalents with respect to the energy. + /// + /// The span of vectors. + public static void Expand(Span vectors) + => CompandingUtilities.Compand(vectors, CompandingUtilities.GetExpandLookupTable(ExpandFunction)); + + /// + /// Compresses the linear vector to its nonlinear equivalent with respect to the energy. + /// + /// The vector. + /// The . + public static Vector4 Compress(Vector4 vector) + => CompandingUtilities.Compand(vector, CompandingUtilities.GetCompressLookupTable(CompressFunction)); + + /// + /// Expands the nonlinear vector to its linear equivalent with respect to the energy. + /// + /// The vector. + /// The . + public static Vector4 Expand(Vector4 vector) + => CompandingUtilities.Compand(vector, CompandingUtilities.GetExpandLookupTable(ExpandFunction)); + + private class SRgbCompandingKey; +} diff --git a/src/ImageSharp/ColorProfiles/Hsl.cs b/src/ImageSharp/ColorProfiles/Hsl.cs new file mode 100644 index 0000000000..2c98c7df99 --- /dev/null +++ b/src/ImageSharp/ColorProfiles/Hsl.cs @@ -0,0 +1,245 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace SixLabors.ImageSharp.ColorProfiles; + +/// +/// Represents a Hsl (hue, saturation, lightness) color. +/// +[StructLayout(LayoutKind.Sequential)] +public readonly struct Hsl : IColorProfile +{ + private static readonly Vector3 Min = Vector3.Zero; + private static readonly Vector3 Max = new(360, 1, 1); + + /// + /// Initializes a new instance of the struct. + /// + /// The h hue component. + /// The s saturation component. + /// The l value (lightness) component. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Hsl(float h, float s, float l) + : this(new Vector3(h, s, l)) + { + } + + /// + /// Initializes a new instance of the struct. + /// + /// The vector representing the h, s, l components. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Hsl(Vector3 vector) + { + vector = Vector3.Clamp(vector, Min, Max); + this.H = vector.X; + this.S = vector.Y; + this.L = vector.Z; + } + + /// + /// Gets the hue component. + /// A value ranging between 0 and 360. + /// + public float H { get; } + + /// + /// Gets the saturation component. + /// A value ranging between 0 and 1. + /// + public float S { get; } + + /// + /// Gets the lightness component. + /// A value ranging between 0 and 1. + /// + public float L { get; } + + /// + /// Compares two objects for equality. + /// + /// + /// The on the left side of the operand. + /// + /// The on the right side of the operand. + /// + /// True if the current left is equal to the parameter; otherwise, false. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator ==(Hsl left, Hsl right) => left.Equals(right); + + /// + /// Compares two objects for inequality. + /// + /// The on the left side of the operand. + /// The on the right side of the operand. + /// + /// True if the current left is unequal to the parameter; otherwise, false. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator !=(Hsl left, Hsl right) => !left.Equals(right); + + /// + public static Hsl FromProfileConnectingSpace(ColorConversionOptions options, in Rgb source) + { + float r = source.R; + float g = source.G; + float b = source.B; + + float max = MathF.Max(r, MathF.Max(g, b)); + float min = MathF.Min(r, MathF.Min(g, b)); + float chroma = max - min; + float h = 0F; + float s = 0F; + float l = (max + min) / 2F; + + if (MathF.Abs(chroma) < Constants.Epsilon) + { + return new Hsl(0F, s, l); + } + + if (MathF.Abs(r - max) < Constants.Epsilon) + { + h = (g - b) / chroma; + } + else if (MathF.Abs(g - max) < Constants.Epsilon) + { + h = 2F + ((b - r) / chroma); + } + else if (MathF.Abs(b - max) < Constants.Epsilon) + { + h = 4F + ((r - g) / chroma); + } + + h *= 60F; + if (h < -Constants.Epsilon) + { + h += 360F; + } + + if (l <= .5F) + { + s = chroma / (max + min); + } + else + { + s = chroma / (2F - max - min); + } + + return new Hsl(h, s, l); + } + + /// + public static void FromProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan source, Span destination) + { + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + for (int i = 0; i < source.Length; i++) + { + Rgb rgb = source[i]; + destination[i] = FromProfileConnectingSpace(options, in rgb); + } + } + + /// + public Rgb ToProfileConnectingSpace(ColorConversionOptions options) + { + float rangedH = this.H / 360F; + float r = 0; + float g = 0; + float b = 0; + float s = this.S; + float l = this.L; + + if (MathF.Abs(l) > Constants.Epsilon) + { + if (MathF.Abs(s) < Constants.Epsilon) + { + r = g = b = l; + } + else + { + float temp2 = (l < .5F) ? l * (1F + s) : l + s - (l * s); + float temp1 = (2F * l) - temp2; + + r = GetColorComponent(temp1, temp2, rangedH + 0.3333333F); + g = GetColorComponent(temp1, temp2, rangedH); + b = GetColorComponent(temp1, temp2, rangedH - 0.3333333F); + } + } + + return new Rgb(r, g, b); + } + + /// + public static void ToProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan source, Span destination) + { + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + for (int i = 0; i < source.Length; i++) + { + Hsl hsl = source[i]; + destination[i] = hsl.ToProfileConnectingSpace(options); + } + } + + /// + public static ChromaticAdaptionWhitePointSource GetChromaticAdaptionWhitePointSource() + => ChromaticAdaptionWhitePointSource.RgbWorkingSpace; + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override int GetHashCode() => HashCode.Combine(this.H, this.S, this.L); + + /// + public override string ToString() => FormattableString.Invariant($"Hsl({this.H:#0.##}, {this.S:#0.##}, {this.L:#0.##})"); + + /// + public override bool Equals(object? obj) => obj is Hsl other && this.Equals(other); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Equals(Hsl other) + => this.AsVector3Unsafe() == other.AsVector3Unsafe(); + + private Vector3 AsVector3Unsafe() => Unsafe.As(ref Unsafe.AsRef(in this)); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static float GetColorComponent(float first, float second, float third) + { + third = MoveIntoRange(third); + if (third < 0.1666667F) + { + return first + ((second - first) * 6F * third); + } + + if (third < .5F) + { + return second; + } + + if (third < 0.6666667F) + { + return first + ((second - first) * (0.6666667F - third) * 6F); + } + + return first; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static float MoveIntoRange(float value) + { + if (value < 0F) + { + value++; + } + else if (value > 1F) + { + value--; + } + + return value; + } +} diff --git a/src/ImageSharp/ColorProfiles/Hsv.cs b/src/ImageSharp/ColorProfiles/Hsv.cs new file mode 100644 index 0000000000..7535f2463d --- /dev/null +++ b/src/ImageSharp/ColorProfiles/Hsv.cs @@ -0,0 +1,231 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace SixLabors.ImageSharp.ColorProfiles; + +/// +/// Represents a HSV (hue, saturation, value) color. Also known as HSB (hue, saturation, brightness). +/// +[StructLayout(LayoutKind.Sequential)] +public readonly struct Hsv : IColorProfile +{ + private static readonly Vector3 Min = Vector3.Zero; + private static readonly Vector3 Max = new(360, 1, 1); + + /// + /// Initializes a new instance of the struct. + /// + /// The h hue component. + /// The s saturation component. + /// The v value (brightness) component. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Hsv(float h, float s, float v) + : this(new Vector3(h, s, v)) + { + } + + /// + /// Initializes a new instance of the struct. + /// + /// The vector representing the h, s, v components. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Hsv(Vector3 vector) + { + vector = Vector3.Clamp(vector, Min, Max); + this.H = vector.X; + this.S = vector.Y; + this.V = vector.Z; + } + + /// + /// Gets the hue component. + /// A value ranging between 0 and 360. + /// + public float H { get; } + + /// + /// Gets the saturation component. + /// A value ranging between 0 and 1. + /// + public float S { get; } + + /// + /// Gets the value (brightness) component. + /// A value ranging between 0 and 1. + /// + public float V { get; } + + /// + /// Compares two objects for equality. + /// + /// The on the left side of the operand. + /// The on the right side of the operand. + /// + /// True if the current left is equal to the parameter; otherwise, false. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator ==(Hsv left, Hsv right) => left.Equals(right); + + /// + /// Compares two objects for inequality. + /// + /// The on the left side of the operand. + /// The on the right side of the operand. + /// + /// True if the current left is unequal to the parameter; otherwise, false. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator !=(Hsv left, Hsv right) => !left.Equals(right); + + /// + public static Hsv FromProfileConnectingSpace(ColorConversionOptions options, in Rgb source) + { + float r = source.R; + float g = source.G; + float b = source.B; + + float max = MathF.Max(r, MathF.Max(g, b)); + float min = MathF.Min(r, MathF.Min(g, b)); + float chroma = max - min; + float h = 0; + float s = 0; + float v = max; + + if (MathF.Abs(chroma) < Constants.Epsilon) + { + return new Hsv(0, s, v); + } + + if (MathF.Abs(r - max) < Constants.Epsilon) + { + h = (g - b) / chroma; + } + else if (MathF.Abs(g - max) < Constants.Epsilon) + { + h = 2 + ((b - r) / chroma); + } + else if (MathF.Abs(b - max) < Constants.Epsilon) + { + h = 4 + ((r - g) / chroma); + } + + h *= 60F; + if (h < -Constants.Epsilon) + { + h += 360F; + } + + s = chroma / v; + + return new Hsv(h, s, v); + } + + /// + public static void FromProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan source, Span destination) + { + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + for (int i = 0; i < source.Length; i++) + { + Rgb rgb = source[i]; + destination[i] = FromProfileConnectingSpace(options, in rgb); + } + } + + /// + public Rgb ToProfileConnectingSpace(ColorConversionOptions options) + { + float s = this.S; + float v = this.V; + + if (MathF.Abs(s) < Constants.Epsilon) + { + return new Rgb(v, v, v); + } + + float h = (MathF.Abs(this.H - 360) < Constants.Epsilon) ? 0 : this.H / 60; + int i = (int)Math.Truncate(h); + float f = h - i; + + float p = v * (1F - s); + float q = v * (1F - (s * f)); + float t = v * (1F - (s * (1F - f))); + + float r, g, b; + switch (i) + { + case 0: + r = v; + g = t; + b = p; + break; + + case 1: + r = q; + g = v; + b = p; + break; + + case 2: + r = p; + g = v; + b = t; + break; + + case 3: + r = p; + g = q; + b = v; + break; + + case 4: + r = t; + g = p; + b = v; + break; + + default: + r = v; + g = p; + b = q; + break; + } + + return new Rgb(r, g, b); + } + + /// + public static void ToProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan source, Span destination) + { + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + for (int i = 0; i < source.Length; i++) + { + Hsv hsv = source[i]; + destination[i] = hsv.ToProfileConnectingSpace(options); + } + } + + /// + public static ChromaticAdaptionWhitePointSource GetChromaticAdaptionWhitePointSource() + => ChromaticAdaptionWhitePointSource.RgbWorkingSpace; + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override int GetHashCode() => HashCode.Combine(this.H, this.S, this.V); + + /// + public override string ToString() => FormattableString.Invariant($"Hsv({this.H:#0.##}, {this.S:#0.##}, {this.V:#0.##})"); + + /// + public override bool Equals(object? obj) => obj is Hsv other && this.Equals(other); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Equals(Hsv other) + => this.AsVector3Unsafe() == other.AsVector3Unsafe(); + + private Vector3 AsVector3Unsafe() => Unsafe.As(ref Unsafe.AsRef(in this)); +} diff --git a/src/ImageSharp/ColorProfiles/HunterLab.cs b/src/ImageSharp/ColorProfiles/HunterLab.cs new file mode 100644 index 0000000000..43ad2ac5c0 --- /dev/null +++ b/src/ImageSharp/ColorProfiles/HunterLab.cs @@ -0,0 +1,200 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace SixLabors.ImageSharp.ColorProfiles; + +/// +/// Represents an Hunter LAB color. +/// . +/// +[StructLayout(LayoutKind.Sequential)] +public readonly struct HunterLab : IColorProfile +{ + /// + /// Initializes a new instance of the struct. + /// + /// The lightness dimension. + /// The a (green - magenta) component. + /// The b (blue - yellow) component. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public HunterLab(float l, float a, float b) + { + this.L = l; + this.A = a; + this.B = b; + } + + /// + /// Initializes a new instance of the struct. + /// + /// The vector representing the l a b components. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public HunterLab(Vector3 vector) + { + // Not clamping as documentation about this space only indicates "usual" ranges + this.L = vector.X; + this.A = vector.Y; + this.B = vector.Z; + } + + /// + /// Gets the lightness dimension. + /// A value usually ranging between 0 (black), 100 (diffuse white) or higher (specular white). + /// + public float L { get; } + + /// + /// Gets the a color component. + /// A value usually ranging from -100 to 100. Negative is green, positive magenta. + /// + public float A { get; } + + /// + /// Gets the b color component. + /// A value usually ranging from -100 to 100. Negative is blue, positive is yellow + /// + public float B { get; } + + /// + /// Compares two objects for equality. + /// + /// The on the left side of the operand. + /// The on the right side of the operand. + /// + /// True if the current left is equal to the parameter; otherwise, false. + /// + public static bool operator ==(HunterLab left, HunterLab right) => left.Equals(right); + + /// + /// Compares two objects for inequality + /// + /// The on the left side of the operand. + /// The on the right side of the operand. + /// + /// True if the current left is unequal to the parameter; otherwise, false. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator !=(HunterLab left, HunterLab right) => !left.Equals(right); + + /// + public static HunterLab FromProfileConnectingSpace(ColorConversionOptions options, in CieXyz source) + { + // Conversion algorithm described here: + // http://en.wikipedia.org/wiki/Lab_color_space#Hunter_Lab + CieXyz whitePoint = options.TargetWhitePoint; + float x = source.X, y = source.Y, z = source.Z; + float xn = whitePoint.X, yn = whitePoint.Y, zn = whitePoint.Z; + + float ka = ComputeKa(in whitePoint); + float kb = ComputeKb(in whitePoint); + + float yByYn = y / yn; + float sqrtYbyYn = MathF.Sqrt(yByYn); + float l = 100 * sqrtYbyYn; + float a = ka * (((x / xn) - yByYn) / sqrtYbyYn); + float b = kb * ((yByYn - (z / zn)) / sqrtYbyYn); + + if (float.IsNaN(a)) + { + a = 0; + } + + if (float.IsNaN(b)) + { + b = 0; + } + + return new HunterLab(l, a, b); + } + + /// + public static void FromProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan source, Span destination) + { + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + for (int i = 0; i < source.Length; i++) + { + CieXyz xyz = source[i]; + destination[i] = FromProfileConnectingSpace(options, in xyz); + } + } + + /// + public CieXyz ToProfileConnectingSpace(ColorConversionOptions options) + { + // Conversion algorithm described here: + // http://en.wikipedia.org/wiki/Lab_color_space#Hunter_Lab + CieXyz whitePoint = options.WhitePoint; + float l = this.L, a = this.A, b = this.B; + float xn = whitePoint.X, yn = whitePoint.Y, zn = whitePoint.Z; + + float ka = ComputeKa(in whitePoint); + float kb = ComputeKb(in whitePoint); + + float pow = Numerics.Pow2(l / 100F); + float sqrtPow = MathF.Sqrt(pow); + float y = pow * yn; + + float x = (((a / ka) * sqrtPow) + pow) * xn; + float z = (((b / kb) * sqrtPow) - pow) * (-zn); + + return new CieXyz(x, y, z); + } + + /// + public static void ToProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan source, Span destination) + { + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + for (int i = 0; i < source.Length; i++) + { + HunterLab lab = source[i]; + destination[i] = lab.ToProfileConnectingSpace(options); + } + } + + /// + public static ChromaticAdaptionWhitePointSource GetChromaticAdaptionWhitePointSource() + => ChromaticAdaptionWhitePointSource.WhitePoint; + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override int GetHashCode() => HashCode.Combine(this.L, this.A, this.B); + + /// + public override string ToString() => FormattableString.Invariant($"HunterLab({this.L:#0.##}, {this.A:#0.##}, {this.B:#0.##})"); + + /// + public override bool Equals(object? obj) => obj is HunterLab other && this.Equals(other); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Equals(HunterLab other) + => this.AsVector3Unsafe() == other.AsVector3Unsafe(); + + private Vector3 AsVector3Unsafe() => Unsafe.As(ref Unsafe.AsRef(in this)); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static float ComputeKa(in CieXyz whitePoint) + { + if (whitePoint.Equals(KnownIlluminants.C)) + { + return 175F; + } + + return 100F * (175F / 198.04F) * (whitePoint.X + whitePoint.Y); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static float ComputeKb(in CieXyz whitePoint) + { + if (whitePoint == KnownIlluminants.C) + { + return 70F; + } + + return 100F * (70F / 218.11F) * (whitePoint.Y + whitePoint.Z); + } +} diff --git a/src/ImageSharp/ColorProfiles/IColorProfile.cs b/src/ImageSharp/ColorProfiles/IColorProfile.cs new file mode 100644 index 0000000000..6a1b2ee8d0 --- /dev/null +++ b/src/ImageSharp/ColorProfiles/IColorProfile.cs @@ -0,0 +1,59 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +namespace SixLabors.ImageSharp.ColorProfiles; + +/// +/// Defines the contract for all color profiles. +/// +public interface IColorProfile +{ + /// + /// Gets the chromatic adaption white point source. + /// + /// The . + public static abstract ChromaticAdaptionWhitePointSource GetChromaticAdaptionWhitePointSource(); +} + +/// +/// Defines the contract for all color profiles. +/// +/// The type of color profile. +/// The type of color profile connecting space. +public interface IColorProfile : IColorProfile, IEquatable + where TSelf : IColorProfile + where TProfileSpace : struct, IProfileConnectingSpace +{ +#pragma warning disable CA1000 // Do not declare static members on generic types + /// + /// Converts the color from the profile connection space. + /// + /// The color profile conversion options. + /// The color profile connecting space. + /// The . + public static abstract TSelf FromProfileConnectingSpace(ColorConversionOptions options, in TProfileSpace source); + + /// + /// Converts the span of colors from the profile connection space. + /// + /// The color profile conversion options. + /// The color profile span to convert from. + /// The color span to write the results to. + public static abstract void FromProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan source, Span destination); + + /// + /// Converts the color to the profile connection space. + /// + /// The color profile conversion options. + /// The . + public TProfileSpace ToProfileConnectingSpace(ColorConversionOptions options); + + /// + /// Converts the span of colors to the profile connection space. + /// + /// The color profile conversion options. + /// The color span to convert from. + /// The color profile span to write the results to. + public static abstract void ToProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan source, Span destination); +#pragma warning restore CA1000 // Do not declare static members on generic types +} diff --git a/src/ImageSharp/ColorProfiles/IProfileConnectingSpace.cs b/src/ImageSharp/ColorProfiles/IProfileConnectingSpace.cs new file mode 100644 index 0000000000..2ac736f444 --- /dev/null +++ b/src/ImageSharp/ColorProfiles/IProfileConnectingSpace.cs @@ -0,0 +1,18 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +namespace SixLabors.ImageSharp.ColorProfiles; + +/// +/// Defines the contract for all color profile connection spaces. +/// +public interface IProfileConnectingSpace; + +/// +/// Defines the contract for all color profile connection spaces. +/// +/// The type of color profile. +/// The type of color profile connecting space. +public interface IProfileConnectingSpace : IColorProfile, IProfileConnectingSpace + where TSelf : struct, IColorProfile, IProfileConnectingSpace + where TProfileSpace : struct, IProfileConnectingSpace; diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/LmsAdaptationMatrix.cs b/src/ImageSharp/ColorProfiles/KnownChromaticAdaptationMatrices.cs similarity index 76% rename from src/ImageSharp/ColorSpaces/Conversion/Implementation/LmsAdaptationMatrix.cs rename to src/ImageSharp/ColorProfiles/KnownChromaticAdaptationMatrices.cs index 80bd160e8a..71d565f87f 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/LmsAdaptationMatrix.cs +++ b/src/ImageSharp/ColorProfiles/KnownChromaticAdaptationMatrices.cs @@ -3,23 +3,25 @@ using System.Numerics; -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; +namespace SixLabors.ImageSharp.ColorProfiles; /// -/// Matrices used for transformation from to , defining the cone response domain. -/// Used in +/// Provides matrices for chromatic adaptation, facilitating the adjustment of color values +/// under different light sources to maintain color constancy. This class supports common +/// adaptation transforms based on the von Kries coefficient law, which assumes independent +/// scaling of the cone responses in the human eye. These matrices can be applied to convert +/// color coordinates between different illuminants, ensuring consistent color appearance +/// across various lighting conditions. /// /// -/// Matrix data obtained from: -/// Two New von Kries Based Chromatic Adaptation Transforms Found by Numerical Optimization -/// S. Bianco, R. Schettini -/// DISCo, Department of Informatics, Systems and Communication, University of Milan-Bicocca, viale Sarca 336, 20126 Milan, Italy -/// https://web.stanford.edu/~sujason/ColorBalancing/Papers/Two%20New%20von%20Kries%20Based%20Chromatic%20Adaptation.pdf +/// Supported adaptation matrices include the Bradford, von Kries, and Sharp transforms. +/// These matrices are typically used in conjunction with color space conversions, such as from XYZ +/// to RGB, to achieve accurate color rendition in digital imaging applications. /// -public static class LmsAdaptationMatrix +public static class KnownChromaticAdaptationMatrices { /// - /// Von Kries chromatic adaptation transform matrix (Hunt-Pointer-Estevez adjusted for D65) + /// von Kries chromatic adaptation transform matrix (Hunt-Pointer-Estevez adjusted for D65) /// public static readonly Matrix4x4 VonKriesHPEAdjusted = Matrix4x4.Transpose(new Matrix4x4 @@ -37,7 +39,7 @@ public static readonly Matrix4x4 VonKriesHPEAdjusted }); /// - /// Von Kries chromatic adaptation transform matrix (Hunt-Pointer-Estevez for equal energy) + /// von Kries chromatic adaptation transform matrix (Hunt-Pointer-Estevez for equal energy) /// public static readonly Matrix4x4 VonKriesHPE = Matrix4x4.Transpose(new Matrix4x4 diff --git a/src/ImageSharp/ColorProfiles/KnownIlluminants.cs b/src/ImageSharp/ColorProfiles/KnownIlluminants.cs new file mode 100644 index 0000000000..b9236497fe --- /dev/null +++ b/src/ImageSharp/ColorProfiles/KnownIlluminants.cs @@ -0,0 +1,71 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +namespace SixLabors.ImageSharp.ColorProfiles; + +/// +/// The well known standard illuminants. +/// Standard illuminants provide a basis for comparing images or colors recorded under different lighting +/// +/// +/// Coefficients taken from: http://www.brucelindbloom.com/index.html?Eqn_ChromAdapt.html +///
+/// Descriptions taken from: http://en.wikipedia.org/wiki/Standard_illuminant +///
+public static class KnownIlluminants +{ + /// + /// Gets the Incandescent / Tungsten illuminant. + /// + public static CieXyz A { get; } = new(1.09850F, 1F, 0.35585F); + + /// + /// Gets the Direct sunlight at noon (obsoleteF) illuminant. + /// + public static CieXyz B { get; } = new(0.99072F, 1F, 0.85223F); + + /// + /// Gets the Average / North sky Daylight (obsoleteF) illuminant. + /// + public static CieXyz C { get; } = new(0.98074F, 1F, 1.18232F); + + /// + /// Gets the Horizon Light. ICC profile PCS illuminant. + /// + public static CieXyz D50 { get; } = new(0.96422F, 1F, 0.82521F); + + /// + /// Gets the Mid-morning / Mid-afternoon Daylight illuminant. + /// + public static CieXyz D55 { get; } = new(0.95682F, 1F, 0.92149F); + + /// + /// Gets the Noon Daylight: TelevisionF, sRGB color space illuminant. + /// + public static CieXyz D65 { get; } = new(0.95047F, 1F, 1.08883F); + + /// + /// Gets the North sky Daylight illuminant. + /// + public static CieXyz D75 { get; } = new(0.94972F, 1F, 1.22638F); + + /// + /// Gets the Equal energy illuminant. + /// + public static CieXyz E { get; } = new(1F, 1F, 1F); + + /// + /// Gets the Cool White Fluorescent illuminant. + /// + public static CieXyz F2 { get; } = new(0.99186F, 1F, 0.67393F); + + /// + /// Gets the D65 simulatorF, Daylight simulator illuminant. + /// + public static CieXyz F7 { get; } = new(0.95041F, 1F, 1.08747F); + + /// + /// Gets the Philips TL84F, Ultralume 40 illuminant. + /// + public static CieXyz F11 { get; } = new(1.00962F, 1F, 0.64350F); +} diff --git a/src/ImageSharp/ColorProfiles/KnownRgbWorkingSpaces.cs b/src/ImageSharp/ColorProfiles/KnownRgbWorkingSpaces.cs new file mode 100644 index 0000000000..9163839363 --- /dev/null +++ b/src/ImageSharp/ColorProfiles/KnownRgbWorkingSpaces.cs @@ -0,0 +1,113 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.ColorProfiles.Companding; +using SixLabors.ImageSharp.ColorProfiles.WorkingSpaces; + +namespace SixLabors.ImageSharp.ColorProfiles; + +/// +/// Chromaticity coordinates based on: +/// +public static class KnownRgbWorkingSpaces +{ + /// + /// sRgb working space. + /// + /// + /// Uses proper companding function, according to: + /// + /// + public static readonly RgbWorkingSpace SRgb = new SRgbWorkingSpace(KnownIlluminants.D65, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6400F, 0.3300F), new CieXyChromaticityCoordinates(0.3000F, 0.6000F), new CieXyChromaticityCoordinates(0.1500F, 0.0600F))); + + /// + /// Simplified sRgb working space (uses gamma companding instead of ). + /// See also . + /// + public static readonly RgbWorkingSpace SRgbSimplified = new GammaWorkingSpace(2.2F, KnownIlluminants.D65, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6400F, 0.3300F), new CieXyChromaticityCoordinates(0.3000F, 0.6000F), new CieXyChromaticityCoordinates(0.1500F, 0.0600F))); + + /// + /// Rec. 709 (ITU-R Recommendation BT.709) working space. + /// + public static readonly RgbWorkingSpace Rec709 = new Rec709WorkingSpace(KnownIlluminants.D65, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.64F, 0.33F), new CieXyChromaticityCoordinates(0.30F, 0.60F), new CieXyChromaticityCoordinates(0.15F, 0.06F))); + + /// + /// Rec. 2020 (ITU-R Recommendation BT.2020F) working space. + /// + public static readonly RgbWorkingSpace Rec2020 = new Rec2020WorkingSpace(KnownIlluminants.D65, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.708F, 0.292F), new CieXyChromaticityCoordinates(0.170F, 0.797F), new CieXyChromaticityCoordinates(0.131F, 0.046F))); + + /// + /// ECI Rgb v2 working space. + /// + public static readonly RgbWorkingSpace ECIRgbv2 = new LWorkingSpace(KnownIlluminants.D50, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6700F, 0.3300F), new CieXyChromaticityCoordinates(0.2100F, 0.7100F), new CieXyChromaticityCoordinates(0.1400F, 0.0800F))); + + /// + /// Adobe Rgb (1998) working space. + /// + public static readonly RgbWorkingSpace AdobeRgb1998 = new GammaWorkingSpace(2.2F, KnownIlluminants.D65, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6400F, 0.3300F), new CieXyChromaticityCoordinates(0.2100F, 0.7100F), new CieXyChromaticityCoordinates(0.1500F, 0.0600F))); + + /// + /// Apple sRgb working space. + /// + public static readonly RgbWorkingSpace ApplesRgb = new GammaWorkingSpace(1.8F, KnownIlluminants.D65, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6250F, 0.3400F), new CieXyChromaticityCoordinates(0.2800F, 0.5950F), new CieXyChromaticityCoordinates(0.1550F, 0.0700F))); + + /// + /// Best Rgb working space. + /// + public static readonly RgbWorkingSpace BestRgb = new GammaWorkingSpace(2.2F, KnownIlluminants.D50, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.7347F, 0.2653F), new CieXyChromaticityCoordinates(0.2150F, 0.7750F), new CieXyChromaticityCoordinates(0.1300F, 0.0350F))); + + /// + /// Beta Rgb working space. + /// + public static readonly RgbWorkingSpace BetaRgb = new GammaWorkingSpace(2.2F, KnownIlluminants.D50, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6888F, 0.3112F), new CieXyChromaticityCoordinates(0.1986F, 0.7551F), new CieXyChromaticityCoordinates(0.1265F, 0.0352F))); + + /// + /// Bruce Rgb working space. + /// + public static readonly RgbWorkingSpace BruceRgb = new GammaWorkingSpace(2.2F, KnownIlluminants.D65, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6400F, 0.3300F), new CieXyChromaticityCoordinates(0.2800F, 0.6500F), new CieXyChromaticityCoordinates(0.1500F, 0.0600F))); + + /// + /// CIE Rgb working space. + /// + public static readonly RgbWorkingSpace CIERgb = new GammaWorkingSpace(2.2F, KnownIlluminants.E, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.7350F, 0.2650F), new CieXyChromaticityCoordinates(0.2740F, 0.7170F), new CieXyChromaticityCoordinates(0.1670F, 0.0090F))); + + /// + /// ColorMatch Rgb working space. + /// + public static readonly RgbWorkingSpace ColorMatchRgb = new GammaWorkingSpace(1.8F, KnownIlluminants.D50, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6300F, 0.3400F), new CieXyChromaticityCoordinates(0.2950F, 0.6050F), new CieXyChromaticityCoordinates(0.1500F, 0.0750F))); + + /// + /// Don Rgb 4 working space. + /// + public static readonly RgbWorkingSpace DonRgb4 = new GammaWorkingSpace(2.2F, KnownIlluminants.D50, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6960F, 0.3000F), new CieXyChromaticityCoordinates(0.2150F, 0.7650F), new CieXyChromaticityCoordinates(0.1300F, 0.0350F))); + + /// + /// Ekta Space PS5 working space. + /// + public static readonly RgbWorkingSpace EktaSpacePS5 = new GammaWorkingSpace(2.2F, KnownIlluminants.D50, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6950F, 0.3050F), new CieXyChromaticityCoordinates(0.2600F, 0.7000F), new CieXyChromaticityCoordinates(0.1100F, 0.0050F))); + + /// + /// NTSC Rgb working space. + /// + public static readonly RgbWorkingSpace NTSCRgb = new GammaWorkingSpace(2.2F, KnownIlluminants.C, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6700F, 0.3300F), new CieXyChromaticityCoordinates(0.2100F, 0.7100F), new CieXyChromaticityCoordinates(0.1400F, 0.0800F))); + + /// + /// PAL/SECAM Rgb working space. + /// + public static readonly RgbWorkingSpace PALSECAMRgb = new GammaWorkingSpace(2.2F, KnownIlluminants.D65, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6400F, 0.3300F), new CieXyChromaticityCoordinates(0.2900F, 0.6000F), new CieXyChromaticityCoordinates(0.1500F, 0.0600F))); + + /// + /// ProPhoto Rgb working space. + /// + public static readonly RgbWorkingSpace ProPhotoRgb = new GammaWorkingSpace(1.8F, KnownIlluminants.D50, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.7347F, 0.2653F), new CieXyChromaticityCoordinates(0.1596F, 0.8404F), new CieXyChromaticityCoordinates(0.0366F, 0.0001F))); + + /// + /// SMPTE-C Rgb working space. + /// + public static readonly RgbWorkingSpace SMPTECRgb = new GammaWorkingSpace(2.2F, KnownIlluminants.D65, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6300F, 0.3400F), new CieXyChromaticityCoordinates(0.3100F, 0.5950F), new CieXyChromaticityCoordinates(0.1550F, 0.0700F))); + + /// + /// Wide Gamut Rgb working space. + /// + public static readonly RgbWorkingSpace WideGamutRgb = new GammaWorkingSpace(2.2F, KnownIlluminants.D50, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.7350F, 0.2650F), new CieXyChromaticityCoordinates(0.1150F, 0.8260F), new CieXyChromaticityCoordinates(0.1570F, 0.0180F))); +} diff --git a/src/ImageSharp/ColorSpaces/Lms.cs b/src/ImageSharp/ColorProfiles/Lms.cs similarity index 58% rename from src/ImageSharp/ColorSpaces/Lms.cs rename to src/ImageSharp/ColorProfiles/Lms.cs index 99210ff6e4..5a6791b2d7 100644 --- a/src/ImageSharp/ColorSpaces/Lms.cs +++ b/src/ImageSharp/ColorProfiles/Lms.cs @@ -3,15 +3,17 @@ using System.Numerics; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; -namespace SixLabors.ImageSharp.ColorSpaces; +namespace SixLabors.ImageSharp.ColorProfiles; /// /// LMS is a color space represented by the response of the three types of cones of the human eye, /// named after their responsivity (sensitivity) at long, medium and short wavelengths. /// /// -public readonly struct Lms : IEquatable +[StructLayout(LayoutKind.Sequential)] +public readonly struct Lms : IColorProfile { /// /// Initializes a new instance of the struct. @@ -19,17 +21,19 @@ namespace SixLabors.ImageSharp.ColorSpaces; /// L represents the responsivity at long wavelengths. /// M represents the responsivity at medium wavelengths. /// S represents the responsivity at short wavelengths. - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public Lms(float l, float m, float s) - : this(new Vector3(l, m, s)) { + this.L = l; + this.M = m; + this.S = s; } /// /// Initializes a new instance of the struct. /// /// The vector representing the l, m, s components. - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public Lms(Vector3 vector) { // Not clamping as documentation about this space only indicates "usual" ranges @@ -42,19 +46,19 @@ public Lms(Vector3 vector) /// Gets the L long component. /// A value usually ranging between -1 and 1. /// - public readonly float L { get; } + public float L { get; } /// /// Gets the M medium component. /// A value usually ranging between -1 and 1. /// - public readonly float M { get; } + public float M { get; } /// /// Gets the S short component. /// A value usually ranging between -1 and 1. /// - public readonly float S { get; } + public float S { get; } /// /// Compares two objects for equality. @@ -64,7 +68,7 @@ public Lms(Vector3 vector) /// /// True if the current left is equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Lms left, Lms right) => left.Equals(right); /// @@ -75,16 +79,57 @@ public Lms(Vector3 vector) /// /// True if the current left is unequal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Lms left, Lms right) => !left.Equals(right); /// /// Returns a new representing this instance. /// /// The . - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public Vector3 ToVector3() => new(this.L, this.M, this.S); + /// + public static Lms FromProfileConnectingSpace(ColorConversionOptions options, in CieXyz source) + { + Vector3 vector = Vector3.Transform(source.ToVector3(), options.AdaptationMatrix); + return new Lms(vector); + } + + /// + public static void FromProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan source, Span destination) + { + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + + for (int i = 0; i < source.Length; i++) + { + CieXyz xyz = source[i]; + destination[i] = FromProfileConnectingSpace(options, in xyz); + } + } + + /// + public CieXyz ToProfileConnectingSpace(ColorConversionOptions options) + { + Vector3 vector = Vector3.Transform(this.ToVector3(), options.InverseAdaptationMatrix); + return new CieXyz(vector); + } + + /// + public static void ToProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan source, Span destination) + { + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + + for (int i = 0; i < source.Length; i++) + { + Lms lms = source[i]; + destination[i] = lms.ToProfileConnectingSpace(options); + } + } + + /// + public static ChromaticAdaptionWhitePointSource GetChromaticAdaptionWhitePointSource() => ChromaticAdaptionWhitePointSource.WhitePoint; + /// public override int GetHashCode() => HashCode.Combine(this.L, this.M, this.S); @@ -95,9 +140,9 @@ public Lms(Vector3 vector) public override bool Equals(object? obj) => obj is Lms other && this.Equals(other); /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals(Lms other) - => this.L.Equals(other.L) - && this.M.Equals(other.M) - && this.S.Equals(other.S); + => this.AsVector3Unsafe() == other.AsVector3Unsafe(); + + private Vector3 AsVector3Unsafe() => Unsafe.As(ref Unsafe.AsRef(in this)); } diff --git a/src/ImageSharp/ColorProfiles/Rgb.cs b/src/ImageSharp/ColorProfiles/Rgb.cs new file mode 100644 index 0000000000..6698e12cb8 --- /dev/null +++ b/src/ImageSharp/ColorProfiles/Rgb.cs @@ -0,0 +1,269 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using SixLabors.ImageSharp.ColorProfiles.WorkingSpaces; + +namespace SixLabors.ImageSharp.ColorProfiles; + +/// +/// Represents an RGB (red, green, blue) color profile. +/// +[StructLayout(LayoutKind.Sequential)] +public readonly struct Rgb : IProfileConnectingSpace +{ + /// + /// Initializes a new instance of the struct. + /// + /// The red component usually ranging between 0 and 1. + /// The green component usually ranging between 0 and 1. + /// The blue component usually ranging between 0 and 1. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Rgb(float r, float g, float b) + { + // Not clamping as this space can exceed "usual" ranges + this.R = r; + this.G = g; + this.B = b; + } + + /// + /// Initializes a new instance of the struct. + /// + /// The vector representing the r, g, b components. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Rgb(Vector3 source) + { + this.R = source.X; + this.G = source.Y; + this.B = source.Z; + } + + /// + /// Gets the red component. + /// A value usually ranging between 0 and 1. + /// + public float R { get; } + + /// + /// Gets the green component. + /// A value usually ranging between 0 and 1. + /// + public float G { get; } + + /// + /// Gets the blue component. + /// A value usually ranging between 0 and 1. + /// + public float B { get; } + + /// + /// Compares two objects for equality. + /// + /// The on the left side of the operand. + /// The on the right side of the operand. + /// + /// True if the current left is equal to the parameter; otherwise, false. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator ==(Rgb left, Rgb right) => left.Equals(right); + + /// + /// Compares two objects for inequality. + /// + /// The on the left side of the operand. + /// The on the right side of the operand. + /// + /// True if the current left is unequal to the parameter; otherwise, false. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator !=(Rgb left, Rgb right) => !left.Equals(right); + + /// + public static Rgb FromProfileConnectingSpace(ColorConversionOptions options, in CieXyz source) + { + // Convert to linear rgb then compress. + Rgb linear = new(Vector3.Transform(source.ToVector3(), GetCieXyzToRgbMatrix(options.TargetRgbWorkingSpace))); + return FromScaledVector4(options.TargetRgbWorkingSpace.Compress(linear.ToScaledVector4())); + } + + /// + public static void FromProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan source, Span destination) + { + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + + Matrix4x4 matrix = GetCieXyzToRgbMatrix(options.TargetRgbWorkingSpace); + for (int i = 0; i < source.Length; i++) + { + // Convert to linear rgb then compress. + Rgb linear = new(Vector3.Transform(source[i].ToVector3(), matrix)); + Vector4 nonlinear = options.TargetRgbWorkingSpace.Compress(linear.ToScaledVector4()); + destination[i] = FromScaledVector4(nonlinear); + } + } + + /// + public CieXyz ToProfileConnectingSpace(ColorConversionOptions options) + { + // First expand to linear rgb + Rgb linear = FromScaledVector4(options.RgbWorkingSpace.Expand(this.ToScaledVector4())); + + // Then convert to xyz + return new CieXyz(Vector3.Transform(linear.ToScaledVector3(), GetRgbToCieXyzMatrix(options.RgbWorkingSpace))); + } + + /// + public static void ToProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan source, Span destination) + { + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + + Matrix4x4 matrix = GetRgbToCieXyzMatrix(options.RgbWorkingSpace); + for (int i = 0; i < source.Length; i++) + { + Rgb rgb = source[i]; + + // First expand to linear rgb + Rgb linear = FromScaledVector4(options.RgbWorkingSpace.Expand(rgb.ToScaledVector4())); + + // Then convert to xyz + destination[i] = new CieXyz(Vector3.Transform(linear.ToScaledVector3(), matrix)); + } + } + + /// + public static ChromaticAdaptionWhitePointSource GetChromaticAdaptionWhitePointSource() => ChromaticAdaptionWhitePointSource.RgbWorkingSpace; + + /// + /// Initializes the color instance from a generic scaled . + /// + /// The vector to load the color from. + /// The . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgb FromScaledVector3(Vector3 source) => new(Vector3.Clamp(source, Vector3.Zero, Vector3.One)); + + /// + /// Initializes the color instance from a generic scaled . + /// + /// The vector to load the color from. + /// The . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgb FromScaledVector4(Vector4 source) + { + source = Vector4.Clamp(source, Vector4.Zero, Vector4.One); + return new(source.X, source.Y, source.Z); + } + + /// + /// Initializes the color instance for a source clamped between 0 and 1 + /// + /// The source to load the color from. + /// The . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgb Clamp(Rgb source) => new(Vector3.Clamp(new(source.R, source.G, source.B), Vector3.Zero, Vector3.One)); + + /// + /// Expands the color into a generic ("scaled") representation + /// with values scaled and usually clamped between 0 and 1. + /// The vector components are typically expanded in least to greatest significance order. + /// + /// The . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Vector3 ToScaledVector3() => Clamp(this).ToVector3(); + + /// + /// Expands the color into a generic representation. + /// The vector components are typically expanded in least to greatest significance order. + /// + /// The . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Vector3 ToVector3() => new(this.R, this.G, this.B); + + /// + /// Expands the color into a generic ("scaled") representation + /// with values scaled and usually clamped between 0 and 1. + /// The vector components are typically expanded in least to greatest significance order. + /// + /// The . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Vector4 ToScaledVector4() => new(this.ToScaledVector3(), 1f); + + /// + public override int GetHashCode() => HashCode.Combine(this.R, this.G, this.B); + + /// + public override string ToString() => FormattableString.Invariant($"Rgb({this.R:#0.##}, {this.G:#0.##}, {this.B:#0.##})"); + + /// + public override bool Equals(object? obj) => obj is Rgb other && this.Equals(other); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Equals(Rgb other) + => this.AsVector3Unsafe() == other.AsVector3Unsafe(); + + private Vector3 AsVector3Unsafe() => Unsafe.As(ref Unsafe.AsRef(in this)); + + private static Matrix4x4 GetCieXyzToRgbMatrix(RgbWorkingSpace workingSpace) + { + Matrix4x4 matrix = GetRgbToCieXyzMatrix(workingSpace); + Matrix4x4.Invert(matrix, out Matrix4x4 inverseMatrix); + return inverseMatrix; + } + + private static Matrix4x4 GetRgbToCieXyzMatrix(RgbWorkingSpace workingSpace) + { + DebugGuard.NotNull(workingSpace, nameof(workingSpace)); + RgbPrimariesChromaticityCoordinates chromaticity = workingSpace.ChromaticityCoordinates; + + float xr = chromaticity.R.X; + float xg = chromaticity.G.X; + float xb = chromaticity.B.X; + float yr = chromaticity.R.Y; + float yg = chromaticity.G.Y; + float yb = chromaticity.B.Y; + + float mXr = xr / yr; + float mZr = (1 - xr - yr) / yr; + + float mXg = xg / yg; + float mZg = (1 - xg - yg) / yg; + + float mXb = xb / yb; + float mZb = (1 - xb - yb) / yb; + + Matrix4x4 xyzMatrix = new() + { + M11 = mXr, + M21 = mXg, + M31 = mXb, + M12 = 1F, + M22 = 1F, + M32 = 1F, + M13 = mZr, + M23 = mZg, + M33 = mZb, + M44 = 1F + }; + + Matrix4x4.Invert(xyzMatrix, out Matrix4x4 inverseXyzMatrix); + + Vector3 vector = Vector3.Transform(workingSpace.WhitePoint.ToVector3(), inverseXyzMatrix); + + // Use transposed Rows/Columns + return new Matrix4x4 + { + M11 = vector.X * mXr, + M21 = vector.Y * mXg, + M31 = vector.Z * mXb, + M12 = vector.X, + M22 = vector.Y, + M32 = vector.Z, + M13 = vector.X * mZr, + M23 = vector.Y * mZg, + M33 = vector.Z * mZb, + M44 = 1F + }; + } +} diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/RGBPrimariesChromaticityCoordinates.cs b/src/ImageSharp/ColorProfiles/RgbPrimariesChromaticityCoordinates.cs similarity index 89% rename from src/ImageSharp/ColorSpaces/Conversion/Implementation/RGBPrimariesChromaticityCoordinates.cs rename to src/ImageSharp/ColorProfiles/RgbPrimariesChromaticityCoordinates.cs index 625e6c551a..1040f23acb 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/RGBPrimariesChromaticityCoordinates.cs +++ b/src/ImageSharp/ColorProfiles/RgbPrimariesChromaticityCoordinates.cs @@ -1,7 +1,9 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; +using SixLabors.ImageSharp.ColorProfiles.WorkingSpaces; + +namespace SixLabors.ImageSharp.ColorProfiles; /// /// Represents the chromaticity coordinates of RGB primaries. @@ -50,9 +52,7 @@ public RgbPrimariesChromaticityCoordinates(CieXyChromaticityCoordinates r, CieXy /// True if the current left is equal to the parameter; otherwise, false. /// public static bool operator ==(RgbPrimariesChromaticityCoordinates left, RgbPrimariesChromaticityCoordinates right) - { - return left.Equals(right); - } + => left.Equals(right); /// /// Compares two objects for inequality @@ -67,21 +67,15 @@ public RgbPrimariesChromaticityCoordinates(CieXyChromaticityCoordinates r, CieXy /// True if the current left is unequal to the parameter; otherwise, false. /// public static bool operator !=(RgbPrimariesChromaticityCoordinates left, RgbPrimariesChromaticityCoordinates right) - { - return !left.Equals(right); - } + => !left.Equals(right); /// public override bool Equals(object? obj) - { - return obj is RgbPrimariesChromaticityCoordinates other && this.Equals(other); - } + => obj is RgbPrimariesChromaticityCoordinates other && this.Equals(other); /// public bool Equals(RgbPrimariesChromaticityCoordinates other) - { - return this.R.Equals(other.R) && this.G.Equals(other.G) && this.B.Equals(other.B); - } + => this.R.Equals(other.R) && this.G.Equals(other.G) && this.B.Equals(other.B); /// public override int GetHashCode() => HashCode.Combine(this.R, this.G, this.B); diff --git a/src/ImageSharp/ColorProfiles/VonKriesChromaticAdaptation.cs b/src/ImageSharp/ColorProfiles/VonKriesChromaticAdaptation.cs new file mode 100644 index 0000000000..2f9a52912e --- /dev/null +++ b/src/ImageSharp/ColorProfiles/VonKriesChromaticAdaptation.cs @@ -0,0 +1,95 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace SixLabors.ImageSharp.ColorProfiles; + +/// +/// Implementation of the Von Kries chromatic adaptation model. +/// +/// +/// Transformation described here: +/// http://www.brucelindbloom.com/index.html?Eqn_ChromAdapt.html +/// +public static class VonKriesChromaticAdaptation +{ + /// + /// Performs a linear transformation of a source color in to the destination color. + /// + /// Doesn't crop the resulting color space coordinates (e.g. allows negative values for XYZ coordinates). + /// The source color. + /// The conversion white points. + /// The chromatic adaptation matrix. + /// The + public static CieXyz Transform(in CieXyz source, (CieXyz From, CieXyz To) whitePoints, Matrix4x4 matrix) + { + CieXyz from = whitePoints.From; + CieXyz to = whitePoints.To; + + if (from.Equals(to)) + { + return new(source.X, source.Y, source.Z); + } + + Vector3 sourceColorLms = Vector3.Transform(source.ToVector3(), matrix); + Vector3 sourceWhitePointLms = Vector3.Transform(from.ToVector3(), matrix); + Vector3 targetWhitePointLms = Vector3.Transform(to.ToVector3(), matrix); + + Vector3 vector = targetWhitePointLms / sourceWhitePointLms; + Vector3 targetColorLms = Vector3.Multiply(vector, sourceColorLms); + + Matrix4x4.Invert(matrix, out Matrix4x4 inverseMatrix); + return new CieXyz(Vector3.Transform(targetColorLms, inverseMatrix)); + } + + /// + /// Performs a bulk linear transformation of a source color in to the destination color. + /// + /// Doesn't crop the resulting color space coordinates (e. g. allows negative values for XYZ coordinates). + /// The span to the source colors. + /// The span to the destination colors. + /// The conversion white points. + /// The chromatic adaptation matrix. + public static void Transform( + ReadOnlySpan source, + Span destination, + (CieXyz From, CieXyz To) whitePoints, + Matrix4x4 matrix) + { + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; + + CieXyz from = whitePoints.From; + CieXyz to = whitePoints.To; + + if (from.Equals(to)) + { + source.CopyTo(destination[..count]); + return; + } + + Matrix4x4.Invert(matrix, out Matrix4x4 inverseMatrix); + + ref CieXyz sourceBase = ref MemoryMarshal.GetReference(source); + ref CieXyz destinationBase = ref MemoryMarshal.GetReference(destination); + + Vector3 sourceWhitePointLms = Vector3.Transform(from.ToVector3(), matrix); + Vector3 targetWhitePointLms = Vector3.Transform(to.ToVector3(), matrix); + + Vector3 vector = targetWhitePointLms / sourceWhitePointLms; + + for (nuint i = 0; i < (uint)count; i++) + { + ref CieXyz sp = ref Unsafe.Add(ref sourceBase, i); + ref CieXyz dp = ref Unsafe.Add(ref destinationBase, i); + + Vector3 sourceColorLms = Vector3.Transform(sp.ToVector3(), matrix); + + Vector3 targetColorLms = Vector3.Multiply(vector, sourceColorLms); + dp = new CieXyz(Vector3.Transform(targetColorLms, inverseMatrix)); + } + } +} diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/GammaWorkingSpace.cs b/src/ImageSharp/ColorProfiles/WorkingSpaces/GammaWorkingSpace.cs similarity index 72% rename from src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/GammaWorkingSpace.cs rename to src/ImageSharp/ColorProfiles/WorkingSpaces/GammaWorkingSpace.cs index e95f1f2b47..91fa426241 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/GammaWorkingSpace.cs +++ b/src/ImageSharp/ColorProfiles/WorkingSpaces/GammaWorkingSpace.cs @@ -1,10 +1,10 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.ColorSpaces.Companding; +using System.Numerics; +using SixLabors.ImageSharp.ColorProfiles.Companding; -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; +namespace SixLabors.ImageSharp.ColorProfiles.WorkingSpaces; /// /// The gamma working space. @@ -26,12 +26,16 @@ public GammaWorkingSpace(float gamma, CieXyz referenceWhite, RgbPrimariesChromat public float Gamma { get; } /// - [MethodImpl(InliningOptions.ShortMethod)] - public override float Compress(float channel) => GammaCompanding.Compress(channel, this.Gamma); + public override void Compress(Span vectors) => GammaCompanding.Compress(vectors, this.Gamma); /// - [MethodImpl(InliningOptions.ShortMethod)] - public override float Expand(float channel) => GammaCompanding.Expand(channel, this.Gamma); + public override void Expand(Span vectors) => GammaCompanding.Expand(vectors, this.Gamma); + + /// + public override Vector4 Compress(Vector4 vector) => GammaCompanding.Compress(vector, this.Gamma); + + /// + public override Vector4 Expand(Vector4 vector) => GammaCompanding.Expand(vector, this.Gamma); /// public override bool Equals(object? obj) diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/LWorkingSpace.cs b/src/ImageSharp/ColorProfiles/WorkingSpaces/LWorkingSpace.cs similarity index 56% rename from src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/LWorkingSpace.cs rename to src/ImageSharp/ColorProfiles/WorkingSpaces/LWorkingSpace.cs index 199f6c8d85..77dc2c06d9 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/LWorkingSpace.cs +++ b/src/ImageSharp/ColorProfiles/WorkingSpaces/LWorkingSpace.cs @@ -1,10 +1,10 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.ColorSpaces.Companding; +using System.Numerics; +using SixLabors.ImageSharp.ColorProfiles.Companding; -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; +namespace SixLabors.ImageSharp.ColorProfiles.WorkingSpaces; /// /// L* working space. @@ -22,10 +22,14 @@ public LWorkingSpace(CieXyz referenceWhite, RgbPrimariesChromaticityCoordinates } /// - [MethodImpl(InliningOptions.ShortMethod)] - public override float Compress(float channel) => LCompanding.Compress(channel); + public override void Compress(Span vectors) => LCompanding.Compress(vectors); /// - [MethodImpl(InliningOptions.ShortMethod)] - public override float Expand(float channel) => LCompanding.Expand(channel); + public override void Expand(Span vectors) => LCompanding.Expand(vectors); + + /// + public override Vector4 Compress(Vector4 vector) => LCompanding.Compress(vector); + + /// + public override Vector4 Expand(Vector4 vector) => LCompanding.Expand(vector); } diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/Rec2020WorkingSpace.cs b/src/ImageSharp/ColorProfiles/WorkingSpaces/Rec2020WorkingSpace.cs similarity index 57% rename from src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/Rec2020WorkingSpace.cs rename to src/ImageSharp/ColorProfiles/WorkingSpaces/Rec2020WorkingSpace.cs index 52cc0f95af..970d103029 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/Rec2020WorkingSpace.cs +++ b/src/ImageSharp/ColorProfiles/WorkingSpaces/Rec2020WorkingSpace.cs @@ -1,10 +1,10 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.ColorSpaces.Companding; +using System.Numerics; +using SixLabors.ImageSharp.ColorProfiles.Companding; -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; +namespace SixLabors.ImageSharp.ColorProfiles.WorkingSpaces; /// /// Rec. 2020 (ITU-R Recommendation BT.2020F) working space. @@ -22,10 +22,14 @@ public Rec2020WorkingSpace(CieXyz referenceWhite, RgbPrimariesChromaticityCoordi } /// - [MethodImpl(InliningOptions.ShortMethod)] - public override float Compress(float channel) => Rec2020Companding.Compress(channel); + public override void Compress(Span vectors) => Rec2020Companding.Compress(vectors); /// - [MethodImpl(InliningOptions.ShortMethod)] - public override float Expand(float channel) => Rec2020Companding.Expand(channel); + public override void Expand(Span vectors) => Rec2020Companding.Expand(vectors); + + /// + public override Vector4 Compress(Vector4 vector) => Rec2020Companding.Compress(vector); + + /// + public override Vector4 Expand(Vector4 vector) => Rec2020Companding.Expand(vector); } diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/Rec709WorkingSpace.cs b/src/ImageSharp/ColorProfiles/WorkingSpaces/Rec709WorkingSpace.cs similarity index 57% rename from src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/Rec709WorkingSpace.cs rename to src/ImageSharp/ColorProfiles/WorkingSpaces/Rec709WorkingSpace.cs index c030e91025..011da58077 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/Rec709WorkingSpace.cs +++ b/src/ImageSharp/ColorProfiles/WorkingSpaces/Rec709WorkingSpace.cs @@ -1,10 +1,10 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.ColorSpaces.Companding; +using System.Numerics; +using SixLabors.ImageSharp.ColorProfiles.Companding; -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; +namespace SixLabors.ImageSharp.ColorProfiles.WorkingSpaces; /// /// Rec. 709 (ITU-R Recommendation BT.709) working space. @@ -22,10 +22,14 @@ public Rec709WorkingSpace(CieXyz referenceWhite, RgbPrimariesChromaticityCoordin } /// - [MethodImpl(InliningOptions.ShortMethod)] - public override float Compress(float channel) => Rec709Companding.Compress(channel); + public override void Compress(Span vectors) => Rec709Companding.Compress(vectors); /// - [MethodImpl(InliningOptions.ShortMethod)] - public override float Expand(float channel) => Rec709Companding.Expand(channel); + public override void Expand(Span vectors) => Rec709Companding.Expand(vectors); + + /// + public override Vector4 Compress(Vector4 vector) => Rec709Companding.Compress(vector); + + /// + public override Vector4 Expand(Vector4 vector) => Rec709Companding.Expand(vector); } diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/RgbWorkingSpace.cs b/src/ImageSharp/ColorProfiles/WorkingSpaces/RgbWorkingSpace.cs similarity index 61% rename from src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/RgbWorkingSpace.cs rename to src/ImageSharp/ColorProfiles/WorkingSpaces/RgbWorkingSpace.cs index dd1dc62a86..97069b856b 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/RgbWorkingSpace.cs +++ b/src/ImageSharp/ColorProfiles/WorkingSpaces/RgbWorkingSpace.cs @@ -1,7 +1,9 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; +using System.Numerics; + +namespace SixLabors.ImageSharp.ColorProfiles.WorkingSpaces; /// /// Base class for all implementations of . @@ -30,26 +32,30 @@ protected RgbWorkingSpace(CieXyz referenceWhite, RgbPrimariesChromaticityCoordin public RgbPrimariesChromaticityCoordinates ChromaticityCoordinates { get; } /// - /// Expands a companded channel to its linear equivalent with respect to the energy. + /// Compresses the linear vectors to their nonlinear equivalents with respect to the energy. + /// + /// The span of vectors. + public abstract void Compress(Span vectors); + + /// + /// Expands the nonlinear vectors to their linear equivalents with respect to the energy. + /// + /// The span of vectors. + public abstract void Expand(Span vectors); + + /// + /// Compresses the linear vector to its nonlinear equivalent with respect to the energy. /// - /// - /// For more info see: - /// - /// - /// The channel value. - /// The representing the linear channel value. - public abstract float Expand(float channel); + /// The vector. + /// The . + public abstract Vector4 Compress(Vector4 vector); /// - /// Compresses an uncompanded channel (linear) to its nonlinear equivalent (depends on the RGB color system). + /// Compresses the linear vector to its nonlinear equivalent with respect to the energy. /// - /// - /// For more info see: - /// - /// - /// The channel value. - /// The representing the nonlinear channel value. - public abstract float Compress(float channel); + /// The vector. + /// The . + public abstract Vector4 Expand(Vector4 vector); /// public override bool Equals(object? obj) diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/SRgbWorkingSpace.cs b/src/ImageSharp/ColorProfiles/WorkingSpaces/SRgbWorkingSpace.cs similarity index 56% rename from src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/SRgbWorkingSpace.cs rename to src/ImageSharp/ColorProfiles/WorkingSpaces/SRgbWorkingSpace.cs index 767157f4cb..b88e6c8983 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/SRgbWorkingSpace.cs +++ b/src/ImageSharp/ColorProfiles/WorkingSpaces/SRgbWorkingSpace.cs @@ -1,10 +1,10 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.ColorSpaces.Companding; +using System.Numerics; +using SixLabors.ImageSharp.ColorProfiles.Companding; -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; +namespace SixLabors.ImageSharp.ColorProfiles.WorkingSpaces; /// /// The sRgb working space. @@ -22,10 +22,14 @@ public SRgbWorkingSpace(CieXyz referenceWhite, RgbPrimariesChromaticityCoordinat } /// - [MethodImpl(InliningOptions.ShortMethod)] - public override float Compress(float channel) => SRgbCompanding.Compress(channel); + public override void Compress(Span vectors) => SRgbCompanding.Compress(vectors); /// - [MethodImpl(InliningOptions.ShortMethod)] - public override float Expand(float channel) => SRgbCompanding.Expand(channel); + public override void Expand(Span vectors) => SRgbCompanding.Expand(vectors); + + /// + public override Vector4 Compress(Vector4 vector) => SRgbCompanding.Compress(vector); + + /// + public override Vector4 Expand(Vector4 vector) => SRgbCompanding.Expand(vector); } diff --git a/src/ImageSharp/ColorSpaces/YCbCr.cs b/src/ImageSharp/ColorProfiles/YCbCr.cs similarity index 52% rename from src/ImageSharp/ColorSpaces/YCbCr.cs rename to src/ImageSharp/ColorProfiles/YCbCr.cs index acb59388fb..03bd1d3120 100644 --- a/src/ImageSharp/ColorSpaces/YCbCr.cs +++ b/src/ImageSharp/ColorProfiles/YCbCr.cs @@ -3,15 +3,17 @@ using System.Numerics; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; -namespace SixLabors.ImageSharp.ColorSpaces; +namespace SixLabors.ImageSharp.ColorProfiles; /// /// Represents an YCbCr (luminance, blue chroma, red chroma) color as defined in the ITU-T T.871 specification for the JFIF use with Jpeg. /// /// /// -public readonly struct YCbCr : IEquatable +[StructLayout(LayoutKind.Sequential)] +public readonly struct YCbCr : IColorProfile { private static readonly Vector3 Min = Vector3.Zero; private static readonly Vector3 Max = new(255); @@ -22,7 +24,7 @@ namespace SixLabors.ImageSharp.ColorSpaces; /// The y luminance component. /// The cb chroma component. /// The cr chroma component. - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public YCbCr(float y, float cb, float cr) : this(new Vector3(y, cb, cr)) { @@ -32,7 +34,7 @@ public YCbCr(float y, float cb, float cr) /// Initializes a new instance of the struct. /// /// The vector representing the y, cb, cr components. - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public YCbCr(Vector3 vector) { vector = Vector3.Clamp(vector, Min, Max); @@ -45,19 +47,19 @@ public YCbCr(Vector3 vector) /// Gets the Y luminance component. /// A value ranging between 0 and 255. /// - public readonly float Y { get; } + public float Y { get; } /// /// Gets the Cb chroma component. /// A value ranging between 0 and 255. /// - public readonly float Cb { get; } + public float Cb { get; } /// /// Gets the Cr chroma component. /// A value ranging between 0 and 255. /// - public readonly float Cr { get; } + public float Cr { get; } /// /// Compares two objects for equality. @@ -77,11 +79,70 @@ public YCbCr(Vector3 vector) /// /// True if the current left is unequal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(YCbCr left, YCbCr right) => !left.Equals(right); /// - [MethodImpl(InliningOptions.ShortMethod)] + public static YCbCr FromProfileConnectingSpace(ColorConversionOptions options, in Rgb source) + { + Vector3 rgb = source.ToScaledVector3() * Max; + float r = rgb.X; + float g = rgb.Y; + float b = rgb.Z; + + float y = (0.299F * r) + (0.587F * g) + (0.114F * b); + float cb = 128F + ((-0.168736F * r) - (0.331264F * g) + (0.5F * b)); + float cr = 128F + ((0.5F * r) - (0.418688F * g) - (0.081312F * b)); + + return new YCbCr(y, cb, cr); + } + + /// + public static void FromProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan source, Span destination) + { + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + + // TODO: We can optimize this by using SIMD + for (int i = 0; i < source.Length; i++) + { + Rgb rgb = source[i]; + destination[i] = FromProfileConnectingSpace(options, in rgb); + } + } + + /// + public Rgb ToProfileConnectingSpace(ColorConversionOptions options) + { + float y = this.Y; + float cb = this.Cb - 128F; + float cr = this.Cr - 128F; + + float r = MathF.Round(y + (1.402F * cr), MidpointRounding.AwayFromZero); + float g = MathF.Round(y - (0.344136F * cb) - (0.714136F * cr), MidpointRounding.AwayFromZero); + float b = MathF.Round(y + (1.772F * cb), MidpointRounding.AwayFromZero); + + return Rgb.FromScaledVector3(new Vector3(r, g, b) / Max); + } + + /// + public static void ToProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan source, Span destination) + { + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + + // TODO: We can optimize this by using SIMD + for (int i = 0; i < source.Length; i++) + { + YCbCr ycbcr = source[i]; + destination[i] = ycbcr.ToProfileConnectingSpace(options); + } + } + + /// + public static ChromaticAdaptionWhitePointSource GetChromaticAdaptionWhitePointSource() + => ChromaticAdaptionWhitePointSource.RgbWorkingSpace; + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] public override int GetHashCode() => HashCode.Combine(this.Y, this.Cb, this.Cr); /// @@ -91,9 +152,9 @@ public YCbCr(Vector3 vector) public override bool Equals(object? obj) => obj is YCbCr other && this.Equals(other); /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals(YCbCr other) - => this.Y.Equals(other.Y) - && this.Cb.Equals(other.Cb) - && this.Cr.Equals(other.Cr); + => this.AsVector3Unsafe() == other.AsVector3Unsafe(); + + private Vector3 AsVector3Unsafe() => Unsafe.As(ref Unsafe.AsRef(in this)); } diff --git a/src/ImageSharp/ColorSpaces/CieLab.cs b/src/ImageSharp/ColorSpaces/CieLab.cs deleted file mode 100644 index 2346b395c0..0000000000 --- a/src/ImageSharp/ColorSpaces/CieLab.cs +++ /dev/null @@ -1,135 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Numerics; -using System.Runtime.CompilerServices; - -namespace SixLabors.ImageSharp.ColorSpaces; - -/// -/// Represents a CIE L*a*b* 1976 color. -/// -/// -public readonly struct CieLab : IEquatable -{ - /// - /// D50 standard illuminant. - /// Used when reference white is not specified explicitly. - /// - public static readonly CieXyz DefaultWhitePoint = Illuminants.D50; - - /// - /// Initializes a new instance of the struct. - /// - /// The lightness dimension. - /// The a (green - magenta) component. - /// The b (blue - yellow) component. - /// Uses as white point. - [MethodImpl(InliningOptions.ShortMethod)] - public CieLab(float l, float a, float b) - : this(l, a, b, DefaultWhitePoint) - { - } - - /// - /// Initializes a new instance of the struct. - /// - /// The lightness dimension. - /// The a (green - magenta) component. - /// The b (blue - yellow) component. - /// The reference white point. - [MethodImpl(InliningOptions.ShortMethod)] - public CieLab(float l, float a, float b, CieXyz whitePoint) - : this(new Vector3(l, a, b), whitePoint) - { - } - - /// - /// Initializes a new instance of the struct. - /// - /// The vector representing the l, a, b components. - /// Uses as white point. - [MethodImpl(InliningOptions.ShortMethod)] - public CieLab(Vector3 vector) - : this(vector, DefaultWhitePoint) - { - } - - /// - /// Initializes a new instance of the struct. - /// - /// The vector representing the l, a, b components. - /// The reference white point. - [MethodImpl(InliningOptions.ShortMethod)] - public CieLab(Vector3 vector, CieXyz whitePoint) - : this() - { - // Not clamping as documentation about this space only indicates "usual" ranges - this.L = vector.X; - this.A = vector.Y; - this.B = vector.Z; - this.WhitePoint = whitePoint; - } - - /// - /// Gets the lightness dimension. - /// A value usually ranging between 0 (black), 100 (diffuse white) or higher (specular white). - /// - public readonly float L { get; } - - /// - /// Gets the a color component. - /// A value usually ranging from -100 to 100. Negative is green, positive magenta. - /// - public readonly float A { get; } - - /// - /// Gets the b color component. - /// A value usually ranging from -100 to 100. Negative is blue, positive is yellow - /// - public readonly float B { get; } - - /// - /// Gets the reference white point of this color - /// - public readonly CieXyz WhitePoint { get; } - - /// - /// Compares two objects for equality. - /// - /// The on the left side of the operand. - /// The on the right side of the operand. - /// - /// True if the current left is equal to the parameter; otherwise, false. - /// - [MethodImpl(InliningOptions.ShortMethod)] - public static bool operator ==(CieLab left, CieLab right) => left.Equals(right); - - /// - /// Compares two objects for inequality - /// - /// The on the left side of the operand. - /// The on the right side of the operand. - /// - /// True if the current left is unequal to the parameter; otherwise, false. - /// - [MethodImpl(InliningOptions.ShortMethod)] - public static bool operator !=(CieLab left, CieLab right) => !left.Equals(right); - - /// - public override int GetHashCode() => HashCode.Combine(this.L, this.A, this.B, this.WhitePoint); - - /// - public override string ToString() => FormattableString.Invariant($"CieLab({this.L:#0.##}, {this.A:#0.##}, {this.B:#0.##})"); - - /// - public override bool Equals(object? obj) => obj is CieLab other && this.Equals(other); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public bool Equals(CieLab other) => - this.L.Equals(other.L) - && this.A.Equals(other.A) - && this.B.Equals(other.B) - && this.WhitePoint.Equals(other.WhitePoint); -} diff --git a/src/ImageSharp/ColorSpaces/CieLchuv.cs b/src/ImageSharp/ColorSpaces/CieLchuv.cs deleted file mode 100644 index 4d47be5aa3..0000000000 --- a/src/ImageSharp/ColorSpaces/CieLchuv.cs +++ /dev/null @@ -1,156 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Numerics; -using System.Runtime.CompilerServices; - -namespace SixLabors.ImageSharp.ColorSpaces; - -/// -/// Represents the CIE L*C*h°, cylindrical form of the CIE L*u*v* 1976 color. -/// -/// -public readonly struct CieLchuv : IEquatable -{ - private static readonly Vector3 Min = new(0, -200, 0); - private static readonly Vector3 Max = new(100, 200, 360); - - /// - /// D50 standard illuminant. - /// Used when reference white is not specified explicitly. - /// - public static readonly CieXyz DefaultWhitePoint = Illuminants.D65; - - /// - /// Initializes a new instance of the struct. - /// - /// The lightness dimension. - /// The chroma, relative saturation. - /// The hue in degrees. - /// Uses as white point. - [MethodImpl(InliningOptions.ShortMethod)] - public CieLchuv(float l, float c, float h) - : this(l, c, h, DefaultWhitePoint) - { - } - - /// - /// Initializes a new instance of the struct. - /// - /// The lightness dimension. - /// The chroma, relative saturation. - /// The hue in degrees. - /// The reference white point. - [MethodImpl(InliningOptions.ShortMethod)] - public CieLchuv(float l, float c, float h, CieXyz whitePoint) - : this(new Vector3(l, c, h), whitePoint) - { - } - - /// - /// Initializes a new instance of the struct. - /// - /// The vector representing the l, c, h components. - /// Uses as white point. - [MethodImpl(InliningOptions.ShortMethod)] - public CieLchuv(Vector3 vector) - : this(vector, DefaultWhitePoint) - { - } - - /// - /// Initializes a new instance of the struct. - /// - /// The vector representing the l, c, h components. - /// The reference white point. - [MethodImpl(InliningOptions.ShortMethod)] - public CieLchuv(Vector3 vector, CieXyz whitePoint) - : this() - { - vector = Vector3.Clamp(vector, Min, Max); - this.L = vector.X; - this.C = vector.Y; - this.H = vector.Z; - this.WhitePoint = whitePoint; - } - - /// - /// Gets the lightness dimension. - /// A value ranging between 0 (black), 100 (diffuse white) or higher (specular white). - /// - public readonly float L { get; } - - /// - /// Gets the a chroma component. - /// A value ranging from 0 to 200. - /// - public readonly float C { get; } - - /// - /// Gets the h° hue component in degrees. - /// A value ranging from 0 to 360. - /// - public readonly float H { get; } - - /// - /// Gets the reference white point of this color - /// - public readonly CieXyz WhitePoint { get; } - - /// - /// Compares two objects for equality. - /// - /// The on the left side of the operand. - /// The on the right side of the operand. - /// - /// True if the current left is equal to the parameter; otherwise, false. - /// - public static bool operator ==(CieLchuv left, CieLchuv right) => left.Equals(right); - - /// - /// Compares two objects for inequality - /// - /// The on the left side of the operand. - /// The on the right side of the operand. - /// - /// True if the current left is unequal to the parameter; otherwise, false. - /// - public static bool operator !=(CieLchuv left, CieLchuv right) => !left.Equals(right); - - /// - public override int GetHashCode() => HashCode.Combine(this.L, this.C, this.H, this.WhitePoint); - - /// - public override string ToString() => FormattableString.Invariant($"CieLchuv({this.L:#0.##}, {this.C:#0.##}, {this.H:#0.##})"); - - /// - public override bool Equals(object? obj) => obj is CieLchuv other && this.Equals(other); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public bool Equals(CieLchuv other) - => this.L.Equals(other.L) - && this.C.Equals(other.C) - && this.H.Equals(other.H) - && this.WhitePoint.Equals(other.WhitePoint); - - /// - /// Computes the saturation of the color (chroma normalized by lightness) - /// - /// - /// A value ranging from 0 to 100. - /// - /// The - [MethodImpl(InliningOptions.ShortMethod)] - public float Saturation() - { - float result = 100 * (this.C / this.L); - - if (float.IsNaN(result)) - { - return 0; - } - - return result; - } -} diff --git a/src/ImageSharp/ColorSpaces/CieLuv.cs b/src/ImageSharp/ColorSpaces/CieLuv.cs deleted file mode 100644 index 04bc96cfa2..0000000000 --- a/src/ImageSharp/ColorSpaces/CieLuv.cs +++ /dev/null @@ -1,136 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Numerics; -using System.Runtime.CompilerServices; - -namespace SixLabors.ImageSharp.ColorSpaces; - -/// -/// The CIE 1976 (L*, u*, v*) color space, commonly known by its abbreviation CIELUV, is a color space adopted by the International -/// Commission on Illumination (CIE) in 1976, as a simple-to-compute transformation of the 1931 CIE XYZ color space, but which -/// attempted perceptual uniformity -/// -/// -public readonly struct CieLuv : IEquatable -{ - /// - /// D65 standard illuminant. - /// Used when reference white is not specified explicitly. - /// - public static readonly CieXyz DefaultWhitePoint = Illuminants.D65; - - /// - /// Initializes a new instance of the struct. - /// - /// The lightness dimension. - /// The blue-yellow chromaticity coordinate of the given whitepoint. - /// The red-green chromaticity coordinate of the given whitepoint. - /// Uses as white point. - [MethodImpl(InliningOptions.ShortMethod)] - public CieLuv(float l, float u, float v) - : this(l, u, v, DefaultWhitePoint) - { - } - - /// - /// Initializes a new instance of the struct. - /// - /// The lightness dimension. - /// The blue-yellow chromaticity coordinate of the given whitepoint. - /// The red-green chromaticity coordinate of the given whitepoint. - /// The reference white point. - [MethodImpl(InliningOptions.ShortMethod)] - public CieLuv(float l, float u, float v, CieXyz whitePoint) - : this(new Vector3(l, u, v), whitePoint) - { - } - - /// - /// Initializes a new instance of the struct. - /// - /// The vector representing the l, u, v components. - /// Uses as white point. - [MethodImpl(InliningOptions.ShortMethod)] - public CieLuv(Vector3 vector) - : this(vector, DefaultWhitePoint) - { - } - - /// - /// Initializes a new instance of the struct. - /// - /// The vector representing the l, u, v components. - /// The reference white point. - [MethodImpl(InliningOptions.ShortMethod)] - public CieLuv(Vector3 vector, CieXyz whitePoint) - { - // Not clamping as documentation about this space only indicates "usual" ranges - this.L = vector.X; - this.U = vector.Y; - this.V = vector.Z; - this.WhitePoint = whitePoint; - } - - /// - /// Gets the lightness dimension - /// A value usually ranging between 0 and 100. - /// - public readonly float L { get; } - - /// - /// Gets the blue-yellow chromaticity coordinate of the given whitepoint. - /// A value usually ranging between -100 and 100. - /// - public readonly float U { get; } - - /// - /// Gets the red-green chromaticity coordinate of the given whitepoint. - /// A value usually ranging between -100 and 100. - /// - public readonly float V { get; } - - /// - /// Gets the reference white point of this color - /// - public readonly CieXyz WhitePoint { get; } - - /// - /// Compares two objects for equality. - /// - /// The on the left side of the operand. - /// The on the right side of the operand. - /// - /// True if the current left is equal to the parameter; otherwise, false. - /// - [MethodImpl(InliningOptions.ShortMethod)] - public static bool operator ==(CieLuv left, CieLuv right) => left.Equals(right); - - /// - /// Compares two objects for inequality. - /// - /// The on the left side of the operand. - /// The on the right side of the operand. - /// - /// True if the current left is unequal to the parameter; otherwise, false. - /// - [MethodImpl(InliningOptions.ShortMethod)] - public static bool operator !=(CieLuv left, CieLuv right) => !left.Equals(right); - - /// - public override int GetHashCode() => HashCode.Combine(this.L, this.U, this.V, this.WhitePoint); - - /// - public override string ToString() => FormattableString.Invariant($"CieLuv({this.L:#0.##}, {this.U:#0.##}, {this.V:#0.##})"); - - /// - public override bool Equals(object? obj) => obj is CieLuv other && this.Equals(other); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public bool Equals(CieLuv other) - => this.L.Equals(other.L) - && this.U.Equals(other.U) - && this.V.Equals(other.V) - && this.WhitePoint.Equals(other.WhitePoint); -} diff --git a/src/ImageSharp/ColorSpaces/Cmyk.cs b/src/ImageSharp/ColorSpaces/Cmyk.cs deleted file mode 100644 index a5aacf38ad..0000000000 --- a/src/ImageSharp/ColorSpaces/Cmyk.cs +++ /dev/null @@ -1,107 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Numerics; -using System.Runtime.CompilerServices; - -namespace SixLabors.ImageSharp.ColorSpaces; - -/// -/// Represents an CMYK (cyan, magenta, yellow, keyline) color. -/// -public readonly struct Cmyk : IEquatable -{ - private static readonly Vector4 Min = Vector4.Zero; - private static readonly Vector4 Max = Vector4.One; - - /// - /// Initializes a new instance of the struct. - /// - /// The cyan component. - /// The magenta component. - /// The yellow component. - /// The keyline black component. - [MethodImpl(InliningOptions.ShortMethod)] - public Cmyk(float c, float m, float y, float k) - : this(new Vector4(c, m, y, k)) - { - } - - /// - /// Initializes a new instance of the struct. - /// - /// The vector representing the c, m, y, k components. - [MethodImpl(InliningOptions.ShortMethod)] - public Cmyk(Vector4 vector) - { - vector = Numerics.Clamp(vector, Min, Max); - this.C = vector.X; - this.M = vector.Y; - this.Y = vector.Z; - this.K = vector.W; - } - - /// - /// Gets the cyan color component. - /// A value ranging between 0 and 1. - /// - public readonly float C { get; } - - /// - /// Gets the magenta color component. - /// A value ranging between 0 and 1. - /// - public readonly float M { get; } - - /// - /// Gets the yellow color component. - /// A value ranging between 0 and 1. - /// - public readonly float Y { get; } - - /// - /// Gets the keyline black color component. - /// A value ranging between 0 and 1. - /// - public readonly float K { get; } - - /// - /// Compares two objects for equality. - /// - /// The on the left side of the operand. - /// The on the right side of the operand. - /// - /// True if the current left is equal to the parameter; otherwise, false. - /// - [MethodImpl(InliningOptions.ShortMethod)] - public static bool operator ==(Cmyk left, Cmyk right) => left.Equals(right); - - /// - /// Compares two objects for inequality. - /// - /// The on the left side of the operand. - /// The on the right side of the operand. - /// - /// True if the current left is unequal to the parameter; otherwise, false. - /// - [MethodImpl(InliningOptions.ShortMethod)] - public static bool operator !=(Cmyk left, Cmyk right) => !left.Equals(right); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public override int GetHashCode() => HashCode.Combine(this.C, this.M, this.Y, this.K); - - /// - public override string ToString() => FormattableString.Invariant($"Cmyk({this.C:#0.##}, {this.M:#0.##}, {this.Y:#0.##}, {this.K:#0.##})"); - - /// - public override bool Equals(object? obj) => obj is Cmyk other && this.Equals(other); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public bool Equals(Cmyk other) - => this.C.Equals(other.C) - && this.M.Equals(other.M) - && this.Y.Equals(other.Y) - && this.K.Equals(other.K); -} diff --git a/src/ImageSharp/ColorSpaces/Companding/GammaCompanding.cs b/src/ImageSharp/ColorSpaces/Companding/GammaCompanding.cs deleted file mode 100644 index e5d98430fd..0000000000 --- a/src/ImageSharp/ColorSpaces/Companding/GammaCompanding.cs +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Runtime.CompilerServices; - -namespace SixLabors.ImageSharp.ColorSpaces.Companding; - -/// -/// Implements gamma companding. -/// -/// -/// -/// -/// -public static class GammaCompanding -{ - /// - /// Expands a companded channel to its linear equivalent with respect to the energy. - /// - /// The channel value. - /// The gamma value. - /// The representing the linear channel value. - [MethodImpl(InliningOptions.ShortMethod)] - public static float Expand(float channel, float gamma) => MathF.Pow(channel, gamma); - - /// - /// Compresses an uncompanded channel (linear) to its nonlinear equivalent. - /// - /// The channel value. - /// The gamma value. - /// The representing the nonlinear channel value. - [MethodImpl(InliningOptions.ShortMethod)] - public static float Compress(float channel, float gamma) => MathF.Pow(channel, 1 / gamma); -} diff --git a/src/ImageSharp/ColorSpaces/Companding/LCompanding.cs b/src/ImageSharp/ColorSpaces/Companding/LCompanding.cs deleted file mode 100644 index db44fd069f..0000000000 --- a/src/ImageSharp/ColorSpaces/Companding/LCompanding.cs +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.ColorSpaces.Companding; - -/// -/// Implements L* companding. -/// -/// -/// For more info see: -/// -/// -/// -public static class LCompanding -{ - /// - /// Expands a companded channel to its linear equivalent with respect to the energy. - /// - /// The channel value. - /// The representing the linear channel value. - [MethodImpl(InliningOptions.ShortMethod)] - public static float Expand(float channel) - => channel <= 0.08F ? (100F * channel) / CieConstants.Kappa : Numerics.Pow3((channel + 0.16F) / 1.16F); - - /// - /// Compresses an uncompanded channel (linear) to its nonlinear equivalent. - /// - /// The channel value - /// The representing the nonlinear channel value. - [MethodImpl(InliningOptions.ShortMethod)] - public static float Compress(float channel) - => channel <= CieConstants.Epsilon ? (channel * CieConstants.Kappa) / 100F : (1.16F * MathF.Pow(channel, 0.3333333F)) - 0.16F; -} diff --git a/src/ImageSharp/ColorSpaces/Companding/Rec2020Companding.cs b/src/ImageSharp/ColorSpaces/Companding/Rec2020Companding.cs deleted file mode 100644 index 4500976189..0000000000 --- a/src/ImageSharp/ColorSpaces/Companding/Rec2020Companding.cs +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Runtime.CompilerServices; - -namespace SixLabors.ImageSharp.ColorSpaces.Companding; - -/// -/// Implements Rec. 2020 companding function. -/// -/// -/// -/// -public static class Rec2020Companding -{ - private const float Alpha = 1.09929682680944F; - private const float AlphaMinusOne = Alpha - 1F; - private const float Beta = 0.018053968510807F; - private const float InverseBeta = Beta * 4.5F; - private const float Epsilon = 1 / 0.45F; - - /// - /// Expands a companded channel to its linear equivalent with respect to the energy. - /// - /// The channel value. - /// The representing the linear channel value. - [MethodImpl(InliningOptions.ShortMethod)] - public static float Expand(float channel) - => channel < InverseBeta ? channel / 4.5F : MathF.Pow((channel + AlphaMinusOne) / Alpha, Epsilon); - - /// - /// Compresses an uncompanded channel (linear) to its nonlinear equivalent. - /// - /// The channel value. - /// The representing the nonlinear channel value. - [MethodImpl(InliningOptions.ShortMethod)] - public static float Compress(float channel) - => channel < Beta ? 4.5F * channel : (Alpha * MathF.Pow(channel, 0.45F)) - AlphaMinusOne; -} diff --git a/src/ImageSharp/ColorSpaces/Companding/Rec709Companding.cs b/src/ImageSharp/ColorSpaces/Companding/Rec709Companding.cs deleted file mode 100644 index 6e4767bcd9..0000000000 --- a/src/ImageSharp/ColorSpaces/Companding/Rec709Companding.cs +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Runtime.CompilerServices; - -namespace SixLabors.ImageSharp.ColorSpaces.Companding; - -/// -/// Implements the Rec. 709 companding function. -/// -/// -/// http://en.wikipedia.org/wiki/Rec._709 -/// -public static class Rec709Companding -{ - private const float Epsilon = 1 / 0.45F; - - /// - /// Expands a companded channel to its linear equivalent with respect to the energy. - /// - /// The channel value. - /// The representing the linear channel value. - [MethodImpl(InliningOptions.ShortMethod)] - public static float Expand(float channel) - => channel < 0.081F ? channel / 4.5F : MathF.Pow((channel + 0.099F) / 1.099F, Epsilon); - - /// - /// Compresses an uncompanded channel (linear) to its nonlinear equivalent. - /// - /// The channel value. - /// The representing the nonlinear channel value. - [MethodImpl(InliningOptions.ShortMethod)] - public static float Compress(float channel) - => channel < 0.018F ? 4.5F * channel : (1.099F * MathF.Pow(channel, 0.45F)) - 0.099F; -} diff --git a/src/ImageSharp/ColorSpaces/Companding/SRgbCompanding.cs b/src/ImageSharp/ColorSpaces/Companding/SRgbCompanding.cs deleted file mode 100644 index 4c3923c888..0000000000 --- a/src/ImageSharp/ColorSpaces/Companding/SRgbCompanding.cs +++ /dev/null @@ -1,230 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Numerics; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using System.Runtime.Intrinsics; -using System.Runtime.Intrinsics.X86; - -namespace SixLabors.ImageSharp.ColorSpaces.Companding; - -/// -/// Implements sRGB companding. -/// -/// -/// For more info see: -/// -/// -/// -public static class SRgbCompanding -{ - private const int Length = Scale + 2; // 256kb @ 16bit precision. - private const int Scale = (1 << 16) - 1; - - private static readonly Lazy LazyCompressTable = new( - () => - { - float[] result = new float[Length]; - - for (int i = 0; i < result.Length; i++) - { - double d = (double)i / Scale; - if (d <= (0.04045 / 12.92)) - { - d *= 12.92; - } - else - { - d = (1.055 * Math.Pow(d, 1.0 / 2.4)) - 0.055; - } - - result[i] = (float)d; - } - - return result; - }, - true); - - private static readonly Lazy LazyExpandTable = new( - () => - { - float[] result = new float[Length]; - - for (int i = 0; i < result.Length; i++) - { - double d = (double)i / Scale; - if (d <= 0.04045) - { - d /= 12.92; - } - else - { - d = Math.Pow((d + 0.055) / 1.055, 2.4); - } - - result[i] = (float)d; - } - - return result; - }, - true); - - private static float[] ExpandTable => LazyExpandTable.Value; - - private static float[] CompressTable => LazyCompressTable.Value; - - /// - /// Expands the companded vectors to their linear equivalents with respect to the energy. - /// - /// The span of vectors. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void Expand(Span vectors) - { - if (Avx2.IsSupported && vectors.Length >= 2) - { - CompandAvx2(vectors, ExpandTable); - - if (Numerics.Modulo2(vectors.Length) != 0) - { - // Vector4 fits neatly in pairs. Any overlap has to be equal to 1. - Expand(ref MemoryMarshal.GetReference(vectors[^1..])); - } - } - else - { - CompandScalar(vectors, ExpandTable); - } - } - - /// - /// Compresses the uncompanded vectors to their nonlinear equivalents with respect to the energy. - /// - /// The span of vectors. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static unsafe void Compress(Span vectors) - { - if (Avx2.IsSupported && vectors.Length >= 2) - { - CompandAvx2(vectors, CompressTable); - - if (Numerics.Modulo2(vectors.Length) != 0) - { - // Vector4 fits neatly in pairs. Any overlap has to be equal to 1. - Compress(ref MemoryMarshal.GetReference(vectors[^1..])); - } - } - else - { - CompandScalar(vectors, CompressTable); - } - } - - /// - /// Expands a companded vector to its linear equivalent with respect to the energy. - /// - /// The vector. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void Expand(ref Vector4 vector) - { - // Alpha is already a linear representation of opacity so we do not want to convert it. - vector.X = Expand(vector.X); - vector.Y = Expand(vector.Y); - vector.Z = Expand(vector.Z); - } - - /// - /// Compresses an uncompanded vector (linear) to its nonlinear equivalent. - /// - /// The vector. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void Compress(ref Vector4 vector) - { - // Alpha is already a linear representation of opacity so we do not want to convert it. - vector.X = Compress(vector.X); - vector.Y = Compress(vector.Y); - vector.Z = Compress(vector.Z); - } - - /// - /// Expands a companded channel to its linear equivalent with respect to the energy. - /// - /// The channel value. - /// The representing the linear channel value. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static float Expand(float channel) - => channel <= 0.04045F ? channel / 12.92F : MathF.Pow((channel + 0.055F) / 1.055F, 2.4F); - - /// - /// Compresses an uncompanded channel (linear) to its nonlinear equivalent. - /// - /// The channel value. - /// The representing the nonlinear channel value. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static float Compress(float channel) - => channel <= 0.0031308F ? 12.92F * channel : (1.055F * MathF.Pow(channel, 0.416666666666667F)) - 0.055F; - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static unsafe void CompandAvx2(Span vectors, float[] table) - { - fixed (float* tablePointer = &MemoryMarshal.GetArrayDataReference(table)) - { - var scale = Vector256.Create((float)Scale); - Vector256 zero = Vector256.Zero; - var offset = Vector256.Create(1); - - // Divide by 2 as 4 elements per Vector4 and 8 per Vector256 - ref Vector256 vectorsBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(vectors)); - ref Vector256 vectorsLast = ref Unsafe.Add(ref vectorsBase, (uint)vectors.Length / 2u); - - while (Unsafe.IsAddressLessThan(ref vectorsBase, ref vectorsLast)) - { - Vector256 multiplied = Avx.Multiply(scale, vectorsBase); - multiplied = Avx.Min(Avx.Max(zero, multiplied), scale); - - Vector256 truncated = Avx.ConvertToVector256Int32WithTruncation(multiplied); - Vector256 truncatedF = Avx.ConvertToVector256Single(truncated); - - Vector256 low = Avx2.GatherVector256(tablePointer, truncated, sizeof(float)); - Vector256 high = Avx2.GatherVector256(tablePointer, Avx2.Add(truncated, offset), sizeof(float)); - - // Alpha is already a linear representation of opacity so we do not want to convert it. - Vector256 companded = Numerics.Lerp(low, high, Avx.Subtract(multiplied, truncatedF)); - vectorsBase = Avx.Blend(companded, vectorsBase, Numerics.BlendAlphaControl); - vectorsBase = ref Unsafe.Add(ref vectorsBase, 1); - } - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static unsafe void CompandScalar(Span vectors, float[] table) - { - fixed (float* tablePointer = &MemoryMarshal.GetArrayDataReference(table)) - { - Vector4 zero = Vector4.Zero; - var scale = new Vector4(Scale); - ref Vector4 vectorsBase = ref MemoryMarshal.GetReference(vectors); - ref Vector4 vectorsLast = ref Unsafe.Add(ref vectorsBase, (uint)vectors.Length); - - while (Unsafe.IsAddressLessThan(ref vectorsBase, ref vectorsLast)) - { - Vector4 multiplied = Numerics.Clamp(vectorsBase * Scale, zero, scale); - - float f0 = multiplied.X; - float f1 = multiplied.Y; - float f2 = multiplied.Z; - - uint i0 = (uint)f0; - uint i1 = (uint)f1; - uint i2 = (uint)f2; - - // Alpha is already a linear representation of opacity so we do not want to convert it. - vectorsBase.X = Numerics.Lerp(tablePointer[i0], tablePointer[i0 + 1], f0 - (int)i0); - vectorsBase.Y = Numerics.Lerp(tablePointer[i1], tablePointer[i1 + 1], f1 - (int)i1); - vectorsBase.Z = Numerics.Lerp(tablePointer[i2], tablePointer[i2 + 1], f2 - (int)i2); - - vectorsBase = ref Unsafe.Add(ref vectorsBase, 1); - } - } - } -} diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Adapt.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Adapt.cs deleted file mode 100644 index b4934e44ac..0000000000 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Adapt.cs +++ /dev/null @@ -1,159 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; - -/// -/// Performs chromatic adaptation on the various color spaces. -/// -public partial class ColorSpaceConverter -{ - /// - /// Performs chromatic adaptation of given color. - /// Target white point is . - /// - /// The color to adapt - /// The source white point. - /// The adapted color - public CieXyz Adapt(in CieXyz color, in CieXyz sourceWhitePoint) => this.Adapt(color, sourceWhitePoint, this.whitePoint); - - /// - /// Performs chromatic adaptation of given color. - /// Target white point is . - /// - /// The color to adapt - /// The source white point. - /// The target white point. - /// The adapted color - public CieXyz Adapt(in CieXyz color, in CieXyz sourceWhitePoint, in CieXyz targetWhitePoint) - { - if (!this.performChromaticAdaptation || sourceWhitePoint.Equals(targetWhitePoint)) - { - return color; - } - - // We know that chromaticAdaption is not null because performChromaticAdaption is checked - return this.chromaticAdaptation!.Transform(color, sourceWhitePoint, targetWhitePoint); - } - - /// - /// Adapts color from the source white point to white point set in . - /// - /// The color to adapt - /// The adapted color - public CieLab Adapt(in CieLab color) - { - if (!this.performChromaticAdaptation || color.WhitePoint.Equals(this.targetLabWhitePoint)) - { - return color; - } - - var xyzColor = this.ToCieXyz(color); - return this.ToCieLab(xyzColor); - } - - /// - /// Adapts color from the source white point to white point set in . - /// - /// The color to adapt - /// The adapted color - public CieLch Adapt(in CieLch color) - { - if (!this.performChromaticAdaptation || color.WhitePoint.Equals(this.targetLabWhitePoint)) - { - return color; - } - - var labColor = this.ToCieLab(color); - return this.ToCieLch(labColor); - } - - /// - /// Adapts color from the source white point to white point set in . - /// - /// The color to adapt - /// The adapted color - public CieLchuv Adapt(in CieLchuv color) - { - if (!this.performChromaticAdaptation || color.WhitePoint.Equals(this.targetLabWhitePoint)) - { - return color; - } - - var luvColor = this.ToCieLuv(color); - return this.ToCieLchuv(luvColor); - } - - /// - /// Adapts color from the source white point to white point set in . - /// - /// The color to adapt - /// The adapted color - public CieLuv Adapt(in CieLuv color) - { - if (!this.performChromaticAdaptation || color.WhitePoint.Equals(this.targetLuvWhitePoint)) - { - return color; - } - - var xyzColor = this.ToCieXyz(color); - return this.ToCieLuv(xyzColor); - } - - /// - /// Adapts color from the source white point to white point set in . - /// - /// The color to adapt - /// The adapted color - public HunterLab Adapt(in HunterLab color) - { - if (!this.performChromaticAdaptation || color.WhitePoint.Equals(this.targetHunterLabWhitePoint)) - { - return color; - } - - var xyzColor = this.ToCieXyz(color); - return this.ToHunterLab(xyzColor); - } - - /// - /// Adapts a color from the source working space to working space set in . - /// - /// The color to adapt - /// The adapted color - public LinearRgb Adapt(in LinearRgb color) - { - if (!this.performChromaticAdaptation || color.WorkingSpace.Equals(this.targetRgbWorkingSpace)) - { - return color; - } - - // Conversion to XYZ - LinearRgbToCieXyzConverter converterToXYZ = GetLinearRgbToCieXyzConverter(color.WorkingSpace); - CieXyz unadapted = converterToXYZ.Convert(color); - - // Adaptation - // We know that chromaticAdaption is not null because performChromaticAdaption is checked - CieXyz adapted = this.chromaticAdaptation!.Transform(unadapted, color.WorkingSpace.WhitePoint, this.targetRgbWorkingSpace.WhitePoint); - - // Conversion back to RGB - return this.cieXyzToLinearRgbConverter.Convert(adapted); - } - - /// - /// Adapts an color from the source working space to working space set in . - /// - /// The color to adapt - /// The adapted color - public Rgb Adapt(in Rgb color) - { - if (!this.performChromaticAdaptation) - { - return color; - } - - var linearInput = ToLinearRgb(color); - LinearRgb linearOutput = this.Adapt(linearInput); - return ToRgb(linearOutput); - } -} diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLab.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLab.cs deleted file mode 100644 index 54667ca2af..0000000000 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLab.cs +++ /dev/null @@ -1,441 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; - -/// -/// Allows conversion to . -/// -public partial class ColorSpaceConverter -{ - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieLab ToCieLab(in CieLch color) - { - // Conversion (preserving white point) - CieLab unadapted = CieLchToCieLabConverter.Convert(color); - - return this.Adapt(unadapted); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLch sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLab destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLch sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLab dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLab(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieLab ToCieLab(in CieLchuv color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return this.ToCieLab(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLab destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLchuv sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLab dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLab(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieLab ToCieLab(in CieLuv color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return this.ToCieLab(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLab destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLuv sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLab dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLab(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieLab ToCieLab(in CieXyy color) - { - CieXyz xyzColor = ToCieXyz(color); - - return this.ToCieLab(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLab destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieXyy sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLab dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLab(sp); - } - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public CieLab ToCieLab(in CieXyz color) - { - CieXyz adapted = this.Adapt(color, this.whitePoint, this.targetLabWhitePoint); - - return this.cieXyzToCieLabConverter.Convert(adapted); - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLab destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLab dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLab(sp); - } - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public CieLab ToCieLab(in Cmyk color) - { - CieXyz xyzColor = this.ToCieXyz(color); - return this.ToCieLab(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLab destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLab dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLab(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieLab ToCieLab(in Hsl color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return this.ToCieLab(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Hsl sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLab destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Hsl sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLab dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLab(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieLab ToCieLab(in Hsv color) - { - CieXyz xyzColor = this.ToCieXyz(color); - return this.ToCieLab(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Hsv sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLab destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Hsv sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLab dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLab(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieLab ToCieLab(in HunterLab color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return this.ToCieLab(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLab destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref HunterLab sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLab dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLab(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieLab ToCieLab(in Lms color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return this.ToCieLab(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Lms sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLab destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Lms sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLab dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLab(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieLab ToCieLab(in LinearRgb color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return this.ToCieLab(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLab destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLab dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLab(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieLab ToCieLab(in Rgb color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return this.ToCieLab(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Rgb sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLab destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Rgb sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLab dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLab(sp); - } - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public CieLab ToCieLab(in YCbCr color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return this.ToCieLab(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLab destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref YCbCr sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLab dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLab(sp); - } - } -} diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLch.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLch.cs deleted file mode 100644 index 9949b5d91b..0000000000 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLch.cs +++ /dev/null @@ -1,441 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; - -/// -/// Allows conversion to . -/// -public partial class ColorSpaceConverter -{ - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public CieLch ToCieLch(in CieLab color) - { - CieLab adapted = this.Adapt(color); - - return CieLabToCieLchConverter.Convert(adapted); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLab sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLch destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLab sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLch dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLch(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieLch ToCieLch(in CieLchuv color) - { - var xyzColor = this.ToCieXyz(color); - - return this.ToCieLch(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLch destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLchuv sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLch dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLch(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieLch ToCieLch(in CieLuv color) - { - var xyzColor = this.ToCieXyz(color); - - return this.ToCieLch(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLch destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLuv sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLch dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLch(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieLch ToCieLch(in CieXyy color) - { - var xyzColor = ToCieXyz(color); - - return this.ToCieLch(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLch destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieXyy sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLch dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLch(sp); - } - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public CieLch ToCieLch(in CieXyz color) - { - var labColor = this.ToCieLab(color); - - return this.ToCieLch(labColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLch destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLch dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLch(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieLch ToCieLch(in Cmyk color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToCieLch(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLch destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLch dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLch(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieLch ToCieLch(in Hsl color) - { - var xyzColor = this.ToCieXyz(color); - - return this.ToCieLch(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Hsl sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLch destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Hsl sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLch dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLch(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieLch ToCieLch(in Hsv color) - { - var xyzColor = this.ToCieXyz(color); - - return this.ToCieLch(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Hsv sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLch destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Hsv sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLch dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLch(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieLch ToCieLch(in HunterLab color) - { - var xyzColor = this.ToCieXyz(color); - - return this.ToCieLch(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLch destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref HunterLab sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLch dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLch(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieLch ToCieLch(in LinearRgb color) - { - var xyzColor = this.ToCieXyz(color); - - return this.ToCieLch(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLch destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLch dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLch(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieLch ToCieLch(in Lms color) - { - var xyzColor = this.ToCieXyz(color); - - return this.ToCieLch(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Lms sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLch destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Lms sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLch dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLch(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieLch ToCieLch(in Rgb color) - { - var xyzColor = this.ToCieXyz(color); - - return this.ToCieLch(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Rgb sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLch destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Rgb sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLch dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLch(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieLch ToCieLch(in YCbCr color) - { - var xyzColor = this.ToCieXyz(color); - - return this.ToCieLch(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLch destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref YCbCr sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLch dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLch(sp); - } - } -} diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLchuv.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLchuv.cs deleted file mode 100644 index 4b856d1189..0000000000 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLchuv.cs +++ /dev/null @@ -1,441 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; - -/// -/// Allows conversion to . -/// -public partial class ColorSpaceConverter -{ - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public CieLchuv ToCieLchuv(in CieLab color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return this.ToCieLchuv(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLab sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLab sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLchuv dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLchuv(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieLchuv ToCieLchuv(in CieLch color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return this.ToCieLchuv(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLch sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLch sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLchuv dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLchuv(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieLchuv ToCieLchuv(in CieLuv color) - { - CieLuv adapted = this.Adapt(color); - - return CieLuvToCieLchuvConverter.Convert(adapted); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLuv sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLchuv dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLchuv(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieLchuv ToCieLchuv(in CieXyy color) - { - CieXyz xyzColor = ToCieXyz(color); - - return this.ToCieLchuv(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieXyy sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLchuv dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLchuv(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieLchuv ToCieLchuv(in CieXyz color) - { - CieLuv luvColor = this.ToCieLuv(color); - - return this.ToCieLchuv(luvColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLchuv dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLchuv(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieLchuv ToCieLchuv(in Cmyk color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return this.ToCieLchuv(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLchuv dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLchuv(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieLchuv ToCieLchuv(in Hsl color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return this.ToCieLchuv(xyzColor); - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Hsl sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Hsl sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLchuv dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLchuv(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieLchuv ToCieLchuv(in Hsv color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return this.ToCieLchuv(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Hsv sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Hsv sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLchuv dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLchuv(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieLchuv ToCieLchuv(in HunterLab color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return this.ToCieLchuv(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref HunterLab sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLchuv dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLchuv(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieLchuv ToCieLchuv(in LinearRgb color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return this.ToCieLchuv(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLchuv dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLchuv(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieLchuv ToCieLchuv(in Lms color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return this.ToCieLchuv(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Lms sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Lms sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLchuv dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLchuv(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieLchuv ToCieLchuv(in Rgb color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return this.ToCieLchuv(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Rgb sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Rgb sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLchuv dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLchuv(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieLchuv ToCieLchuv(in YCbCr color) - { - CieXyz xyzColor = this.ToCieXyz(color); - return this.ToCieLchuv(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref YCbCr sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLchuv dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLchuv(sp); - } - } -} diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLuv.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLuv.cs deleted file mode 100644 index 2e8029f64a..0000000000 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLuv.cs +++ /dev/null @@ -1,435 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; - -/// -/// Allows conversion to . -/// -public partial class ColorSpaceConverter -{ - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieLuv ToCieLuv(in CieLab color) - { - CieXyz xyzColor = this.ToCieXyz(color); - return this.ToCieLuv(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLab sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLuv destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLab sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLuv dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLuv(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieLuv ToCieLuv(in CieLch color) - { - CieXyz xyzColor = this.ToCieXyz(color); - return this.ToCieLuv(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLch sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLuv destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLch sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLuv dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLuv(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieLuv ToCieLuv(in CieLchuv color) - { - // Conversion (preserving white point) - CieLuv unadapted = CieLchuvToCieLuvConverter.Convert(color); - - // Adaptation - return this.Adapt(unadapted); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLuv destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLchuv sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLuv dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLuv(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieLuv ToCieLuv(in CieXyy color) - { - CieXyz xyzColor = ToCieXyz(color); - return this.ToCieLuv(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLuv destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieXyy sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLuv dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLuv(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieLuv ToCieLuv(in CieXyz color) - { - // Adaptation - CieXyz adapted = this.Adapt(color, this.whitePoint, this.targetLuvWhitePoint); - - // Conversion - return this.cieXyzToCieLuvConverter.Convert(adapted); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLuv destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLuv dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLuv(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieLuv ToCieLuv(in Cmyk color) - { - CieXyz xyzColor = this.ToCieXyz(color); - return this.ToCieLuv(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLuv destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLuv dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLuv(sp); - } - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public CieLuv ToCieLuv(in Hsl color) - { - CieXyz xyzColor = this.ToCieXyz(color); - return this.ToCieLuv(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Hsl sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLuv destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Hsl sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLuv dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLuv(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieLuv ToCieLuv(in Hsv color) - { - CieXyz xyzColor = this.ToCieXyz(color); - return this.ToCieLuv(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Hsv sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLuv destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Hsv sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLuv dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLuv(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieLuv ToCieLuv(in HunterLab color) - { - CieXyz xyzColor = this.ToCieXyz(color); - return this.ToCieLuv(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLuv destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref HunterLab sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLuv dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLuv(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieLuv ToCieLuv(in Lms color) - { - CieXyz xyzColor = this.ToCieXyz(color); - return this.ToCieLuv(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Lms sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLuv destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Lms sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLuv dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLuv(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieLuv ToCieLuv(in LinearRgb color) - { - CieXyz xyzColor = this.ToCieXyz(color); - return this.ToCieLuv(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLuv destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLuv dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLuv(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieLuv ToCieLuv(in Rgb color) - { - CieXyz xyzColor = this.ToCieXyz(color); - return this.ToCieLuv(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Rgb sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLuv destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Rgb sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLuv dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLuv(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieLuv ToCieLuv(in YCbCr color) - { - CieXyz xyzColor = this.ToCieXyz(color); - return this.ToCieLuv(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors. - /// The span to the destination colors. - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLuv destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref YCbCr sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLuv dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLuv(sp); - } - } -} diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyy.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyy.cs deleted file mode 100644 index 13b2a225c3..0000000000 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyy.cs +++ /dev/null @@ -1,437 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; - -/// -/// Allows conversion to . -/// -public partial class ColorSpaceConverter -{ - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public CieXyy ToCieXyy(in CieLab color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return ToCieXyy(xyzColor); - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLab sourceRef = ref MemoryMarshal.GetReference(source); - ref CieXyy destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLab sp = ref Unsafe.Add(ref sourceRef, i); - ref CieXyy dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieXyy(sp); - } - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public CieXyy ToCieXyy(in CieLch color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return ToCieXyy(xyzColor); - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLch sourceRef = ref MemoryMarshal.GetReference(source); - ref CieXyy destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLch sp = ref Unsafe.Add(ref sourceRef, i); - ref CieXyy dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieXyy(sp); - } - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public CieXyy ToCieXyy(in CieLchuv color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return ToCieXyy(xyzColor); - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source); - ref CieXyy destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLchuv sp = ref Unsafe.Add(ref sourceRef, i); - ref CieXyy dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieXyy(sp); - } - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public CieXyy ToCieXyy(in CieLuv color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return ToCieXyy(xyzColor); - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source); - ref CieXyy destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLuv sp = ref Unsafe.Add(ref sourceRef, i); - ref CieXyy dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieXyy(sp); - } - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public static CieXyy ToCieXyy(in CieXyz color) => CieXyzAndCieXyyConverter.Convert(color); - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public static void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source); - ref CieXyy destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i); - ref CieXyy dp = ref Unsafe.Add(ref destRef, i); - dp = ToCieXyy(sp); - } - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public CieXyy ToCieXyy(in Cmyk color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return ToCieXyy(xyzColor); - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source); - ref CieXyy destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i); - ref CieXyy dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieXyy(sp); - } - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public CieXyy ToCieXyy(Hsl color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return ToCieXyy(xyzColor); - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Hsl sourceRef = ref MemoryMarshal.GetReference(source); - ref CieXyy destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Hsl sp = ref Unsafe.Add(ref sourceRef, i); - ref CieXyy dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieXyy(sp); - } - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public CieXyy ToCieXyy(in Hsv color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return ToCieXyy(xyzColor); - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Hsv sourceRef = ref MemoryMarshal.GetReference(source); - ref CieXyy destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Hsv sp = ref Unsafe.Add(ref sourceRef, i); - ref CieXyy dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieXyy(sp); - } - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public CieXyy ToCieXyy(in HunterLab color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return ToCieXyy(xyzColor); - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source); - ref CieXyy destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref HunterLab sp = ref Unsafe.Add(ref sourceRef, i); - ref CieXyy dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieXyy(sp); - } - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public CieXyy ToCieXyy(in LinearRgb color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return ToCieXyy(xyzColor); - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source); - ref CieXyy destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i); - ref CieXyy dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieXyy(sp); - } - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public CieXyy ToCieXyy(in Lms color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return ToCieXyy(xyzColor); - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Lms sourceRef = ref MemoryMarshal.GetReference(source); - ref CieXyy destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Lms sp = ref Unsafe.Add(ref sourceRef, i); - ref CieXyy dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieXyy(sp); - } - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public CieXyy ToCieXyy(in Rgb color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return ToCieXyy(xyzColor); - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Rgb sourceRef = ref MemoryMarshal.GetReference(source); - ref CieXyy destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Rgb sp = ref Unsafe.Add(ref sourceRef, i); - ref CieXyy dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieXyy(sp); - } - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public CieXyy ToCieXyy(in YCbCr color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return ToCieXyy(xyzColor); - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source); - ref CieXyy destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref YCbCr sp = ref Unsafe.Add(ref sourceRef, i); - ref CieXyy dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieXyy(sp); - } - } -} diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyz.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyz.cs deleted file mode 100644 index 2212ca2e58..0000000000 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyz.cs +++ /dev/null @@ -1,458 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Collections.Concurrent; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; - -/// -/// Allows conversion to . -/// -public partial class ColorSpaceConverter -{ - private static readonly ConcurrentDictionary ConverterCache = new(); - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieXyz ToCieXyz(in CieLab color) - { - // Conversion - CieXyz unadapted = CieLabToCieXyzConverter.Convert(color); - - // Adaptation - return this.Adapt(unadapted, color.WhitePoint); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLab sourceRef = ref MemoryMarshal.GetReference(source); - ref CieXyz destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLab sp = ref Unsafe.Add(ref sourceRef, i); - ref CieXyz dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieXyz(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieXyz ToCieXyz(in CieLch color) - { - // Conversion to Lab - CieLab labColor = CieLchToCieLabConverter.Convert(color); - - // Conversion to XYZ (incl. adaptation) - return this.ToCieXyz(labColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLch sourceRef = ref MemoryMarshal.GetReference(source); - ref CieXyz destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLch sp = ref Unsafe.Add(ref sourceRef, i); - ref CieXyz dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieXyz(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieXyz ToCieXyz(in CieLchuv color) - { - // Conversion to Luv - CieLuv luvColor = CieLchuvToCieLuvConverter.Convert(color); - - // Conversion to XYZ (incl. adaptation) - return this.ToCieXyz(luvColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source); - ref CieXyz destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLchuv sp = ref Unsafe.Add(ref sourceRef, i); - ref CieXyz dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieXyz(sp); - } - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public CieXyz ToCieXyz(in CieLuv color) - { - // Conversion - CieXyz unadapted = CieLuvToCieXyzConverter.Convert(color); - - // Adaptation - return this.Adapt(unadapted, color.WhitePoint); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source); - ref CieXyz destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLuv sp = ref Unsafe.Add(ref sourceRef, i); - ref CieXyz dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieXyz(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public static CieXyz ToCieXyz(in CieXyy color) - - // Conversion - => CieXyzAndCieXyyConverter.Convert(color); - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public static void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source); - ref CieXyz destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieXyy sp = ref Unsafe.Add(ref sourceRef, i); - ref CieXyz dp = ref Unsafe.Add(ref destRef, i); - dp = ToCieXyz(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieXyz ToCieXyz(in Cmyk color) - { - Rgb rgb = ToRgb(color); - - return this.ToCieXyz(rgb); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source); - ref CieXyz destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i); - ref CieXyz dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieXyz(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieXyz ToCieXyz(in Hsl color) - { - Rgb rgb = ToRgb(color); - - return this.ToCieXyz(rgb); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors. - /// The span to the destination colors. - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Hsl sourceRef = ref MemoryMarshal.GetReference(source); - ref CieXyz destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Hsl sp = ref Unsafe.Add(ref sourceRef, i); - ref CieXyz dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieXyz(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieXyz ToCieXyz(in Hsv color) - { - // Conversion - Rgb rgb = ToRgb(color); - - return this.ToCieXyz(rgb); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Hsv sourceRef = ref MemoryMarshal.GetReference(source); - ref CieXyz destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Hsv sp = ref Unsafe.Add(ref sourceRef, i); - ref CieXyz dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieXyz(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieXyz ToCieXyz(in HunterLab color) - { - CieXyz unadapted = HunterLabToCieXyzConverter.Convert(color); - - return this.Adapt(unadapted, color.WhitePoint); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source); - ref CieXyz destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref HunterLab sp = ref Unsafe.Add(ref sourceRef, i); - ref CieXyz dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieXyz(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieXyz ToCieXyz(in LinearRgb color) - { - // Conversion - LinearRgbToCieXyzConverter converter = GetLinearRgbToCieXyzConverter(color.WorkingSpace); - CieXyz unadapted = converter.Convert(color); - - return this.Adapt(unadapted, color.WorkingSpace.WhitePoint); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors. - /// The span to the destination colors. - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source); - ref CieXyz destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i); - ref CieXyz dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieXyz(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieXyz ToCieXyz(in Lms color) - => this.cieXyzAndLmsConverter.Convert(color); - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Lms sourceRef = ref MemoryMarshal.GetReference(source); - ref CieXyz destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Lms sp = ref Unsafe.Add(ref sourceRef, i); - ref CieXyz dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieXyz(sp); - } - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public CieXyz ToCieXyz(in Rgb color) - { - // Conversion - LinearRgb linear = RgbToLinearRgbConverter.Convert(color); - return this.ToCieXyz(linear); - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Rgb sourceRef = ref MemoryMarshal.GetReference(source); - ref CieXyz destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Rgb sp = ref Unsafe.Add(ref sourceRef, i); - ref CieXyz dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieXyz(sp); - } - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public CieXyz ToCieXyz(in YCbCr color) - { - Rgb rgb = this.ToRgb(color); - - return this.ToCieXyz(rgb); - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source); - ref CieXyz destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref YCbCr sp = ref Unsafe.Add(ref sourceRef, i); - ref CieXyz dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieXyz(sp); - } - } - - /// - /// Gets the correct converter for the given rgb working space. - /// - /// The source working space - /// The - private static LinearRgbToCieXyzConverter GetLinearRgbToCieXyzConverter(RgbWorkingSpace workingSpace) - => ConverterCache.GetOrAdd(workingSpace, (key) => new LinearRgbToCieXyzConverter(key)); -} diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Cmyk.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Cmyk.cs deleted file mode 100644 index ea9a5d734b..0000000000 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Cmyk.cs +++ /dev/null @@ -1,437 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; - -/// -/// Allows conversion to . -/// -public partial class ColorSpaceConverter -{ - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public Cmyk ToCmyk(in CieLab color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return this.ToCmyk(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLab sourceRef = ref MemoryMarshal.GetReference(source); - ref Cmyk destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLab sp = ref Unsafe.Add(ref sourceRef, i); - ref Cmyk dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCmyk(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public Cmyk ToCmyk(in CieLch color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return this.ToCmyk(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLch sourceRef = ref MemoryMarshal.GetReference(source); - ref Cmyk destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLch sp = ref Unsafe.Add(ref sourceRef, i); - ref Cmyk dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCmyk(sp); - } - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Cmyk ToCmyk(in CieLchuv color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return this.ToCmyk(xyzColor); - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source); - ref Cmyk destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLchuv sp = ref Unsafe.Add(ref sourceRef, i); - ref Cmyk dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCmyk(sp); - } - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Cmyk ToCmyk(in CieLuv color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return this.ToCmyk(xyzColor); - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source); - ref Cmyk destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLuv sp = ref Unsafe.Add(ref sourceRef, i); - ref Cmyk dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCmyk(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public Cmyk ToCmyk(in CieXyy color) - { - CieXyz xyzColor = ToCieXyz(color); - - return this.ToCmyk(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source); - ref Cmyk destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieXyy sp = ref Unsafe.Add(ref sourceRef, i); - ref Cmyk dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCmyk(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public Cmyk ToCmyk(in CieXyz color) - { - Rgb rgb = this.ToRgb(color); - - return CmykAndRgbConverter.Convert(rgb); - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source); - ref Cmyk destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i); - ref Cmyk dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCmyk(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public static Cmyk ToCmyk(in Hsl color) - { - Rgb rgb = ToRgb(color); - - return CmykAndRgbConverter.Convert(rgb); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public static void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Hsl sourceRef = ref MemoryMarshal.GetReference(source); - ref Cmyk destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Hsl sp = ref Unsafe.Add(ref sourceRef, i); - ref Cmyk dp = ref Unsafe.Add(ref destRef, i); - dp = ToCmyk(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public static Cmyk ToCmyk(in Hsv color) - { - Rgb rgb = ToRgb(color); - - return CmykAndRgbConverter.Convert(rgb); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public static void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Hsv sourceRef = ref MemoryMarshal.GetReference(source); - ref Cmyk destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Hsv sp = ref Unsafe.Add(ref sourceRef, i); - ref Cmyk dp = ref Unsafe.Add(ref destRef, i); - dp = ToCmyk(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public Cmyk ToCmyk(in HunterLab color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return this.ToCmyk(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source); - ref Cmyk destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref HunterLab sp = ref Unsafe.Add(ref sourceRef, i); - ref Cmyk dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCmyk(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public static Cmyk ToCmyk(in LinearRgb color) - { - Rgb rgb = ToRgb(color); - - return CmykAndRgbConverter.Convert(rgb); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public static void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source); - ref Cmyk destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i); - ref Cmyk dp = ref Unsafe.Add(ref destRef, i); - dp = ToCmyk(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public Cmyk ToCmyk(in Lms color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return this.ToCmyk(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors, - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Lms sourceRef = ref MemoryMarshal.GetReference(source); - ref Cmyk destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Lms sp = ref Unsafe.Add(ref sourceRef, i); - ref Cmyk dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCmyk(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public static Cmyk ToCmyk(in Rgb color) => CmykAndRgbConverter.Convert(color); - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public static void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Rgb sourceRef = ref MemoryMarshal.GetReference(source); - ref Cmyk destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Rgb sp = ref Unsafe.Add(ref sourceRef, i); - ref Cmyk dp = ref Unsafe.Add(ref destRef, i); - dp = ToCmyk(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public Cmyk ToCmyk(in YCbCr color) - { - Rgb rgb = this.ToRgb(color); - - return CmykAndRgbConverter.Convert(rgb); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source); - ref Cmyk destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref YCbCr sp = ref Unsafe.Add(ref sourceRef, i); - ref Cmyk dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCmyk(sp); - } - } -} diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsl.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsl.cs deleted file mode 100644 index 67ec162917..0000000000 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsl.cs +++ /dev/null @@ -1,437 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; - -/// -/// Allows conversion to . -/// -public partial class ColorSpaceConverter -{ - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public Hsl ToHsl(in CieLab color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return this.ToHsl(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLab sourceRef = ref MemoryMarshal.GetReference(source); - ref Hsl destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLab sp = ref Unsafe.Add(ref sourceRef, i); - ref Hsl dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToHsl(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public Hsl ToHsl(in CieLch color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return this.ToHsl(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLch sourceRef = ref MemoryMarshal.GetReference(source); - ref Hsl destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLch sp = ref Unsafe.Add(ref sourceRef, i); - ref Hsl dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToHsl(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public Hsl ToHsl(in CieLchuv color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return this.ToHsl(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source); - ref Hsl destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLchuv sp = ref Unsafe.Add(ref sourceRef, i); - ref Hsl dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToHsl(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public Hsl ToHsl(in CieLuv color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return this.ToHsl(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source); - ref Hsl destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLuv sp = ref Unsafe.Add(ref sourceRef, i); - ref Hsl dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToHsl(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public Hsl ToHsl(in CieXyy color) - { - CieXyz xyzColor = ToCieXyz(color); - - return this.ToHsl(xyzColor); - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source); - ref Hsl destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieXyy sp = ref Unsafe.Add(ref sourceRef, i); - ref Hsl dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToHsl(sp); - } - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Hsl ToHsl(in CieXyz color) - { - Rgb rgb = this.ToRgb(color); - - return HslAndRgbConverter.Convert(rgb); - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source); - ref Hsl destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i); - ref Hsl dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToHsl(sp); - } - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public static Hsl ToHsl(in Cmyk color) - { - Rgb rgb = ToRgb(color); - - return HslAndRgbConverter.Convert(rgb); - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public static void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source); - ref Hsl destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i); - ref Hsl dp = ref Unsafe.Add(ref destRef, i); - dp = ToHsl(sp); - } - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public static Hsl ToHsl(in Hsv color) - { - Rgb rgb = ToRgb(color); - - return HslAndRgbConverter.Convert(rgb); - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public static void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Hsv sourceRef = ref MemoryMarshal.GetReference(source); - ref Hsl destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Hsv sp = ref Unsafe.Add(ref sourceRef, i); - ref Hsl dp = ref Unsafe.Add(ref destRef, i); - dp = ToHsl(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public Hsl ToHsl(in HunterLab color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return this.ToHsl(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source); - ref Hsl destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref HunterLab sp = ref Unsafe.Add(ref sourceRef, i); - ref Hsl dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToHsl(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public static Hsl ToHsl(in LinearRgb color) - { - Rgb rgb = ToRgb(color); - - return HslAndRgbConverter.Convert(rgb); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public static void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source); - ref Hsl destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i); - ref Hsl dp = ref Unsafe.Add(ref destRef, i); - dp = ToHsl(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public Hsl ToHsl(Lms color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return this.ToHsl(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Lms sourceRef = ref MemoryMarshal.GetReference(source); - ref Hsl destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Lms sp = ref Unsafe.Add(ref sourceRef, i); - ref Hsl dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToHsl(sp); - } - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public static Hsl ToHsl(in Rgb color) => HslAndRgbConverter.Convert(color); - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public static void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Rgb sourceRef = ref MemoryMarshal.GetReference(source); - ref Hsl destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Rgb sp = ref Unsafe.Add(ref sourceRef, i); - ref Hsl dp = ref Unsafe.Add(ref destRef, i); - dp = ToHsl(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public Hsl ToHsl(in YCbCr color) - { - Rgb rgb = this.ToRgb(color); - - return HslAndRgbConverter.Convert(rgb); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source); - ref Hsl destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref YCbCr sp = ref Unsafe.Add(ref sourceRef, i); - ref Hsl dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToHsl(sp); - } - } -} diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsv.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsv.cs deleted file mode 100644 index 47ee42dc5a..0000000000 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsv.cs +++ /dev/null @@ -1,437 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; - -/// -/// Allows conversion to . -/// -public partial class ColorSpaceConverter -{ - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Hsv ToHsv(in CieLab color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return this.ToHsv(xyzColor); - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLab sourceRef = ref MemoryMarshal.GetReference(source); - ref Hsv destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLab sp = ref Unsafe.Add(ref sourceRef, i); - ref Hsv dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToHsv(sp); - } - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Hsv ToHsv(in CieLch color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return this.ToHsv(xyzColor); - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLch sourceRef = ref MemoryMarshal.GetReference(source); - ref Hsv destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLch sp = ref Unsafe.Add(ref sourceRef, i); - ref Hsv dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToHsv(sp); - } - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Hsv ToHsv(in CieLchuv color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return this.ToHsv(xyzColor); - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source); - ref Hsv destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLchuv sp = ref Unsafe.Add(ref sourceRef, i); - ref Hsv dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToHsv(sp); - } - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Hsv ToHsv(in CieLuv color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return this.ToHsv(xyzColor); - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source); - ref Hsv destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLuv sp = ref Unsafe.Add(ref sourceRef, i); - ref Hsv dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToHsv(sp); - } - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Hsv ToHsv(in CieXyy color) - { - CieXyz xyzColor = ToCieXyz(color); - - return this.ToHsv(xyzColor); - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source); - ref Hsv destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieXyy sp = ref Unsafe.Add(ref sourceRef, i); - ref Hsv dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToHsv(sp); - } - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Hsv ToHsv(in CieXyz color) - { - Rgb rgb = this.ToRgb(color); - - return HsvAndRgbConverter.Convert(rgb); - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source); - ref Hsv destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i); - ref Hsv dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToHsv(sp); - } - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public static Hsv ToHsv(in Cmyk color) - { - Rgb rgb = ToRgb(color); - - return HsvAndRgbConverter.Convert(rgb); - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public static void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source); - ref Hsv destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i); - ref Hsv dp = ref Unsafe.Add(ref destRef, i); - dp = ToHsv(sp); - } - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public static Hsv ToHsv(in Hsl color) - { - Rgb rgb = ToRgb(color); - - return HsvAndRgbConverter.Convert(rgb); - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors. - public static void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Hsl sourceRef = ref MemoryMarshal.GetReference(source); - ref Hsv destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Hsl sp = ref Unsafe.Add(ref sourceRef, i); - ref Hsv dp = ref Unsafe.Add(ref destRef, i); - dp = ToHsv(sp); - } - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Hsv ToHsv(in HunterLab color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return this.ToHsv(xyzColor); - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source); - ref Hsv destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref HunterLab sp = ref Unsafe.Add(ref sourceRef, i); - ref Hsv dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToHsv(sp); - } - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public static Hsv ToHsv(in LinearRgb color) - { - Rgb rgb = ToRgb(color); - - return HsvAndRgbConverter.Convert(rgb); - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public static void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source); - ref Hsv destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i); - ref Hsv dp = ref Unsafe.Add(ref destRef, i); - dp = ToHsv(sp); - } - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Hsv ToHsv(Lms color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return this.ToHsv(xyzColor); - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Lms sourceRef = ref MemoryMarshal.GetReference(source); - ref Hsv destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Lms sp = ref Unsafe.Add(ref sourceRef, i); - ref Hsv dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToHsv(sp); - } - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public static Hsv ToHsv(in Rgb color) => HsvAndRgbConverter.Convert(color); - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public static void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Rgb sourceRef = ref MemoryMarshal.GetReference(source); - ref Hsv destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Rgb sp = ref Unsafe.Add(ref sourceRef, i); - ref Hsv dp = ref Unsafe.Add(ref destRef, i); - dp = ToHsv(sp); - } - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Hsv ToHsv(in YCbCr color) - { - Rgb rgb = this.ToRgb(color); - - return HsvAndRgbConverter.Convert(rgb); - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source); - ref Hsv destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref YCbCr sp = ref Unsafe.Add(ref sourceRef, i); - ref Hsv dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToHsv(sp); - } - } -} diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.HunterLab.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.HunterLab.cs deleted file mode 100644 index 0604027760..0000000000 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.HunterLab.cs +++ /dev/null @@ -1,430 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; - -/// -/// Allows conversion to . -/// -public partial class ColorSpaceConverter -{ - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors. - /// The span to the destination colors. - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLab sourceRef = ref MemoryMarshal.GetReference(source); - ref HunterLab destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLab sp = ref Unsafe.Add(ref sourceRef, i); - ref HunterLab dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToHunterLab(sp); - } - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors. - /// The span to the destination colors. - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLch sourceRef = ref MemoryMarshal.GetReference(source); - ref HunterLab destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLch sp = ref Unsafe.Add(ref sourceRef, i); - ref HunterLab dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToHunterLab(sp); - } - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source); - ref HunterLab destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLchuv sp = ref Unsafe.Add(ref sourceRef, i); - ref HunterLab dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToHunterLab(sp); - } - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source); - ref HunterLab destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLuv sp = ref Unsafe.Add(ref sourceRef, i); - ref HunterLab dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToHunterLab(sp); - } - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors. - /// The span to the destination colors. - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source); - ref HunterLab destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieXyy sp = ref Unsafe.Add(ref sourceRef, i); - ref HunterLab dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToHunterLab(sp); - } - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors. - /// The span to the destination colors. - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source); - ref HunterLab destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i); - ref HunterLab dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToHunterLab(sp); - } - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source); - ref HunterLab destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i); - ref HunterLab dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToHunterLab(sp); - } - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors. - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Hsl sourceRef = ref MemoryMarshal.GetReference(source); - ref HunterLab destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Hsl sp = ref Unsafe.Add(ref sourceRef, i); - ref HunterLab dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToHunterLab(sp); - } - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Hsv sourceRef = ref MemoryMarshal.GetReference(source); - ref HunterLab destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Hsv sp = ref Unsafe.Add(ref sourceRef, i); - ref HunterLab dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToHunterLab(sp); - } - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source); - ref HunterLab destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i); - ref HunterLab dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToHunterLab(sp); - } - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Lms sourceRef = ref MemoryMarshal.GetReference(source); - ref HunterLab destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Lms sp = ref Unsafe.Add(ref sourceRef, i); - ref HunterLab dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToHunterLab(sp); - } - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Rgb sourceRef = ref MemoryMarshal.GetReference(source); - ref HunterLab destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Rgb sp = ref Unsafe.Add(ref sourceRef, i); - ref HunterLab dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToHunterLab(sp); - } - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source); - ref HunterLab destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref YCbCr sp = ref Unsafe.Add(ref sourceRef, i); - ref HunterLab dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToHunterLab(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public HunterLab ToHunterLab(in CieLab color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToHunterLab(xyzColor); - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public HunterLab ToHunterLab(in CieLch color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToHunterLab(xyzColor); - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public HunterLab ToHunterLab(in CieLchuv color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToHunterLab(xyzColor); - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public HunterLab ToHunterLab(in CieLuv color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToHunterLab(xyzColor); - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public HunterLab ToHunterLab(in CieXyy color) - { - var xyzColor = ToCieXyz(color); - return this.ToHunterLab(xyzColor); - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public HunterLab ToHunterLab(in CieXyz color) - { - CieXyz adapted = this.Adapt(color, this.whitePoint, this.targetHunterLabWhitePoint); - - return this.cieXyzToHunterLabConverter.Convert(adapted); - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public HunterLab ToHunterLab(in Cmyk color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToHunterLab(xyzColor); - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public HunterLab ToHunterLab(in Hsl color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToHunterLab(xyzColor); - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public HunterLab ToHunterLab(in Hsv color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToHunterLab(xyzColor); - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public HunterLab ToHunterLab(in LinearRgb color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToHunterLab(xyzColor); - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public HunterLab ToHunterLab(in Lms color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToHunterLab(xyzColor); - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public HunterLab ToHunterLab(in Rgb color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToHunterLab(xyzColor); - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public HunterLab ToHunterLab(in YCbCr color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToHunterLab(xyzColor); - } -} diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.LinearRgb.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.LinearRgb.cs deleted file mode 100644 index fd385a15b0..0000000000 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.LinearRgb.cs +++ /dev/null @@ -1,429 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; - -/// -/// Allows conversion to . -/// -public partial class ColorSpaceConverter -{ - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors. - /// The span to the destination colors. - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLab sourceRef = ref MemoryMarshal.GetReference(source); - ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLab sp = ref Unsafe.Add(ref sourceRef, i); - ref LinearRgb dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToLinearRgb(sp); - } - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors. - /// The span to the destination colors. - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLch sourceRef = ref MemoryMarshal.GetReference(source); - ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLch sp = ref Unsafe.Add(ref sourceRef, i); - ref LinearRgb dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToLinearRgb(sp); - } - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors. - /// The span to the destination colors. - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source); - ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLchuv sp = ref Unsafe.Add(ref sourceRef, i); - ref LinearRgb dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToLinearRgb(sp); - } - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors. - /// The span to the destination colors. - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source); - ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLuv sp = ref Unsafe.Add(ref sourceRef, i); - ref LinearRgb dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToLinearRgb(sp); - } - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors. - /// The span to the destination colors. - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source); - ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieXyy sp = ref Unsafe.Add(ref sourceRef, i); - ref LinearRgb dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToLinearRgb(sp); - } - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors. - /// The span to the destination colors. - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source); - ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i); - ref LinearRgb dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToLinearRgb(sp); - } - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors. - /// The span to the destination colors. - public static void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source); - ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i); - ref LinearRgb dp = ref Unsafe.Add(ref destRef, i); - dp = ToLinearRgb(sp); - } - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors. - /// The span to the destination colors. - public static void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Hsl sourceRef = ref MemoryMarshal.GetReference(source); - ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Hsl sp = ref Unsafe.Add(ref sourceRef, i); - ref LinearRgb dp = ref Unsafe.Add(ref destRef, i); - dp = ToLinearRgb(sp); - } - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors. - /// The span to the destination colors. - public static void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Hsv sourceRef = ref MemoryMarshal.GetReference(source); - ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Hsv sp = ref Unsafe.Add(ref sourceRef, i); - ref LinearRgb dp = ref Unsafe.Add(ref destRef, i); - dp = ToLinearRgb(sp); - } - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors. - /// The span to the destination colors. - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source); - ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref HunterLab sp = ref Unsafe.Add(ref sourceRef, i); - ref LinearRgb dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToLinearRgb(sp); - } - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors. - /// The span to the destination colors. - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Lms sourceRef = ref MemoryMarshal.GetReference(source); - ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Lms sp = ref Unsafe.Add(ref sourceRef, i); - ref LinearRgb dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToLinearRgb(sp); - } - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public static void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Rgb sourceRef = ref MemoryMarshal.GetReference(source); - ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Rgb sp = ref Unsafe.Add(ref sourceRef, i); - ref LinearRgb dp = ref Unsafe.Add(ref destRef, i); - dp = ToLinearRgb(sp); - } - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source); - ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref YCbCr sp = ref Unsafe.Add(ref sourceRef, i); - ref LinearRgb dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToLinearRgb(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public LinearRgb ToLinearRgb(in CieLab color) - { - CieXyz xyzColor = this.ToCieXyz(color); - return this.ToLinearRgb(xyzColor); - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public LinearRgb ToLinearRgb(in CieLch color) - { - CieXyz xyzColor = this.ToCieXyz(color); - return this.ToLinearRgb(xyzColor); - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public LinearRgb ToLinearRgb(in CieLchuv color) - { - CieXyz xyzColor = this.ToCieXyz(color); - return this.ToLinearRgb(xyzColor); - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public LinearRgb ToLinearRgb(in CieLuv color) - { - CieXyz xyzColor = this.ToCieXyz(color); - return this.ToLinearRgb(xyzColor); - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public LinearRgb ToLinearRgb(in CieXyy color) - { - CieXyz xyzColor = ToCieXyz(color); - return this.ToLinearRgb(xyzColor); - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public LinearRgb ToLinearRgb(in CieXyz color) - { - // Adaptation - CieXyz adapted = this.Adapt(color, this.whitePoint, this.targetRgbWorkingSpace.WhitePoint); - - // Conversion - return this.cieXyzToLinearRgbConverter.Convert(adapted); - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public static LinearRgb ToLinearRgb(in Cmyk color) - { - Rgb rgb = ToRgb(color); - return ToLinearRgb(rgb); - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public static LinearRgb ToLinearRgb(in Hsl color) - { - Rgb rgb = ToRgb(color); - return ToLinearRgb(rgb); - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public static LinearRgb ToLinearRgb(in Hsv color) - { - Rgb rgb = ToRgb(color); - return ToLinearRgb(rgb); - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public LinearRgb ToLinearRgb(in HunterLab color) - { - CieXyz xyzColor = this.ToCieXyz(color); - return this.ToLinearRgb(xyzColor); - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public LinearRgb ToLinearRgb(in Lms color) - { - CieXyz xyzColor = this.ToCieXyz(color); - return this.ToLinearRgb(xyzColor); - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public static LinearRgb ToLinearRgb(in Rgb color) - => RgbToLinearRgbConverter.Convert(color); - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public LinearRgb ToLinearRgb(in YCbCr color) - { - Rgb rgb = this.ToRgb(color); - return ToLinearRgb(rgb); - } -} diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Lms.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Lms.cs deleted file mode 100644 index 56f61ef80b..0000000000 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Lms.cs +++ /dev/null @@ -1,425 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; - -/// -/// Allows conversion to . -/// -public partial class ColorSpaceConverter -{ - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLab sourceRef = ref MemoryMarshal.GetReference(source); - ref Lms destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLab sp = ref Unsafe.Add(ref sourceRef, i); - ref Lms dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToLms(sp); - } - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLch sourceRef = ref MemoryMarshal.GetReference(source); - ref Lms destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLch sp = ref Unsafe.Add(ref sourceRef, i); - ref Lms dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToLms(sp); - } - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source); - ref Lms destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLchuv sp = ref Unsafe.Add(ref sourceRef, i); - ref Lms dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToLms(sp); - } - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source); - ref Lms destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLuv sp = ref Unsafe.Add(ref sourceRef, i); - ref Lms dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToLms(sp); - } - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source); - ref Lms destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieXyy sp = ref Unsafe.Add(ref sourceRef, i); - ref Lms dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToLms(sp); - } - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source); - ref Lms destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i); - ref Lms dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToLms(sp); - } - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source); - ref Lms destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i); - ref Lms dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToLms(sp); - } - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Hsl sourceRef = ref MemoryMarshal.GetReference(source); - ref Lms destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Hsl sp = ref Unsafe.Add(ref sourceRef, i); - ref Lms dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToLms(sp); - } - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Hsv sourceRef = ref MemoryMarshal.GetReference(source); - ref Lms destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Hsv sp = ref Unsafe.Add(ref sourceRef, i); - ref Lms dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToLms(sp); - } - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source); - ref Lms destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref HunterLab sp = ref Unsafe.Add(ref sourceRef, i); - ref Lms dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToLms(sp); - } - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source); - ref Lms destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i); - ref Lms dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToLms(sp); - } - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Rgb sourceRef = ref MemoryMarshal.GetReference(source); - ref Lms destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Rgb sp = ref Unsafe.Add(ref sourceRef, i); - ref Lms dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToLms(sp); - } - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source); - ref Lms destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref YCbCr sp = ref Unsafe.Add(ref sourceRef, i); - ref Lms dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToLms(sp); - } - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Lms ToLms(in CieLab color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToLms(xyzColor); - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Lms ToLms(in CieLch color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToLms(xyzColor); - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Lms ToLms(in CieLchuv color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToLms(xyzColor); - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Lms ToLms(in CieLuv color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToLms(xyzColor); - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Lms ToLms(in CieXyy color) - { - var xyzColor = ToCieXyz(color); - return this.ToLms(xyzColor); - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Lms ToLms(in CieXyz color) => this.cieXyzAndLmsConverter.Convert(color); - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Lms ToLms(in Cmyk color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToLms(xyzColor); - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Lms ToLms(in Hsl color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToLms(xyzColor); - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Lms ToLms(in Hsv color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToLms(xyzColor); - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Lms ToLms(in HunterLab color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToLms(xyzColor); - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Lms ToLms(in LinearRgb color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToLms(xyzColor); - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Lms ToLms(in Rgb color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToLms(xyzColor); - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Lms ToLms(in YCbCr color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToLms(xyzColor); - } -} diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Rgb.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Rgb.cs deleted file mode 100644 index 080e1fc4bf..0000000000 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Rgb.cs +++ /dev/null @@ -1,419 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; - -/// -/// Allows conversion to . -/// -public partial class ColorSpaceConverter -{ - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLab sourceRef = ref MemoryMarshal.GetReference(source); - ref Rgb destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLab sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgb dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToRgb(sp); - } - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLch sourceRef = ref MemoryMarshal.GetReference(source); - ref Rgb destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLch sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgb dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToRgb(sp); - } - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source); - ref Rgb destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLchuv sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgb dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToRgb(sp); - } - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source); - ref Rgb destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLuv sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgb dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToRgb(sp); - } - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source); - ref Rgb destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieXyy sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgb dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToRgb(sp); - } - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source); - ref Rgb destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgb dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToRgb(sp); - } - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public static void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source); - ref Rgb destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgb dp = ref Unsafe.Add(ref destRef, i); - dp = ToRgb(sp); - } - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public static void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Hsv sourceRef = ref MemoryMarshal.GetReference(source); - ref Rgb destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Hsv sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgb dp = ref Unsafe.Add(ref destRef, i); - dp = ToRgb(sp); - } - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public static void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Hsl sourceRef = ref MemoryMarshal.GetReference(source); - ref Rgb destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Hsl sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgb dp = ref Unsafe.Add(ref destRef, i); - dp = ToRgb(sp); - } - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source); - ref Rgb destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref HunterLab sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgb dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToRgb(sp); - } - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public static void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source); - ref Rgb destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgb dp = ref Unsafe.Add(ref destRef, i); - dp = ToRgb(sp); - } - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Lms sourceRef = ref MemoryMarshal.GetReference(source); - ref Rgb destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Lms sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgb dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToRgb(sp); - } - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source); - ref Rgb destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref YCbCr sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgb dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToRgb(sp); - } - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Rgb ToRgb(in CieLab color) - { - CieXyz xyzColor = this.ToCieXyz(color); - return this.ToRgb(xyzColor); - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Rgb ToRgb(in CieLch color) - { - CieXyz xyzColor = this.ToCieXyz(color); - return this.ToRgb(xyzColor); - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Rgb ToRgb(in CieLchuv color) - { - CieXyz xyzColor = this.ToCieXyz(color); - return this.ToRgb(xyzColor); - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Rgb ToRgb(in CieLuv color) - { - CieXyz xyzColor = this.ToCieXyz(color); - return this.ToRgb(xyzColor); - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Rgb ToRgb(in CieXyy color) - { - CieXyz xyzColor = ToCieXyz(color); - return this.ToRgb(xyzColor); - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Rgb ToRgb(in CieXyz color) - { - // Conversion - LinearRgb linear = this.ToLinearRgb(color); - - // Compand - return ToRgb(linear); - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public static Rgb ToRgb(in Cmyk color) => CmykAndRgbConverter.Convert(color); - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public static Rgb ToRgb(in Hsv color) => HsvAndRgbConverter.Convert(color); - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public static Rgb ToRgb(in Hsl color) => HslAndRgbConverter.Convert(color); - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Rgb ToRgb(in HunterLab color) - { - CieXyz xyzColor = this.ToCieXyz(color); - return this.ToRgb(xyzColor); - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public static Rgb ToRgb(in LinearRgb color) => LinearRgbToRgbConverter.Convert(color); - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Rgb ToRgb(in Lms color) - { - CieXyz xyzColor = this.ToCieXyz(color); - return this.ToRgb(xyzColor); - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Rgb ToRgb(in YCbCr color) - { - // Conversion - Rgb rgb = YCbCrAndRgbConverter.Convert(color); - - // Adaptation - return this.Adapt(rgb); - } -} diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.YCbCr.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.YCbCr.cs deleted file mode 100644 index da8e046ff7..0000000000 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.YCbCr.cs +++ /dev/null @@ -1,404 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; - -/// -/// Allows conversion to . -/// -public partial class ColorSpaceConverter -{ - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors. - /// The span to the destination colors. - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLab sourceRef = ref MemoryMarshal.GetReference(source); - ref YCbCr destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLab sp = ref Unsafe.Add(ref sourceRef, i); - ref YCbCr dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToYCbCr(sp); - } - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors. - /// The span to the destination colors. - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLch sourceRef = ref MemoryMarshal.GetReference(source); - ref YCbCr destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLch sp = ref Unsafe.Add(ref sourceRef, i); - ref YCbCr dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToYCbCr(sp); - } - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source); - ref YCbCr destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLuv sp = ref Unsafe.Add(ref sourceRef, i); - ref YCbCr dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToYCbCr(sp); - } - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source); - ref YCbCr destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieXyy sp = ref Unsafe.Add(ref sourceRef, i); - ref YCbCr dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToYCbCr(sp); - } - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source); - ref YCbCr destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i); - ref YCbCr dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToYCbCr(sp); - } - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public static void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source); - ref YCbCr destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i); - ref YCbCr dp = ref Unsafe.Add(ref destRef, i); - dp = ToYCbCr(sp); - } - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public static void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Hsl sourceRef = ref MemoryMarshal.GetReference(source); - ref YCbCr destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Hsl sp = ref Unsafe.Add(ref sourceRef, i); - ref YCbCr dp = ref Unsafe.Add(ref destRef, i); - dp = ToYCbCr(sp); - } - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public static void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Hsv sourceRef = ref MemoryMarshal.GetReference(source); - ref YCbCr destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Hsv sp = ref Unsafe.Add(ref sourceRef, i); - ref YCbCr dp = ref Unsafe.Add(ref destRef, i); - dp = ToYCbCr(sp); - } - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source); - ref YCbCr destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref HunterLab sp = ref Unsafe.Add(ref sourceRef, i); - ref YCbCr dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToYCbCr(sp); - } - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public static void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source); - ref YCbCr destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i); - ref YCbCr dp = ref Unsafe.Add(ref destRef, i); - dp = ToYCbCr(sp); - } - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Lms sourceRef = ref MemoryMarshal.GetReference(source); - ref YCbCr destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Lms sp = ref Unsafe.Add(ref sourceRef, i); - ref YCbCr dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToYCbCr(sp); - } - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public static void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Rgb sourceRef = ref MemoryMarshal.GetReference(source); - ref YCbCr destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Rgb sp = ref Unsafe.Add(ref sourceRef, i); - ref YCbCr dp = ref Unsafe.Add(ref destRef, i); - dp = ToYCbCr(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public YCbCr ToYCbCr(in CieLab color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return this.ToYCbCr(xyzColor); - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public YCbCr ToYCbCr(in CieLch color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return this.ToYCbCr(xyzColor); - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public YCbCr ToYCbCr(in CieLuv color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return this.ToYCbCr(xyzColor); - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public YCbCr ToYCbCr(in CieXyy color) - { - CieXyz xyzColor = ToCieXyz(color); - - return this.ToYCbCr(xyzColor); - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public YCbCr ToYCbCr(in CieXyz color) - { - Rgb rgb = this.ToRgb(color); - - return YCbCrAndRgbConverter.Convert(rgb); - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public static YCbCr ToYCbCr(in Cmyk color) - { - Rgb rgb = ToRgb(color); - - return YCbCrAndRgbConverter.Convert(rgb); - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public static YCbCr ToYCbCr(in Hsl color) - { - Rgb rgb = ToRgb(color); - - return YCbCrAndRgbConverter.Convert(rgb); - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public static YCbCr ToYCbCr(in Hsv color) - { - Rgb rgb = ToRgb(color); - - return YCbCrAndRgbConverter.Convert(rgb); - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public YCbCr ToYCbCr(in HunterLab color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return this.ToYCbCr(xyzColor); - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public static YCbCr ToYCbCr(in LinearRgb color) - { - Rgb rgb = ToRgb(color); - - return YCbCrAndRgbConverter.Convert(rgb); - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public YCbCr ToYCbCr(in Lms color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return this.ToYCbCr(xyzColor); - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public static YCbCr ToYCbCr(in Rgb color) => YCbCrAndRgbConverter.Convert(color); -} diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.cs deleted file mode 100644 index b5e3162e64..0000000000 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.cs +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Numerics; - -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; - -/// -/// Provides methods to allow the conversion of color values between different color spaces. -/// -public partial class ColorSpaceConverter -{ - // Options. - private static readonly ColorSpaceConverterOptions DefaultOptions = new(); - private readonly Matrix4x4 lmsAdaptationMatrix; - private readonly CieXyz whitePoint; - private readonly CieXyz targetLuvWhitePoint; - private readonly CieXyz targetLabWhitePoint; - private readonly CieXyz targetHunterLabWhitePoint; - private readonly RgbWorkingSpace targetRgbWorkingSpace; - private readonly IChromaticAdaptation? chromaticAdaptation; - private readonly bool performChromaticAdaptation; - private readonly CieXyzAndLmsConverter cieXyzAndLmsConverter; - private readonly CieXyzToCieLabConverter cieXyzToCieLabConverter; - private readonly CieXyzToCieLuvConverter cieXyzToCieLuvConverter; - private readonly CieXyzToHunterLabConverter cieXyzToHunterLabConverter; - private readonly CieXyzToLinearRgbConverter cieXyzToLinearRgbConverter; - - /// - /// Initializes a new instance of the class. - /// - public ColorSpaceConverter() - : this(DefaultOptions) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// The configuration options. - public ColorSpaceConverter(ColorSpaceConverterOptions options) - { - Guard.NotNull(options, nameof(options)); - this.whitePoint = options.WhitePoint; - this.targetLuvWhitePoint = options.TargetLuvWhitePoint; - this.targetLabWhitePoint = options.TargetLabWhitePoint; - this.targetHunterLabWhitePoint = options.TargetHunterLabWhitePoint; - this.targetRgbWorkingSpace = options.TargetRgbWorkingSpace; - this.chromaticAdaptation = options.ChromaticAdaptation; - this.performChromaticAdaptation = this.chromaticAdaptation != null; - this.lmsAdaptationMatrix = options.LmsAdaptationMatrix; - - this.cieXyzAndLmsConverter = new CieXyzAndLmsConverter(this.lmsAdaptationMatrix); - this.cieXyzToCieLabConverter = new CieXyzToCieLabConverter(this.targetLabWhitePoint); - this.cieXyzToCieLuvConverter = new CieXyzToCieLuvConverter(this.targetLuvWhitePoint); - this.cieXyzToHunterLabConverter = new CieXyzToHunterLabConverter(this.targetHunterLabWhitePoint); - this.cieXyzToLinearRgbConverter = new CieXyzToLinearRgbConverter(this.targetRgbWorkingSpace); - } -} diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverterOptions.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverterOptions.cs deleted file mode 100644 index 9f576de726..0000000000 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverterOptions.cs +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Numerics; - -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; - -/// -/// Configuration options for the class. -/// -public class ColorSpaceConverterOptions -{ - /// - /// Gets or sets the white point used for chromatic adaptation in conversions from/to XYZ color space. - /// When default, no adaptation will be performed. - /// Defaults to: . - /// - public CieXyz WhitePoint { get; set; } = CieLuv.DefaultWhitePoint; - - /// - /// Gets or sets the white point used *when creating* Luv/LChuv colors. (Luv/LChuv colors on the input already contain the white point information) - /// Defaults to: . - /// - public CieXyz TargetLuvWhitePoint { get; set; } = CieLuv.DefaultWhitePoint; - - /// - /// Gets or sets the white point used *when creating* Lab/LChab colors. (Lab/LChab colors on the input already contain the white point information) - /// Defaults to: . - /// - public CieXyz TargetLabWhitePoint { get; set; } = CieLab.DefaultWhitePoint; - - /// - /// Gets or sets the white point used *when creating* HunterLab colors. (HunterLab colors on the input already contain the white point information) - /// Defaults to: . - /// - public CieXyz TargetHunterLabWhitePoint { get; set; } = HunterLab.DefaultWhitePoint; - - /// - /// Gets or sets the target working space used *when creating* RGB colors. (RGB colors on the input already contain the working space information) - /// Defaults to: . - /// - public RgbWorkingSpace TargetRgbWorkingSpace { get; set; } = Rgb.DefaultWorkingSpace; - - /// - /// Gets or sets the chromatic adaptation method used. When null, no adaptation will be performed. - /// - public IChromaticAdaptation? ChromaticAdaptation { get; set; } = new VonKriesChromaticAdaptation(); - - /// - /// Gets or sets transformation matrix used in conversion to and from . - /// - public Matrix4x4 LmsAdaptationMatrix { get; set; } = CieXyzAndLmsConverter.DefaultTransformationMatrix; -} diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CIeLchToCieLabConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CIeLchToCieLabConverter.cs deleted file mode 100644 index f16ce7b0fa..0000000000 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CIeLchToCieLabConverter.cs +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Runtime.CompilerServices; - -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; - -/// -/// Converts from to . -/// -internal static class CieLchToCieLabConverter -{ - /// - /// Performs the conversion from the input to an instance of type. - /// - /// The input color instance. - /// The converted result - [MethodImpl(InliningOptions.ShortMethod)] - public static CieLab Convert(in CieLch input) - { - // Conversion algorithm described here: - // https://en.wikipedia.org/wiki/Lab_color_space#Cylindrical_representation:_CIELCh_or_CIEHLC - float l = input.L, c = input.C, hDegrees = input.H; - float hRadians = GeometryUtilities.DegreeToRadian(hDegrees); - - float a = c * MathF.Cos(hRadians); - float b = c * MathF.Sin(hRadians); - - return new CieLab(l, a, b, input.WhitePoint); - } -} diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLabToCieLchConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLabToCieLchConverter.cs deleted file mode 100644 index 4eeb7695e1..0000000000 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLabToCieLchConverter.cs +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Runtime.CompilerServices; - -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; - -/// -/// Converts from to . -/// -internal static class CieLabToCieLchConverter -{ - /// - /// Performs the conversion from the input to an instance of type. - /// - /// The input color instance. - /// The converted result - [MethodImpl(InliningOptions.ShortMethod)] - public static CieLch Convert(in CieLab input) - { - // Conversion algorithm described here: - // https://en.wikipedia.org/wiki/Lab_color_space#Cylindrical_representation:_CIELCh_or_CIEHLC - float l = input.L, a = input.A, b = input.B; - float c = MathF.Sqrt((a * a) + (b * b)); - float hRadians = MathF.Atan2(b, a); - float hDegrees = GeometryUtilities.RadianToDegree(hRadians); - - // Wrap the angle round at 360. - hDegrees %= 360; - - // Make sure it's not negative. - while (hDegrees < 0) - { - hDegrees += 360; - } - - return new CieLch(l, c, hDegrees, input.WhitePoint); - } -} diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLabToCieXyzConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLabToCieXyzConverter.cs deleted file mode 100644 index b02ad0000b..0000000000 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLabToCieXyzConverter.cs +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Numerics; -using System.Runtime.CompilerServices; - -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; - -/// -/// Converts from to . -/// -internal static class CieLabToCieXyzConverter -{ - /// - /// Performs the conversion from the input to an instance of type. - /// - /// The input color instance. - /// The converted result - [MethodImpl(InliningOptions.ShortMethod)] - public static CieXyz Convert(in CieLab input) - { - // Conversion algorithm described here: http://www.brucelindbloom.com/index.html?Eqn_Lab_to_XYZ.html - float l = input.L, a = input.A, b = input.B; - float fy = (l + 16) / 116F; - float fx = (a / 500F) + fy; - float fz = fy - (b / 200F); - - float fx3 = Numerics.Pow3(fx); - float fz3 = Numerics.Pow3(fz); - - float xr = fx3 > CieConstants.Epsilon ? fx3 : ((116F * fx) - 16F) / CieConstants.Kappa; - float yr = l > CieConstants.Kappa * CieConstants.Epsilon ? Numerics.Pow3((l + 16F) / 116F) : l / CieConstants.Kappa; - float zr = fz3 > CieConstants.Epsilon ? fz3 : ((116F * fz) - 16F) / CieConstants.Kappa; - - Vector3 wxyz = new(input.WhitePoint.X, input.WhitePoint.Y, input.WhitePoint.Z); - - // Avoids XYZ coordinates out range (restricted by 0 and XYZ reference white) - Vector3 xyzr = Vector3.Clamp(new Vector3(xr, yr, zr), Vector3.Zero, Vector3.One); - - Vector3 xyz = xyzr * wxyz; - return new CieXyz(xyz); - } -} diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLchuvToCieLuvConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLchuvToCieLuvConverter.cs deleted file mode 100644 index 9a1e79da48..0000000000 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLchuvToCieLuvConverter.cs +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Runtime.CompilerServices; - -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; - -/// -/// Converts from to . -/// -internal static class CieLchuvToCieLuvConverter -{ - /// - /// Performs the conversion from the input to an instance of type. - /// - /// The input color instance. - /// The converted result - [MethodImpl(InliningOptions.ShortMethod)] - public static CieLuv Convert(in CieLchuv input) - { - // Conversion algorithm described here: - // https://en.wikipedia.org/wiki/CIELUV#Cylindrical_representation_.28CIELCH.29 - float l = input.L, c = input.C, hDegrees = input.H; - float hRadians = GeometryUtilities.DegreeToRadian(hDegrees); - - float u = c * MathF.Cos(hRadians); - float v = c * MathF.Sin(hRadians); - - return new CieLuv(l, u, v, input.WhitePoint); - } -} diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLuvToCieLchuvConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLuvToCieLchuvConverter.cs deleted file mode 100644 index 4756bab825..0000000000 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLuvToCieLchuvConverter.cs +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Runtime.CompilerServices; - -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; - -/// -/// Converts from to . -/// -internal static class CieLuvToCieLchuvConverter -{ - /// - /// Performs the conversion from the input to an instance of type. - /// - /// The input color instance. - /// The converted result - [MethodImpl(InliningOptions.ShortMethod)] - public static CieLchuv Convert(in CieLuv input) - { - // Conversion algorithm described here: - // https://en.wikipedia.org/wiki/CIELUV#Cylindrical_representation_.28CIELCH.29 - float l = input.L, a = input.U, b = input.V; - float c = MathF.Sqrt((a * a) + (b * b)); - float hRadians = MathF.Atan2(b, a); - float hDegrees = GeometryUtilities.RadianToDegree(hRadians); - - // Wrap the angle round at 360. - hDegrees %= 360; - - // Make sure it's not negative. - while (hDegrees < 0) - { - hDegrees += 360; - } - - return new CieLchuv(l, c, hDegrees, input.WhitePoint); - } -} diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLuvToCieXyzConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLuvToCieXyzConverter.cs deleted file mode 100644 index 404c4e824d..0000000000 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLuvToCieXyzConverter.cs +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Runtime.CompilerServices; - -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; - -/// -/// Converts from to . -/// -internal static class CieLuvToCieXyzConverter -{ - /// - /// Performs the conversion from the input to an instance of type. - /// - /// The input color instance. - /// The converted result - public static CieXyz Convert(in CieLuv input) - { - // Conversion algorithm described here: http://www.brucelindbloom.com/index.html?Eqn_Luv_to_XYZ.html - float l = input.L, u = input.U, v = input.V; - - float u0 = ComputeU0(input.WhitePoint); - float v0 = ComputeV0(input.WhitePoint); - - float y = l > CieConstants.Kappa * CieConstants.Epsilon - ? Numerics.Pow3((l + 16) / 116) - : l / CieConstants.Kappa; - - float a = ((52 * l / (u + (13 * l * u0))) - 1) / 3; - float b = -5 * y; - const float c = -0.3333333F; - float d = y * ((39 * l / (v + (13 * l * v0))) - 5); - - float x = (d - b) / (a - c); - float z = (x * a) + b; - - if (float.IsNaN(x) || x < 0) - { - x = 0; - } - - if (float.IsNaN(y) || y < 0) - { - y = 0; - } - - if (float.IsNaN(z) || z < 0) - { - z = 0; - } - - return new CieXyz(x, y, z); - } - - /// - /// Calculates the blue-yellow chromacity based on the given whitepoint. - /// - /// The whitepoint - /// The - [MethodImpl(InliningOptions.ShortMethod)] - private static float ComputeU0(in CieXyz input) - => (4 * input.X) / (input.X + (15 * input.Y) + (3 * input.Z)); - - /// - /// Calculates the red-green chromacity based on the given whitepoint. - /// - /// The whitepoint - /// The - [MethodImpl(InliningOptions.ShortMethod)] - private static float ComputeV0(in CieXyz input) - => (9 * input.Y) / (input.X + (15 * input.Y) + (3 * input.Z)); -} diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzAndCieXyyConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzAndCieXyyConverter.cs deleted file mode 100644 index 4cc443cf7b..0000000000 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzAndCieXyyConverter.cs +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Runtime.CompilerServices; - -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; - -/// -/// Color converter between CIE XYZ and CIE xyY. -/// for formulas. -/// -internal static class CieXyzAndCieXyyConverter -{ - /// - /// Performs the conversion from the input to an instance of type. - /// - /// The input color instance. - /// The converted result - [MethodImpl(InliningOptions.ShortMethod)] - public static CieXyy Convert(in CieXyz input) - { - float x = input.X / (input.X + input.Y + input.Z); - float y = input.Y / (input.X + input.Y + input.Z); - - if (float.IsNaN(x) || float.IsNaN(y)) - { - return new CieXyy(0, 0, input.Y); - } - - return new CieXyy(x, y, input.Y); - } - - /// - /// Performs the conversion from the input to an instance of type. - /// - /// The input color instance. - /// The converted result - [MethodImpl(InliningOptions.ShortMethod)] - public static CieXyz Convert(in CieXyy input) - { - if (MathF.Abs(input.Y) < Constants.Epsilon) - { - return new CieXyz(0, 0, input.Yl); - } - - float x = (input.X * input.Yl) / input.Y; - float y = input.Yl; - float z = ((1 - input.X - input.Y) * y) / input.Y; - - return new CieXyz(x, y, z); - } -} diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzAndHunterLabConverterBase.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzAndHunterLabConverterBase.cs deleted file mode 100644 index ba221108fb..0000000000 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzAndHunterLabConverterBase.cs +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Runtime.CompilerServices; - -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; - -/// -/// The base class for converting between and color spaces. -/// -internal abstract class CieXyzAndHunterLabConverterBase -{ - /// - /// Returns the Ka coefficient that depends upon the whitepoint illuminant. - /// - /// The whitepoint - /// The - [MethodImpl(InliningOptions.ShortMethod)] - public static float ComputeKa(CieXyz whitePoint) - { - if (whitePoint.Equals(Illuminants.C)) - { - return 175F; - } - - return 100F * (175F / 198.04F) * (whitePoint.X + whitePoint.Y); - } - - /// - /// Returns the Kb coefficient that depends upon the whitepoint illuminant. - /// - /// The whitepoint - /// The - [MethodImpl(InliningOptions.ShortMethod)] - public static float ComputeKb(CieXyz whitePoint) - { - if (whitePoint == Illuminants.C) - { - return 70F; - } - - return 100F * (70F / 218.11F) * (whitePoint.Y + whitePoint.Z); - } -} diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzAndLmsConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzAndLmsConverter.cs deleted file mode 100644 index b5f8a70b6f..0000000000 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzAndLmsConverter.cs +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Numerics; -using System.Runtime.CompilerServices; - -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; - -/// -/// Color converter between and -/// -internal sealed class CieXyzAndLmsConverter -{ - /// - /// Default transformation matrix used, when no other is set. (Bradford) - /// - /// - public static readonly Matrix4x4 DefaultTransformationMatrix = LmsAdaptationMatrix.Bradford; - - private Matrix4x4 inverseTransformationMatrix; - private Matrix4x4 transformationMatrix; - - /// - /// Initializes a new instance of the class. - /// - public CieXyzAndLmsConverter() - : this(DefaultTransformationMatrix) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// - /// Definition of the cone response domain (see ), - /// if not set will be used. - /// - public CieXyzAndLmsConverter(Matrix4x4 transformationMatrix) - { - this.transformationMatrix = transformationMatrix; - Matrix4x4.Invert(this.transformationMatrix, out this.inverseTransformationMatrix); - } - - /// - /// Performs the conversion from the input to an instance of type. - /// - /// The input color instance. - /// The converted result - [MethodImpl(InliningOptions.ShortMethod)] - public Lms Convert(in CieXyz input) - { - Vector3 vector = Vector3.Transform(input.ToVector3(), this.transformationMatrix); - - return new Lms(vector); - } - - /// - /// Performs the conversion from the input to an instance of type. - /// - /// The input color instance. - /// The converted result - [MethodImpl(InliningOptions.ShortMethod)] - public CieXyz Convert(in Lms input) - { - Vector3 vector = Vector3.Transform(input.ToVector3(), this.inverseTransformationMatrix); - - return new CieXyz(vector); - } -} diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToCieLabConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToCieLabConverter.cs deleted file mode 100644 index 0ce6e3c9ff..0000000000 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToCieLabConverter.cs +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Runtime.CompilerServices; - -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; - -/// -/// Converts from to . -/// -internal sealed class CieXyzToCieLabConverter -{ - /// - /// Initializes a new instance of the class. - /// - public CieXyzToCieLabConverter() - : this(CieLab.DefaultWhitePoint) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// The target reference lab white point - public CieXyzToCieLabConverter(CieXyz labWhitePoint) => this.LabWhitePoint = labWhitePoint; - - /// - /// Gets the target reference whitepoint. When not set, is used. - /// - public CieXyz LabWhitePoint { get; } - - /// - /// Performs the conversion from the input to an instance of type. - /// - /// The input color instance. - /// The converted result - [MethodImpl(InliningOptions.ShortMethod)] - public CieLab Convert(in CieXyz input) - { - // Conversion algorithm described here: http://www.brucelindbloom.com/index.html?Eqn_XYZ_to_Lab.html - float wx = this.LabWhitePoint.X, wy = this.LabWhitePoint.Y, wz = this.LabWhitePoint.Z; - - float xr = input.X / wx, yr = input.Y / wy, zr = input.Z / wz; - - const float inv116 = 1 / 116F; - - float fx = xr > CieConstants.Epsilon ? MathF.Pow(xr, 0.3333333F) : ((CieConstants.Kappa * xr) + 16F) * inv116; - float fy = yr > CieConstants.Epsilon ? MathF.Pow(yr, 0.3333333F) : ((CieConstants.Kappa * yr) + 16F) * inv116; - float fz = zr > CieConstants.Epsilon ? MathF.Pow(zr, 0.3333333F) : ((CieConstants.Kappa * zr) + 16F) * inv116; - - float l = (116F * fy) - 16F; - float a = 500F * (fx - fy); - float b = 200F * (fy - fz); - - return new CieLab(l, a, b, this.LabWhitePoint); - } -} diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToCieLuvConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToCieLuvConverter.cs deleted file mode 100644 index 1e17ae54f0..0000000000 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToCieLuvConverter.cs +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Runtime.CompilerServices; - -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; - -/// -/// Converts from to . -/// -internal sealed class CieXyzToCieLuvConverter -{ - /// - /// Initializes a new instance of the class. - /// - public CieXyzToCieLuvConverter() - : this(CieLuv.DefaultWhitePoint) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// The target reference luv white point - public CieXyzToCieLuvConverter(CieXyz luvWhitePoint) => this.LuvWhitePoint = luvWhitePoint; - - /// - /// Gets the target reference whitepoint. When not set, is used. - /// - public CieXyz LuvWhitePoint { get; } - - /// - /// Performs the conversion from the input to an instance of type. - /// - /// The input color instance. - /// The converted result - public CieLuv Convert(in CieXyz input) - { - // Conversion algorithm described here: http://www.brucelindbloom.com/index.html?Eqn_XYZ_to_Luv.html - float yr = input.Y / this.LuvWhitePoint.Y; - float up = ComputeUp(input); - float vp = ComputeVp(input); - float upr = ComputeUp(this.LuvWhitePoint); - float vpr = ComputeVp(this.LuvWhitePoint); - - float l = yr > CieConstants.Epsilon ? ((116 * MathF.Pow(yr, 0.3333333F)) - 16F) : (CieConstants.Kappa * yr); - - if (float.IsNaN(l) || l < 0) - { - l = 0; - } - - float u = 13 * l * (up - upr); - float v = 13 * l * (vp - vpr); - - if (float.IsNaN(u)) - { - u = 0; - } - - if (float.IsNaN(v)) - { - v = 0; - } - - return new CieLuv(l, u, v, this.LuvWhitePoint); - } - - /// - /// Calculates the blue-yellow chromacity based on the given whitepoint. - /// - /// The whitepoint - /// The - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static float ComputeUp(in CieXyz input) - => (4 * input.X) / (input.X + (15 * input.Y) + (3 * input.Z)); - - /// - /// Calculates the red-green chromacity based on the given whitepoint. - /// - /// The whitepoint - /// The - [MethodImpl(InliningOptions.ShortMethod)] - private static float ComputeVp(in CieXyz input) - => (9 * input.Y) / (input.X + (15 * input.Y) + (3 * input.Z)); -} diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToHunterLabConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToHunterLabConverter.cs deleted file mode 100644 index dab953a749..0000000000 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToHunterLabConverter.cs +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Runtime.CompilerServices; - -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; - -/// -/// Color converter between and -/// -internal sealed class CieXyzToHunterLabConverter : CieXyzAndHunterLabConverterBase -{ - /// - /// Initializes a new instance of the class. - /// - public CieXyzToHunterLabConverter() - : this(HunterLab.DefaultWhitePoint) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// The hunter Lab white point. - public CieXyzToHunterLabConverter(CieXyz labWhitePoint) => this.HunterLabWhitePoint = labWhitePoint; - - /// - /// Gets the target reference white. When not set, is used. - /// - public CieXyz HunterLabWhitePoint { get; } - - /// - /// Performs the conversion from the input to an instance of type. - /// - /// The input color instance. - /// The converted result - [MethodImpl(InliningOptions.ShortMethod)] - public HunterLab Convert(in CieXyz input) - { - // Conversion algorithm described here: http://en.wikipedia.org/wiki/Lab_color_space#Hunter_Lab - float x = input.X, y = input.Y, z = input.Z; - float xn = this.HunterLabWhitePoint.X, yn = this.HunterLabWhitePoint.Y, zn = this.HunterLabWhitePoint.Z; - - float ka = ComputeKa(this.HunterLabWhitePoint); - float kb = ComputeKb(this.HunterLabWhitePoint); - - float yByYn = y / yn; - float sqrtYbyYn = MathF.Sqrt(yByYn); - float l = 100 * sqrtYbyYn; - float a = ka * (((x / xn) - yByYn) / sqrtYbyYn); - float b = kb * ((yByYn - (z / zn)) / sqrtYbyYn); - - if (float.IsNaN(a)) - { - a = 0; - } - - if (float.IsNaN(b)) - { - b = 0; - } - - return new HunterLab(l, a, b, this.HunterLabWhitePoint); - } -} diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToLinearRgbConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToLinearRgbConverter.cs deleted file mode 100644 index 4d15cb5d56..0000000000 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToLinearRgbConverter.cs +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Numerics; -using System.Runtime.CompilerServices; - -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; - -/// -/// Color converter between and -/// -internal sealed class CieXyzToLinearRgbConverter : LinearRgbAndCieXyzConverterBase -{ - private readonly Matrix4x4 conversionMatrix; - - /// - /// Initializes a new instance of the class. - /// - public CieXyzToLinearRgbConverter() - : this(Rgb.DefaultWorkingSpace) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// The target working space. - public CieXyzToLinearRgbConverter(RgbWorkingSpace workingSpace) - { - this.TargetWorkingSpace = workingSpace; - - // Gets the inverted Rgb -> Xyz matrix - Matrix4x4.Invert(GetRgbToCieXyzMatrix(workingSpace), out Matrix4x4 inverted); - - this.conversionMatrix = inverted; - } - - /// - /// Gets the target working space. - /// - public RgbWorkingSpace TargetWorkingSpace { get; } - - /// - /// Performs the conversion from the input to an instance of type. - /// - /// The input color instance. - /// The converted result. - [MethodImpl(InliningOptions.ShortMethod)] - public LinearRgb Convert(in CieXyz input) - { - var vector = Vector3.Transform(input.ToVector3(), this.conversionMatrix); - - return new LinearRgb(vector, this.TargetWorkingSpace); - } -} diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CmykAndRgbConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CmykAndRgbConverter.cs deleted file mode 100644 index 07ca1c7e46..0000000000 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CmykAndRgbConverter.cs +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Numerics; -using System.Runtime.CompilerServices; - -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; - -/// -/// Color converter between and . -/// -internal static class CmykAndRgbConverter -{ - /// - /// Performs the conversion from the input to an instance of type. - /// - /// The input color instance. - /// The converted result - [MethodImpl(InliningOptions.ShortMethod)] - public static Rgb Convert(in Cmyk input) - { - Vector3 rgb = (Vector3.One - new Vector3(input.C, input.M, input.Y)) * (Vector3.One - new Vector3(input.K)); - return new Rgb(rgb); - } - - /// - /// Performs the conversion from the input to an instance of type. - /// - /// The input color instance. - /// The converted result. - [MethodImpl(InliningOptions.ShortMethod)] - public static Cmyk Convert(in Rgb input) - { - // To CMY - Vector3 cmy = Vector3.One - input.ToVector3(); - - // To CMYK - Vector3 k = new(MathF.Min(cmy.X, MathF.Min(cmy.Y, cmy.Z))); - - if (MathF.Abs(k.X - 1F) < Constants.Epsilon) - { - return new Cmyk(0, 0, 0, 1F); - } - - cmy = (cmy - k) / (Vector3.One - k); - - return new Cmyk(cmy.X, cmy.Y, cmy.Z, k.X); - } -} diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/HslAndRgbConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/HslAndRgbConverter.cs deleted file mode 100644 index 24aecc3c45..0000000000 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/HslAndRgbConverter.cs +++ /dev/null @@ -1,158 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Runtime.CompilerServices; - -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; - -/// -/// Color converter between HSL and Rgb -/// See for formulas. -/// -internal static class HslAndRgbConverter -{ - /// - /// Performs the conversion from the input to an instance of type. - /// - /// The input color instance. - /// The converted result - [MethodImpl(InliningOptions.ShortMethod)] - public static Rgb Convert(in Hsl input) - { - float rangedH = input.H / 360F; - float r = 0; - float g = 0; - float b = 0; - float s = input.S; - float l = input.L; - - if (MathF.Abs(l) > Constants.Epsilon) - { - if (MathF.Abs(s) < Constants.Epsilon) - { - r = g = b = l; - } - else - { - float temp2 = (l < .5F) ? l * (1F + s) : l + s - (l * s); - float temp1 = (2F * l) - temp2; - - r = GetColorComponent(temp1, temp2, rangedH + 0.3333333F); - g = GetColorComponent(temp1, temp2, rangedH); - b = GetColorComponent(temp1, temp2, rangedH - 0.3333333F); - } - } - - return new Rgb(r, g, b); - } - - /// - /// Performs the conversion from the input to an instance of type. - /// - /// The input color instance. - /// The converted result - [MethodImpl(InliningOptions.ShortMethod)] - public static Hsl Convert(in Rgb input) - { - float r = input.R; - float g = input.G; - float b = input.B; - - float max = MathF.Max(r, MathF.Max(g, b)); - float min = MathF.Min(r, MathF.Min(g, b)); - float chroma = max - min; - float h = 0F; - float s = 0F; - float l = (max + min) / 2F; - - if (MathF.Abs(chroma) < Constants.Epsilon) - { - return new Hsl(0F, s, l); - } - - if (MathF.Abs(r - max) < Constants.Epsilon) - { - h = (g - b) / chroma; - } - else if (MathF.Abs(g - max) < Constants.Epsilon) - { - h = 2F + ((b - r) / chroma); - } - else if (MathF.Abs(b - max) < Constants.Epsilon) - { - h = 4F + ((r - g) / chroma); - } - - h *= 60F; - if (h < 0F) - { - h += 360F; - } - - if (l <= .5F) - { - s = chroma / (max + min); - } - else - { - s = chroma / (2F - max - min); - } - - return new Hsl(h, s, l); - } - - /// - /// Gets the color component from the given values. - /// - /// The first value. - /// The second value. - /// The third value. - /// - /// The . - /// - [MethodImpl(InliningOptions.ShortMethod)] - private static float GetColorComponent(float first, float second, float third) - { - third = MoveIntoRange(third); - if (third < 0.1666667F) - { - return first + ((second - first) * 6F * third); - } - - if (third < .5F) - { - return second; - } - - if (third < 0.6666667F) - { - return first + ((second - first) * (0.6666667F - third) * 6F); - } - - return first; - } - - /// - /// Moves the specific value within the acceptable range for - /// conversion. - /// Used for converting colors to this type. - /// - /// The value to shift. - /// - /// The . - /// - [MethodImpl(InliningOptions.ShortMethod)] - private static float MoveIntoRange(float value) - { - if (value < 0F) - { - value++; - } - else if (value > 1F) - { - value--; - } - - return value; - } -} diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/HsvAndRgbConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/HsvAndRgbConverter.cs deleted file mode 100644 index 5273576175..0000000000 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/HsvAndRgbConverter.cs +++ /dev/null @@ -1,128 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Runtime.CompilerServices; - -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; - -/// -/// Color converter between HSV and Rgb -/// See for formulas. -/// -internal static class HsvAndRgbConverter -{ - /// - /// Performs the conversion from the input to an instance of type. - /// - /// The input color instance. - /// The converted result - [MethodImpl(InliningOptions.ShortMethod)] - public static Rgb Convert(in Hsv input) - { - float s = input.S; - float v = input.V; - - if (MathF.Abs(s) < Constants.Epsilon) - { - return new Rgb(v, v, v); - } - - float h = (MathF.Abs(input.H - 360) < Constants.Epsilon) ? 0 : input.H / 60; - int i = (int)Math.Truncate(h); - float f = h - i; - - float p = v * (1F - s); - float q = v * (1F - (s * f)); - float t = v * (1F - (s * (1F - f))); - - float r, g, b; - switch (i) - { - case 0: - r = v; - g = t; - b = p; - break; - - case 1: - r = q; - g = v; - b = p; - break; - - case 2: - r = p; - g = v; - b = t; - break; - - case 3: - r = p; - g = q; - b = v; - break; - - case 4: - r = t; - g = p; - b = v; - break; - - default: - r = v; - g = p; - b = q; - break; - } - - return new Rgb(r, g, b); - } - - /// - /// Performs the conversion from the input to an instance of type. - /// - /// The input color instance. - /// The converted result - [MethodImpl(InliningOptions.ShortMethod)] - public static Hsv Convert(in Rgb input) - { - float r = input.R; - float g = input.G; - float b = input.B; - - float max = MathF.Max(r, MathF.Max(g, b)); - float min = MathF.Min(r, MathF.Min(g, b)); - float chroma = max - min; - float h = 0; - float s = 0; - float v = max; - - if (MathF.Abs(chroma) < Constants.Epsilon) - { - return new Hsv(0, s, v); - } - - if (MathF.Abs(r - max) < Constants.Epsilon) - { - h = (g - b) / chroma; - } - else if (MathF.Abs(g - max) < Constants.Epsilon) - { - h = 2 + ((b - r) / chroma); - } - else if (MathF.Abs(b - max) < Constants.Epsilon) - { - h = 4 + ((r - g) / chroma); - } - - h *= 60; - if (h < 0.0) - { - h += 360; - } - - s = chroma / v; - - return new Hsv(h, s, v); - } -} diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/HunterLabToCieXyzConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/HunterLabToCieXyzConverter.cs deleted file mode 100644 index 3930e8dc2d..0000000000 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/HunterLabToCieXyzConverter.cs +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Runtime.CompilerServices; - -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; - -/// -/// Color converter between and -/// -internal sealed class HunterLabToCieXyzConverter : CieXyzAndHunterLabConverterBase -{ - /// - /// Performs the conversion from the input to an instance of type. - /// - /// The input color instance. - /// The converted result - [MethodImpl(InliningOptions.ShortMethod)] - public static CieXyz Convert(in HunterLab input) - { - // Conversion algorithm described here: http://en.wikipedia.org/wiki/Lab_color_space#Hunter_Lab - float l = input.L, a = input.A, b = input.B; - float xn = input.WhitePoint.X, yn = input.WhitePoint.Y, zn = input.WhitePoint.Z; - - float ka = ComputeKa(input.WhitePoint); - float kb = ComputeKb(input.WhitePoint); - - float pow = Numerics.Pow2(l / 100F); - float sqrtPow = MathF.Sqrt(pow); - float y = pow * yn; - - float x = (((a / ka) * sqrtPow) + pow) * xn; - float z = (((b / kb) * sqrtPow) - pow) * (-zn); - - return new CieXyz(x, y, z); - } -} diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/LinearRgbAndCieXyzConverterBase.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/LinearRgbAndCieXyzConverterBase.cs deleted file mode 100644 index 27391fc802..0000000000 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/LinearRgbAndCieXyzConverterBase.cs +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Numerics; - -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; - -/// -/// Provides base methods for converting between and color spaces. -/// -internal abstract class LinearRgbAndCieXyzConverterBase -{ - /// - /// Returns the correct matrix to convert between the Rgb and CieXyz color space. - /// - /// The Rgb working space. - /// The based on the chromaticity and working space. - public static Matrix4x4 GetRgbToCieXyzMatrix(RgbWorkingSpace workingSpace) - { - DebugGuard.NotNull(workingSpace, nameof(workingSpace)); - RgbPrimariesChromaticityCoordinates chromaticity = workingSpace.ChromaticityCoordinates; - - float xr = chromaticity.R.X; - float xg = chromaticity.G.X; - float xb = chromaticity.B.X; - float yr = chromaticity.R.Y; - float yg = chromaticity.G.Y; - float yb = chromaticity.B.Y; - - float mXr = xr / yr; - float mZr = (1 - xr - yr) / yr; - - float mXg = xg / yg; - float mZg = (1 - xg - yg) / yg; - - float mXb = xb / yb; - float mZb = (1 - xb - yb) / yb; - - Matrix4x4 xyzMatrix = new() - { - M11 = mXr, - M21 = mXg, - M31 = mXb, - M12 = 1F, - M22 = 1F, - M32 = 1F, - M13 = mZr, - M23 = mZg, - M33 = mZb, - M44 = 1F - }; - - Matrix4x4.Invert(xyzMatrix, out Matrix4x4 inverseXyzMatrix); - - Vector3 vector = Vector3.Transform(workingSpace.WhitePoint.ToVector3(), inverseXyzMatrix); - - // Use transposed Rows/Columns - // TODO: Is there a built in method for this multiplication? - return new Matrix4x4 - { - M11 = vector.X * mXr, - M21 = vector.Y * mXg, - M31 = vector.Z * mXb, - M12 = vector.X * 1, - M22 = vector.Y * 1, - M32 = vector.Z * 1, - M13 = vector.X * mZr, - M23 = vector.Y * mZg, - M33 = vector.Z * mZb, - M44 = 1F - }; - } -} diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/LinearRgbToCieXyzConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/LinearRgbToCieXyzConverter.cs deleted file mode 100644 index 091cab9931..0000000000 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/LinearRgbToCieXyzConverter.cs +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Numerics; -using System.Runtime.CompilerServices; - -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; - -/// -/// Color converter between and -/// -internal sealed class LinearRgbToCieXyzConverter : LinearRgbAndCieXyzConverterBase -{ - private readonly Matrix4x4 conversionMatrix; - - /// - /// Initializes a new instance of the class. - /// - public LinearRgbToCieXyzConverter() - : this(Rgb.DefaultWorkingSpace) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// The target working space. - public LinearRgbToCieXyzConverter(RgbWorkingSpace workingSpace) - { - this.SourceWorkingSpace = workingSpace; - this.conversionMatrix = GetRgbToCieXyzMatrix(workingSpace); - } - - /// - /// Gets the source working space - /// - public RgbWorkingSpace SourceWorkingSpace { get; } - - /// - /// Performs the conversion from the input to an instance of type. - /// - /// The input color instance. - /// The converted result - [MethodImpl(InliningOptions.ShortMethod)] - public CieXyz Convert(in LinearRgb input) - { - DebugGuard.IsTrue(input.WorkingSpace.Equals(this.SourceWorkingSpace), nameof(input.WorkingSpace), "Input and source working spaces must be equal."); - - Vector3 vector = Vector3.Transform(input.ToVector3(), this.conversionMatrix); - return new CieXyz(vector); - } -} diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/LinearRgbToRgbConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/LinearRgbToRgbConverter.cs deleted file mode 100644 index d41e7f74da..0000000000 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/LinearRgbToRgbConverter.cs +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Runtime.CompilerServices; - -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; - -/// -/// Color converter between and . -/// -internal static class LinearRgbToRgbConverter -{ - /// - /// Performs the conversion from the input to an instance of type. - /// - /// The input color instance. - /// The converted result. - [MethodImpl(InliningOptions.ShortMethod)] - public static Rgb Convert(in LinearRgb input) => - new( - r: input.WorkingSpace.Compress(input.R), - g: input.WorkingSpace.Compress(input.G), - b: input.WorkingSpace.Compress(input.B), - workingSpace: input.WorkingSpace); -} diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/RgbToLinearRgbConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/RgbToLinearRgbConverter.cs deleted file mode 100644 index c63bbae3da..0000000000 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/RgbToLinearRgbConverter.cs +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Runtime.CompilerServices; - -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; - -/// -/// Color converter between Rgb and LinearRgb. -/// -internal static class RgbToLinearRgbConverter -{ - /// - /// Performs the conversion from the input to an instance of type. - /// - /// The input color instance. - /// The converted result. - [MethodImpl(InliningOptions.ShortMethod)] - public static LinearRgb Convert(in Rgb input) - => new( - r: input.WorkingSpace.Expand(input.R), - g: input.WorkingSpace.Expand(input.G), - b: input.WorkingSpace.Expand(input.B), - workingSpace: input.WorkingSpace); -} diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/YCbCrAndRgbConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/YCbCrAndRgbConverter.cs deleted file mode 100644 index eda55ec4c5..0000000000 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/YCbCrAndRgbConverter.cs +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Numerics; -using System.Runtime.CompilerServices; - -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; - -/// -/// Color converter between and -/// See for formulas. -/// -internal static class YCbCrAndRgbConverter -{ - private static readonly Vector3 MaxBytes = new(255F); - - /// - /// Performs the conversion from the input to an instance of type. - /// - /// The input color instance. - /// The converted result. - [MethodImpl(InliningOptions.ShortMethod)] - public static Rgb Convert(in YCbCr input) - { - float y = input.Y; - float cb = input.Cb - 128F; - float cr = input.Cr - 128F; - - float r = MathF.Round(y + (1.402F * cr), MidpointRounding.AwayFromZero); - float g = MathF.Round(y - (0.344136F * cb) - (0.714136F * cr), MidpointRounding.AwayFromZero); - float b = MathF.Round(y + (1.772F * cb), MidpointRounding.AwayFromZero); - - return new Rgb(new Vector3(r, g, b) / MaxBytes); - } - - /// - /// Performs the conversion from the input to an instance of type. - /// - /// The input color instance. - /// The converted result. - [MethodImpl(InliningOptions.ShortMethod)] - public static YCbCr Convert(in Rgb input) - { - Vector3 rgb = input.ToVector3() * MaxBytes; - float r = rgb.X; - float g = rgb.Y; - float b = rgb.Z; - - float y = (0.299F * r) + (0.587F * g) + (0.114F * b); - float cb = 128F + ((-0.168736F * r) - (0.331264F * g) + (0.5F * b)); - float cr = 128F + ((0.5F * r) - (0.418688F * g) - (0.081312F * b)); - - return new YCbCr(y, cb, cr); - } -} diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/IChromaticAdaptation.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/IChromaticAdaptation.cs deleted file mode 100644 index 3b6abb041e..0000000000 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/IChromaticAdaptation.cs +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; - -/// -/// Chromatic adaptation. -/// A linear transformation of a source color (XS, YS, ZS) into a destination color (XD, YD, ZD) by a linear transformation [M] -/// which is dependent on the source reference white (XWS, YWS, ZWS) and the destination reference white (XWD, YWD, ZWD). -/// -public interface IChromaticAdaptation -{ - /// - /// Performs a linear transformation of a source color in to the destination color. - /// - /// Doesn't crop the resulting color space coordinates (e. g. allows negative values for XYZ coordinates). - /// The source color. - /// The source white point. - /// The destination white point. - /// The - CieXyz Transform(in CieXyz source, in CieXyz sourceWhitePoint, in CieXyz destinationWhitePoint); - - /// - /// Performs a bulk linear transformation of a source color in to the destination color. - /// - /// Doesn't crop the resulting color space coordinates (e. g. allows negative values for XYZ coordinates). - /// The span to the source colors. - /// The span to the destination colors. - /// The source white point. - /// The destination white point. - void Transform( - ReadOnlySpan source, - Span destination, - CieXyz sourceWhitePoint, - in CieXyz destinationWhitePoint); -} diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/VonKriesChromaticAdaptation.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/VonKriesChromaticAdaptation.cs deleted file mode 100644 index 97e9cee813..0000000000 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/VonKriesChromaticAdaptation.cs +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Numerics; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; - -/// -/// Implementation of the von Kries chromatic adaptation model. -/// -/// -/// Transformation described here: -/// http://www.brucelindbloom.com/index.html?Eqn_ChromAdapt.html -/// -public sealed class VonKriesChromaticAdaptation : IChromaticAdaptation -{ - private readonly CieXyzAndLmsConverter converter; - - /// - /// Initializes a new instance of the class. - /// - public VonKriesChromaticAdaptation() - : this(new CieXyzAndLmsConverter()) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// - /// The transformation matrix used for the conversion (definition of the cone response domain). - /// - /// - public VonKriesChromaticAdaptation(Matrix4x4 transformationMatrix) - : this(new CieXyzAndLmsConverter(transformationMatrix)) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// The color converter - internal VonKriesChromaticAdaptation(CieXyzAndLmsConverter converter) => this.converter = converter; - - /// - public CieXyz Transform(in CieXyz source, in CieXyz sourceWhitePoint, in CieXyz destinationWhitePoint) - { - if (sourceWhitePoint.Equals(destinationWhitePoint)) - { - return source; - } - - Lms sourceColorLms = this.converter.Convert(source); - Lms sourceWhitePointLms = this.converter.Convert(sourceWhitePoint); - Lms targetWhitePointLms = this.converter.Convert(destinationWhitePoint); - - Vector3 vector = targetWhitePointLms.ToVector3() / sourceWhitePointLms.ToVector3(); - var targetColorLms = new Lms(Vector3.Multiply(vector, sourceColorLms.ToVector3())); - - return this.converter.Convert(targetColorLms); - } - - /// - public void Transform( - ReadOnlySpan source, - Span destination, - CieXyz sourceWhitePoint, - in CieXyz destinationWhitePoint) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - if (sourceWhitePoint.Equals(destinationWhitePoint)) - { - source.CopyTo(destination[..count]); - return; - } - - ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source); - ref CieXyz destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i); - ref CieXyz dp = ref Unsafe.Add(ref destRef, i); - - Lms sourceColorLms = this.converter.Convert(sp); - Lms sourceWhitePointLms = this.converter.Convert(sourceWhitePoint); - Lms targetWhitePointLms = this.converter.Convert(destinationWhitePoint); - - Vector3 vector = targetWhitePointLms.ToVector3() / sourceWhitePointLms.ToVector3(); - var targetColorLms = new Lms(Vector3.Multiply(vector, sourceColorLms.ToVector3())); - - dp = this.converter.Convert(targetColorLms); - } - } -} diff --git a/src/ImageSharp/ColorSpaces/Hsl.cs b/src/ImageSharp/ColorSpaces/Hsl.cs deleted file mode 100644 index cf18c70c78..0000000000 --- a/src/ImageSharp/ColorSpaces/Hsl.cs +++ /dev/null @@ -1,100 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Numerics; -using System.Runtime.CompilerServices; - -namespace SixLabors.ImageSharp.ColorSpaces; - -/// -/// Represents a Hsl (hue, saturation, lightness) color. -/// -public readonly struct Hsl : IEquatable -{ - private static readonly Vector3 Min = Vector3.Zero; - private static readonly Vector3 Max = new(360, 1, 1); - - /// - /// Initializes a new instance of the struct. - /// - /// The h hue component. - /// The s saturation component. - /// The l value (lightness) component. - [MethodImpl(InliningOptions.ShortMethod)] - public Hsl(float h, float s, float l) - : this(new Vector3(h, s, l)) - { - } - - /// - /// Initializes a new instance of the struct. - /// - /// The vector representing the h, s, l components. - [MethodImpl(InliningOptions.ShortMethod)] - public Hsl(Vector3 vector) - { - vector = Vector3.Clamp(vector, Min, Max); - this.H = vector.X; - this.S = vector.Y; - this.L = vector.Z; - } - - /// - /// Gets the hue component. - /// A value ranging between 0 and 360. - /// - public readonly float H { get; } - - /// - /// Gets the saturation component. - /// A value ranging between 0 and 1. - /// - public readonly float S { get; } - - /// - /// Gets the lightness component. - /// A value ranging between 0 and 1. - /// - public readonly float L { get; } - - /// - /// Compares two objects for equality. - /// - /// - /// The on the left side of the operand. - /// - /// The on the right side of the operand. - /// - /// True if the current left is equal to the parameter; otherwise, false. - /// - [MethodImpl(InliningOptions.ShortMethod)] - public static bool operator ==(Hsl left, Hsl right) => left.Equals(right); - - /// - /// Compares two objects for inequality. - /// - /// The on the left side of the operand. - /// The on the right side of the operand. - /// - /// True if the current left is unequal to the parameter; otherwise, false. - /// - [MethodImpl(InliningOptions.ShortMethod)] - public static bool operator !=(Hsl left, Hsl right) => !left.Equals(right); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public override int GetHashCode() => HashCode.Combine(this.H, this.S, this.L); - - /// - public override string ToString() => FormattableString.Invariant($"Hsl({this.H:#0.##}, {this.S:#0.##}, {this.L:#0.##})"); - - /// - public override bool Equals(object? obj) => obj is Hsl other && this.Equals(other); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public bool Equals(Hsl other) - => this.H.Equals(other.H) - && this.S.Equals(other.S) - && this.L.Equals(other.L); -} diff --git a/src/ImageSharp/ColorSpaces/Hsv.cs b/src/ImageSharp/ColorSpaces/Hsv.cs deleted file mode 100644 index 87c16c0b6a..0000000000 --- a/src/ImageSharp/ColorSpaces/Hsv.cs +++ /dev/null @@ -1,98 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Numerics; -using System.Runtime.CompilerServices; - -namespace SixLabors.ImageSharp.ColorSpaces; - -/// -/// Represents a HSV (hue, saturation, value) color. Also known as HSB (hue, saturation, brightness). -/// -public readonly struct Hsv : IEquatable -{ - private static readonly Vector3 Min = Vector3.Zero; - private static readonly Vector3 Max = new(360, 1, 1); - - /// - /// Initializes a new instance of the struct. - /// - /// The h hue component. - /// The s saturation component. - /// The v value (brightness) component. - [MethodImpl(InliningOptions.ShortMethod)] - public Hsv(float h, float s, float v) - : this(new Vector3(h, s, v)) - { - } - - /// - /// Initializes a new instance of the struct. - /// - /// The vector representing the h, s, v components. - [MethodImpl(InliningOptions.ShortMethod)] - public Hsv(Vector3 vector) - { - vector = Vector3.Clamp(vector, Min, Max); - this.H = vector.X; - this.S = vector.Y; - this.V = vector.Z; - } - - /// - /// Gets the hue component. - /// A value ranging between 0 and 360. - /// - public readonly float H { get; } - - /// - /// Gets the saturation component. - /// A value ranging between 0 and 1. - /// - public readonly float S { get; } - - /// - /// Gets the value (brightness) component. - /// A value ranging between 0 and 1. - /// - public readonly float V { get; } - - /// - /// Compares two objects for equality. - /// - /// The on the left side of the operand. - /// The on the right side of the operand. - /// - /// True if the current left is equal to the parameter; otherwise, false. - /// - [MethodImpl(InliningOptions.ShortMethod)] - public static bool operator ==(Hsv left, Hsv right) => left.Equals(right); - - /// - /// Compares two objects for inequality. - /// - /// The on the left side of the operand. - /// The on the right side of the operand. - /// - /// True if the current left is unequal to the parameter; otherwise, false. - /// - [MethodImpl(InliningOptions.ShortMethod)] - public static bool operator !=(Hsv left, Hsv right) => !left.Equals(right); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public override int GetHashCode() => HashCode.Combine(this.H, this.S, this.V); - - /// - public override string ToString() => FormattableString.Invariant($"Hsv({this.H:#0.##}, {this.S:#0.##}, {this.V:#0.##})"); - - /// - public override bool Equals(object? obj) => obj is Hsv other && this.Equals(other); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public bool Equals(Hsv other) - => this.H.Equals(other.H) - && this.S.Equals(other.S) - && this.V.Equals(other.V); -} diff --git a/src/ImageSharp/ColorSpaces/HunterLab.cs b/src/ImageSharp/ColorSpaces/HunterLab.cs deleted file mode 100644 index 516574b098..0000000000 --- a/src/ImageSharp/ColorSpaces/HunterLab.cs +++ /dev/null @@ -1,134 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Numerics; -using System.Runtime.CompilerServices; - -namespace SixLabors.ImageSharp.ColorSpaces; - -/// -/// Represents an Hunter LAB color. -/// . -/// -public readonly struct HunterLab : IEquatable -{ - /// - /// D50 standard illuminant. - /// Used when reference white is not specified explicitly. - /// - public static readonly CieXyz DefaultWhitePoint = Illuminants.C; - - /// - /// Initializes a new instance of the struct. - /// - /// The lightness dimension. - /// The a (green - magenta) component. - /// The b (blue - yellow) component. - /// Uses as white point. - [MethodImpl(InliningOptions.ShortMethod)] - public HunterLab(float l, float a, float b) - : this(new Vector3(l, a, b), DefaultWhitePoint) - { - } - - /// - /// Initializes a new instance of the struct. - /// - /// The lightness dimension. - /// The a (green - magenta) component. - /// The b (blue - yellow) component. - /// The reference white point. - [MethodImpl(InliningOptions.ShortMethod)] - public HunterLab(float l, float a, float b, CieXyz whitePoint) - : this(new Vector3(l, a, b), whitePoint) - { - } - - /// - /// Initializes a new instance of the struct. - /// - /// The vector representing the l, a, b components. - /// Uses as white point. - [MethodImpl(InliningOptions.ShortMethod)] - public HunterLab(Vector3 vector) - : this(vector, DefaultWhitePoint) - { - } - - /// - /// Initializes a new instance of the struct. - /// - /// The vector representing the l a b components. - /// The reference white point. - [MethodImpl(InliningOptions.ShortMethod)] - public HunterLab(Vector3 vector, CieXyz whitePoint) - { - // Not clamping as documentation about this space only indicates "usual" ranges - this.L = vector.X; - this.A = vector.Y; - this.B = vector.Z; - this.WhitePoint = whitePoint; - } - - /// - /// Gets the lightness dimension. - /// A value usually ranging between 0 (black), 100 (diffuse white) or higher (specular white). - /// - public readonly float L { get; } - - /// - /// Gets the a color component. - /// A value usually ranging from -100 to 100. Negative is green, positive magenta. - /// - public readonly float A { get; } - - /// - /// Gets the b color component. - /// A value usually ranging from -100 to 100. Negative is blue, positive is yellow - /// - public readonly float B { get; } - - /// - /// Gets the reference white point of this color. - /// - public readonly CieXyz WhitePoint { get; } - - /// - /// Compares two objects for equality. - /// - /// The on the left side of the operand. - /// The on the right side of the operand. - /// - /// True if the current left is equal to the parameter; otherwise, false. - /// - public static bool operator ==(HunterLab left, HunterLab right) => left.Equals(right); - - /// - /// Compares two objects for inequality - /// - /// The on the left side of the operand. - /// The on the right side of the operand. - /// - /// True if the current left is unequal to the parameter; otherwise, false. - /// - [MethodImpl(InliningOptions.ShortMethod)] - public static bool operator !=(HunterLab left, HunterLab right) => !left.Equals(right); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public override int GetHashCode() => HashCode.Combine(this.L, this.A, this.B, this.WhitePoint); - - /// - public override string ToString() => FormattableString.Invariant($"HunterLab({this.L:#0.##}, {this.A:#0.##}, {this.B:#0.##})"); - - /// - public override bool Equals(object? obj) => obj is HunterLab other && this.Equals(other); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public bool Equals(HunterLab other) - => this.L.Equals(other.L) - && this.A.Equals(other.A) - && this.B.Equals(other.B) - && this.WhitePoint.Equals(other.WhitePoint); -} diff --git a/src/ImageSharp/ColorSpaces/Illuminants.cs b/src/ImageSharp/ColorSpaces/Illuminants.cs deleted file mode 100644 index 7c25305c2c..0000000000 --- a/src/ImageSharp/ColorSpaces/Illuminants.cs +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -namespace SixLabors.ImageSharp.ColorSpaces; - -/// -/// The well known standard illuminants. -/// Standard illuminants provide a basis for comparing images or colors recorded under different lighting -/// -/// -/// Coefficients taken from: http://www.brucelindbloom.com/index.html?Eqn_ChromAdapt.html -///
-/// Descriptions taken from: http://en.wikipedia.org/wiki/Standard_illuminant -///
-public static class Illuminants -{ - /// - /// Incandescent / Tungsten - /// - public static readonly CieXyz A = new CieXyz(1.09850F, 1F, 0.35585F); - - /// - /// Direct sunlight at noon (obsoleteF) - /// - public static readonly CieXyz B = new CieXyz(0.99072F, 1F, 0.85223F); - - /// - /// Average / North sky Daylight (obsoleteF) - /// - public static readonly CieXyz C = new CieXyz(0.98074F, 1F, 1.18232F); - - /// - /// Horizon Light. ICC profile PCS - /// - public static readonly CieXyz D50 = new CieXyz(0.96422F, 1F, 0.82521F); - - /// - /// Mid-morning / Mid-afternoon Daylight - /// - public static readonly CieXyz D55 = new CieXyz(0.95682F, 1F, 0.92149F); - - /// - /// Noon Daylight: TelevisionF, sRGB color space - /// - public static readonly CieXyz D65 = new CieXyz(0.95047F, 1F, 1.08883F); - - /// - /// North sky Daylight - /// - public static readonly CieXyz D75 = new CieXyz(0.94972F, 1F, 1.22638F); - - /// - /// Equal energy - /// - public static readonly CieXyz E = new CieXyz(1F, 1F, 1F); - - /// - /// Cool White Fluorescent - /// - public static readonly CieXyz F2 = new CieXyz(0.99186F, 1F, 0.67393F); - - /// - /// D65 simulatorF, Daylight simulator - /// - public static readonly CieXyz F7 = new CieXyz(0.95041F, 1F, 1.08747F); - - /// - /// Philips TL84F, Ultralume 40 - /// - public static readonly CieXyz F11 = new CieXyz(1.00962F, 1F, 0.64350F); -} diff --git a/src/ImageSharp/ColorSpaces/LinearRgb.cs b/src/ImageSharp/ColorSpaces/LinearRgb.cs deleted file mode 100644 index 49c7814a0e..0000000000 --- a/src/ImageSharp/ColorSpaces/LinearRgb.cs +++ /dev/null @@ -1,142 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Numerics; -using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.ColorSpaces; - -/// -/// Represents an linear Rgb color with specified working space -/// -public readonly struct LinearRgb : IEquatable -{ - private static readonly Vector3 Min = Vector3.Zero; - private static readonly Vector3 Max = Vector3.One; - - /// - /// The default LinearRgb working space. - /// - public static readonly RgbWorkingSpace DefaultWorkingSpace = RgbWorkingSpaces.SRgb; - - /// - /// Initializes a new instance of the struct. - /// - /// The red component ranging between 0 and 1. - /// The green component ranging between 0 and 1. - /// The blue component ranging between 0 and 1. - [MethodImpl(InliningOptions.ShortMethod)] - public LinearRgb(float r, float g, float b) - : this(r, g, b, DefaultWorkingSpace) - { - } - - /// - /// Initializes a new instance of the struct. - /// - /// The red component ranging between 0 and 1. - /// The green component ranging between 0 and 1. - /// The blue component ranging between 0 and 1. - /// The rgb working space. - [MethodImpl(InliningOptions.ShortMethod)] - public LinearRgb(float r, float g, float b, RgbWorkingSpace workingSpace) - : this(new Vector3(r, g, b), workingSpace) - { - } - - /// - /// Initializes a new instance of the struct. - /// - /// The vector representing the r, g, b components. - [MethodImpl(InliningOptions.ShortMethod)] - public LinearRgb(Vector3 vector) - : this(vector, DefaultWorkingSpace) - { - } - - /// - /// Initializes a new instance of the struct. - /// - /// The vector representing the r, g, b components. - /// The LinearRgb working space. - [MethodImpl(InliningOptions.ShortMethod)] - public LinearRgb(Vector3 vector, RgbWorkingSpace workingSpace) - { - // Clamp to 0-1 range. - vector = Vector3.Clamp(vector, Min, Max); - this.R = vector.X; - this.G = vector.Y; - this.B = vector.Z; - this.WorkingSpace = workingSpace; - } - - /// - /// Gets the red component. - /// A value usually ranging between 0 and 1. - /// - public readonly float R { get; } - - /// - /// Gets the green component. - /// A value usually ranging between 0 and 1. - /// - public readonly float G { get; } - - /// - /// Gets the blue component. - /// A value usually ranging between 0 and 1. - /// - public readonly float B { get; } - - /// - /// Gets the LinearRgb color space - /// - public readonly RgbWorkingSpace WorkingSpace { get; } - - /// - /// Compares two objects for equality. - /// - /// The on the left side of the operand. - /// The on the right side of the operand. - /// - /// True if the current left is equal to the parameter; otherwise, false. - /// - [MethodImpl(InliningOptions.ShortMethod)] - public static bool operator ==(LinearRgb left, LinearRgb right) => left.Equals(right); - - /// - /// Compares two objects for inequality. - /// - /// The on the left side of the operand. - /// The on the right side of the operand. - /// - /// True if the current left is unequal to the parameter; otherwise, false. - /// - [MethodImpl(InliningOptions.ShortMethod)] - public static bool operator !=(LinearRgb left, LinearRgb right) => !left.Equals(right); - - /// - /// Returns a new representing this instance. - /// - /// The . - [MethodImpl(InliningOptions.ShortMethod)] - public Vector3 ToVector3() => new(this.R, this.G, this.B); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public override int GetHashCode() => HashCode.Combine(this.R, this.G, this.B); - - /// - public override string ToString() => FormattableString.Invariant($"LinearRgb({this.R:#0.##}, {this.G:#0.##}, {this.B:#0.##})"); - - /// - public override bool Equals(object? obj) => obj is LinearRgb other && this.Equals(other); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public bool Equals(LinearRgb other) - => this.R.Equals(other.R) - && this.G.Equals(other.G) - && this.B.Equals(other.B); -} diff --git a/src/ImageSharp/ColorSpaces/Rgb.cs b/src/ImageSharp/ColorSpaces/Rgb.cs deleted file mode 100644 index 55052a710e..0000000000 --- a/src/ImageSharp/ColorSpaces/Rgb.cs +++ /dev/null @@ -1,163 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Numerics; -using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.ColorSpaces.Conversion; -using SixLabors.ImageSharp.PixelFormats; - -namespace SixLabors.ImageSharp.ColorSpaces; - -/// -/// Represents an RGB color with specified working space. -/// -public readonly struct Rgb : IEquatable -{ - /// - /// The default rgb working space. - /// - public static readonly RgbWorkingSpace DefaultWorkingSpace = RgbWorkingSpaces.SRgb; - - private static readonly Vector3 Min = Vector3.Zero; - private static readonly Vector3 Max = Vector3.One; - - /// - /// Initializes a new instance of the struct. - /// - /// The red component ranging between 0 and 1. - /// The green component ranging between 0 and 1. - /// The blue component ranging between 0 and 1. - [MethodImpl(InliningOptions.ShortMethod)] - public Rgb(float r, float g, float b) - : this(r, g, b, DefaultWorkingSpace) - { - } - - /// - /// Initializes a new instance of the struct. - /// - /// The red component ranging between 0 and 1. - /// The green component ranging between 0 and 1. - /// The blue component ranging between 0 and 1. - /// The rgb working space. - [MethodImpl(InliningOptions.ShortMethod)] - public Rgb(float r, float g, float b, RgbWorkingSpace workingSpace) - : this(new Vector3(r, g, b), workingSpace) - { - } - - /// - /// Initializes a new instance of the struct. - /// - /// The vector representing the r, g, b components. - [MethodImpl(InliningOptions.ShortMethod)] - public Rgb(Vector3 vector) - : this(vector, DefaultWorkingSpace) - { - } - - /// - /// Initializes a new instance of the struct. - /// - /// The vector representing the r, g, b components. - /// The rgb working space. - [MethodImpl(InliningOptions.ShortMethod)] - public Rgb(Vector3 vector, RgbWorkingSpace workingSpace) - { - vector = Vector3.Clamp(vector, Min, Max); - this.R = vector.X; - this.G = vector.Y; - this.B = vector.Z; - this.WorkingSpace = workingSpace; - } - - /// - /// Gets the red component. - /// A value usually ranging between 0 and 1. - /// - public readonly float R { get; } - - /// - /// Gets the green component. - /// A value usually ranging between 0 and 1. - /// - public readonly float G { get; } - - /// - /// Gets the blue component. - /// A value usually ranging between 0 and 1. - /// - public readonly float B { get; } - - /// - /// Gets the Rgb color space - /// - public readonly RgbWorkingSpace WorkingSpace { get; } - - /// - /// Allows the implicit conversion of an instance of to a - /// . - /// - /// The instance of to convert. - /// An instance of . - [MethodImpl(InliningOptions.ShortMethod)] - public static implicit operator Rgb(Rgb24 color) => new(color.R / 255F, color.G / 255F, color.B / 255F); - - /// - /// Allows the implicit conversion of an instance of to a - /// . - /// - /// The instance of to convert. - /// An instance of . - [MethodImpl(InliningOptions.ShortMethod)] - public static implicit operator Rgb(Rgba32 color) => new(color.R / 255F, color.G / 255F, color.B / 255F); - - /// - /// Compares two objects for equality. - /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// - /// - /// True if the current left is equal to the parameter; otherwise, false. - /// - [MethodImpl(InliningOptions.ShortMethod)] - public static bool operator ==(Rgb left, Rgb right) => left.Equals(right); - - /// - /// Compares two objects for inequality. - /// - /// The on the left side of the operand. - /// The on the right side of the operand. - /// - /// True if the current left is unequal to the parameter; otherwise, false. - /// - [MethodImpl(InliningOptions.ShortMethod)] - public static bool operator !=(Rgb left, Rgb right) => !left.Equals(right); - - /// - /// Returns a new representing this instance. - /// - /// The . - [MethodImpl(InliningOptions.ShortMethod)] - public Vector3 ToVector3() => new(this.R, this.G, this.B); - - /// - public override int GetHashCode() => HashCode.Combine(this.R, this.G, this.B); - - /// - public override string ToString() => FormattableString.Invariant($"Rgb({this.R:#0.##}, {this.G:#0.##}, {this.B:#0.##})"); - - /// - public override bool Equals(object? obj) => obj is Rgb other && this.Equals(other); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public bool Equals(Rgb other) - => this.R.Equals(other.R) - && this.G.Equals(other.G) - && this.B.Equals(other.B); -} diff --git a/src/ImageSharp/ColorSpaces/RgbWorkingSpaces.cs b/src/ImageSharp/ColorSpaces/RgbWorkingSpaces.cs deleted file mode 100644 index 53c8c2cf08..0000000000 --- a/src/ImageSharp/ColorSpaces/RgbWorkingSpaces.cs +++ /dev/null @@ -1,114 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces.Companding; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -// ReSharper disable InconsistentNaming -namespace SixLabors.ImageSharp.ColorSpaces; - -/// -/// Chromaticity coordinates based on: -/// -public static class RgbWorkingSpaces -{ - /// - /// sRgb working space. - /// - /// - /// Uses proper companding function, according to: - /// - /// - public static readonly RgbWorkingSpace SRgb = new SRgbWorkingSpace(Illuminants.D65, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6400F, 0.3300F), new CieXyChromaticityCoordinates(0.3000F, 0.6000F), new CieXyChromaticityCoordinates(0.1500F, 0.0600F))); - - /// - /// Simplified sRgb working space (uses gamma companding instead of ). - /// See also . - /// - public static readonly RgbWorkingSpace SRgbSimplified = new GammaWorkingSpace(2.2F, Illuminants.D65, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6400F, 0.3300F), new CieXyChromaticityCoordinates(0.3000F, 0.6000F), new CieXyChromaticityCoordinates(0.1500F, 0.0600F))); - - /// - /// Rec. 709 (ITU-R Recommendation BT.709) working space. - /// - public static readonly RgbWorkingSpace Rec709 = new Rec709WorkingSpace(Illuminants.D65, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.64F, 0.33F), new CieXyChromaticityCoordinates(0.30F, 0.60F), new CieXyChromaticityCoordinates(0.15F, 0.06F))); - - /// - /// Rec. 2020 (ITU-R Recommendation BT.2020F) working space. - /// - public static readonly RgbWorkingSpace Rec2020 = new Rec2020WorkingSpace(Illuminants.D65, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.708F, 0.292F), new CieXyChromaticityCoordinates(0.170F, 0.797F), new CieXyChromaticityCoordinates(0.131F, 0.046F))); - - /// - /// ECI Rgb v2 working space. - /// - public static readonly RgbWorkingSpace ECIRgbv2 = new LWorkingSpace(Illuminants.D50, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6700F, 0.3300F), new CieXyChromaticityCoordinates(0.2100F, 0.7100F), new CieXyChromaticityCoordinates(0.1400F, 0.0800F))); - - /// - /// Adobe Rgb (1998) working space. - /// - public static readonly RgbWorkingSpace AdobeRgb1998 = new GammaWorkingSpace(2.2F, Illuminants.D65, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6400F, 0.3300F), new CieXyChromaticityCoordinates(0.2100F, 0.7100F), new CieXyChromaticityCoordinates(0.1500F, 0.0600F))); - - /// - /// Apple sRgb working space. - /// - public static readonly RgbWorkingSpace ApplesRgb = new GammaWorkingSpace(1.8F, Illuminants.D65, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6250F, 0.3400F), new CieXyChromaticityCoordinates(0.2800F, 0.5950F), new CieXyChromaticityCoordinates(0.1550F, 0.0700F))); - - /// - /// Best Rgb working space. - /// - public static readonly RgbWorkingSpace BestRgb = new GammaWorkingSpace(2.2F, Illuminants.D50, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.7347F, 0.2653F), new CieXyChromaticityCoordinates(0.2150F, 0.7750F), new CieXyChromaticityCoordinates(0.1300F, 0.0350F))); - - /// - /// Beta Rgb working space. - /// - public static readonly RgbWorkingSpace BetaRgb = new GammaWorkingSpace(2.2F, Illuminants.D50, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6888F, 0.3112F), new CieXyChromaticityCoordinates(0.1986F, 0.7551F), new CieXyChromaticityCoordinates(0.1265F, 0.0352F))); - - /// - /// Bruce Rgb working space. - /// - public static readonly RgbWorkingSpace BruceRgb = new GammaWorkingSpace(2.2F, Illuminants.D65, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6400F, 0.3300F), new CieXyChromaticityCoordinates(0.2800F, 0.6500F), new CieXyChromaticityCoordinates(0.1500F, 0.0600F))); - - /// - /// CIE Rgb working space. - /// - public static readonly RgbWorkingSpace CIERgb = new GammaWorkingSpace(2.2F, Illuminants.E, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.7350F, 0.2650F), new CieXyChromaticityCoordinates(0.2740F, 0.7170F), new CieXyChromaticityCoordinates(0.1670F, 0.0090F))); - - /// - /// ColorMatch Rgb working space. - /// - public static readonly RgbWorkingSpace ColorMatchRgb = new GammaWorkingSpace(1.8F, Illuminants.D50, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6300F, 0.3400F), new CieXyChromaticityCoordinates(0.2950F, 0.6050F), new CieXyChromaticityCoordinates(0.1500F, 0.0750F))); - - /// - /// Don Rgb 4 working space. - /// - public static readonly RgbWorkingSpace DonRgb4 = new GammaWorkingSpace(2.2F, Illuminants.D50, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6960F, 0.3000F), new CieXyChromaticityCoordinates(0.2150F, 0.7650F), new CieXyChromaticityCoordinates(0.1300F, 0.0350F))); - - /// - /// Ekta Space PS5 working space. - /// - public static readonly RgbWorkingSpace EktaSpacePS5 = new GammaWorkingSpace(2.2F, Illuminants.D50, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6950F, 0.3050F), new CieXyChromaticityCoordinates(0.2600F, 0.7000F), new CieXyChromaticityCoordinates(0.1100F, 0.0050F))); - - /// - /// NTSC Rgb working space. - /// - public static readonly RgbWorkingSpace NTSCRgb = new GammaWorkingSpace(2.2F, Illuminants.C, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6700F, 0.3300F), new CieXyChromaticityCoordinates(0.2100F, 0.7100F), new CieXyChromaticityCoordinates(0.1400F, 0.0800F))); - - /// - /// PAL/SECAM Rgb working space. - /// - public static readonly RgbWorkingSpace PALSECAMRgb = new GammaWorkingSpace(2.2F, Illuminants.D65, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6400F, 0.3300F), new CieXyChromaticityCoordinates(0.2900F, 0.6000F), new CieXyChromaticityCoordinates(0.1500F, 0.0600F))); - - /// - /// ProPhoto Rgb working space. - /// - public static readonly RgbWorkingSpace ProPhotoRgb = new GammaWorkingSpace(1.8F, Illuminants.D50, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.7347F, 0.2653F), new CieXyChromaticityCoordinates(0.1596F, 0.8404F), new CieXyChromaticityCoordinates(0.0366F, 0.0001F))); - - /// - /// SMPTE-C Rgb working space. - /// - public static readonly RgbWorkingSpace SMPTECRgb = new GammaWorkingSpace(2.2F, Illuminants.D65, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6300F, 0.3400F), new CieXyChromaticityCoordinates(0.3100F, 0.5950F), new CieXyChromaticityCoordinates(0.1550F, 0.0700F))); - - /// - /// Wide Gamut Rgb working space. - /// - public static readonly RgbWorkingSpace WideGamutRgb = new GammaWorkingSpace(2.2F, Illuminants.D50, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.7350F, 0.2650F), new CieXyChromaticityCoordinates(0.1150F, 0.8260F), new CieXyChromaticityCoordinates(0.1570F, 0.0180F))); -} diff --git a/src/ImageSharp/Common/Helpers/ColorNumerics.cs b/src/ImageSharp/Common/Helpers/ColorNumerics.cs index 553a7c2e89..1c30d857f6 100644 --- a/src/ImageSharp/Common/Helpers/ColorNumerics.cs +++ b/src/ImageSharp/Common/Helpers/ColorNumerics.cs @@ -41,6 +41,34 @@ public static int GetBT709Luminance(ref Vector4 vector, int luminanceLevels) public static byte Get8BitBT709Luminance(byte r, byte g, byte b) => (byte)((r * .2126F) + (g * .7152F) + (b * .0722F) + 0.5F); + /// + /// Gets the luminance from the rgb components using the formula + /// as specified by ITU-R Recommendation BT.709. + /// + /// The red component. + /// The green component. + /// The blue component. + /// The . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static byte Get8BitBT709Luminance(ushort r, ushort g, ushort b) + => (byte)((From16BitTo8Bit(r) * .2126F) + + (From16BitTo8Bit(g) * .7152F) + + (From16BitTo8Bit(b) * .0722F) + 0.5F); + + /// + /// Gets the luminance from the rgb components using the formula as + /// specified by ITU-R Recommendation BT.709. + /// + /// The red component. + /// The green component. + /// The blue component. + /// The . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ushort Get16BitBT709Luminance(byte r, byte g, byte b) + => (ushort)((From8BitTo16Bit(r) * .2126F) + + (From8BitTo16Bit(g) * .7152F) + + (From8BitTo16Bit(b) * .0722F) + 0.5F); + /// /// Gets the luminance from the rgb components using the formula as /// specified by ITU-R Recommendation BT.709. @@ -72,8 +100,8 @@ public static ushort Get16BitBT709Luminance(float r, float g, float b) /// The 8 bit component value. /// The [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static byte DownScaleFrom16BitTo8Bit(ushort component) - { + public static byte From16BitTo8Bit(ushort component) => + // To scale to 8 bits From a 16-bit value V the required value (from the PNG specification) is: // // (V * 255) / 65535 @@ -102,8 +130,7 @@ public static byte DownScaleFrom16BitTo8Bit(ushort component) // An alternative arithmetic calculation which also gives no errors is: // // (V * 255 + 32895) >> 16 - return (byte)(((component * 255) + 32895) >> 16); - } + (byte)(((component * 255) + 32895) >> 16); /// /// Scales a value from an 8 bit to @@ -112,7 +139,7 @@ public static byte DownScaleFrom16BitTo8Bit(ushort component) /// The 8 bit component value. /// The [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ushort UpscaleFrom8BitTo16Bit(byte component) + public static ushort From8BitTo16Bit(byte component) => (ushort)(component * 257); /// diff --git a/src/ImageSharp/Common/Helpers/DebugGuard.cs b/src/ImageSharp/Common/Helpers/DebugGuard.cs index be2daa139e..990b21c99e 100644 --- a/src/ImageSharp/Common/Helpers/DebugGuard.cs +++ b/src/ImageSharp/Common/Helpers/DebugGuard.cs @@ -33,10 +33,12 @@ public static void IsTrue(bool target, string message) [Conditional("DEBUG")] public static void NotDisposed(bool isDisposed, string objectName) { +#pragma warning disable CA1513 if (isDisposed) { throw new ObjectDisposedException(objectName); } +#pragma warning restore CA1513 } /// diff --git a/src/ImageSharp/Common/Helpers/Numerics.cs b/src/ImageSharp/Common/Helpers/Numerics.cs index aba3c0abdc..ca14ae4c38 100644 --- a/src/ImageSharp/Common/Helpers/Numerics.cs +++ b/src/ImageSharp/Common/Helpers/Numerics.cs @@ -5,7 +5,6 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Intrinsics; -using System.Runtime.Intrinsics.Arm; using System.Runtime.Intrinsics.X86; namespace SixLabors.ImageSharp; @@ -61,6 +60,12 @@ public static int LeastCommonMultiple(int a, int b) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static nint Modulo4(nint x) => x & 3; + /// + /// Calculates % 4 + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static nuint Modulo4(nuint x) => x & 3; + /// /// Calculates % 8 /// @@ -136,6 +141,14 @@ public static int Abs(int x) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Pow3(float x) => x * x * x; + /// + /// Returns a specified number raised to the power of 3 + /// + /// A double-precision floating-point number + /// The number raised to the power of 3. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static double Pow3(double x) => x * x * x; + /// /// Implementation of 1D Gaussian G(x) function /// @@ -908,25 +921,6 @@ public static int ReduceSum(Vector256 accumulator) return Sse2.ConvertToInt32(vsum); } - /// - /// Reduces elements of the vector into one sum. - /// - /// The accumulator to reduce. - /// The sum of all elements. - [MethodImpl(InliningOptions.ShortMethod)] - public static int ReduceSumArm(Vector128 accumulator) - { - if (AdvSimd.Arm64.IsSupported) - { - Vector64 sum = AdvSimd.Arm64.AddAcross(accumulator); - return (int)AdvSimd.Extract(sum, 0); - } - - Vector128 sum2 = AdvSimd.AddPairwiseWidening(accumulator); - Vector64 sum3 = AdvSimd.Add(sum2.GetLower().AsUInt32(), sum2.GetUpper().AsUInt32()); - return (int)AdvSimd.Extract(sum3, 0); - } - /// /// Reduces even elements of the vector into one sum. /// @@ -1024,6 +1018,26 @@ public static nuint Vector256Count(this ReadOnlySpan span) where TVector : struct => (uint)span.Length / (uint)Vector256.Count; + /// + /// Gets the count of vectors that safely fit into the given span. + /// + /// The type of the vector. + /// The given span. + /// Count of vectors that safely fit into the span. + public static nuint Vector512Count(this Span span) + where TVector : struct + => (uint)span.Length / (uint)Vector512.Count; + + /// + /// Gets the count of vectors that safely fit into the given span. + /// + /// The type of the vector. + /// The given span. + /// Count of vectors that safely fit into the span. + public static nuint Vector512Count(this ReadOnlySpan span) + where TVector : struct + => (uint)span.Length / (uint)Vector512.Count; + /// /// Gets the count of vectors that safely fit into the given span. /// @@ -1063,4 +1077,24 @@ public static nuint Vector256Count(this Span span) public static nuint Vector256Count(int length) where TVector : struct => (uint)length / (uint)Vector256.Count; + + /// + /// Gets the count of vectors that safely fit into the given span. + /// + /// The type of the vector. + /// The given span. + /// Count of vectors that safely fit into the span. + public static nuint Vector512Count(this Span span) + where TVector : struct + => (uint)span.Length / (uint)Vector512.Count; + + /// + /// Gets the count of vectors that safely fit into length. + /// + /// The type of the vector. + /// The given length. + /// Count of vectors that safely fit into the length. + public static nuint Vector512Count(int length) + where TVector : struct + => (uint)length / (uint)Vector512.Count; } diff --git a/src/ImageSharp/Common/Helpers/Shuffle/IComponentShuffle.cs b/src/ImageSharp/Common/Helpers/Shuffle/IComponentShuffle.cs index 683ac518b8..c856267db2 100644 --- a/src/ImageSharp/Common/Helpers/Shuffle/IComponentShuffle.cs +++ b/src/ImageSharp/Common/Helpers/Shuffle/IComponentShuffle.cs @@ -1,12 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using System.Buffers.Binary; -using System.Numerics; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using static SixLabors.ImageSharp.SimdUtils; - // The JIT can detect and optimize rotation idioms ROTL (Rotate Left) // and ROTR (Rotate Right) emitting efficient CPU instructions: // https://github.com/dotnet/coreclr/pull/1830 @@ -19,190 +13,24 @@ namespace SixLabors.ImageSharp; internal interface IComponentShuffle { /// - /// Shuffles then slices 8-bit integers within 128-bit lanes in - /// using the control and store the results in . + /// Shuffles then slices 8-bit integers in + /// using a byte control and store the results in . + /// If successful, this method will reduce the length of length + /// by the shuffle amount. /// /// The source span of bytes. - /// The destination span of bytes. - void ShuffleReduce(ref ReadOnlySpan source, ref Span dest); + /// The destination span of bytes. + void ShuffleReduce(ref ReadOnlySpan source, ref Span destination); /// - /// Shuffle 8-bit integers within 128-bit lanes in - /// using the control and store the results in . + /// Shuffle 8-bit integers in + /// using the control and store the results in . /// /// The source span of bytes. - /// The destination span of bytes. + /// The destination span of bytes. /// - /// Implementation can assume that source.Length is less or equal than dest.Length. + /// Implementation can assume that source.Length is less or equal than destination.Length. /// Loops should iterate using source.Length. /// - void RunFallbackShuffle(ReadOnlySpan source, Span dest); -} - -/// -internal interface IShuffle4 : IComponentShuffle -{ -} - -internal readonly struct DefaultShuffle4 : IShuffle4 -{ - public DefaultShuffle4(byte control) - => this.Control = control; - - public byte Control { get; } - - [MethodImpl(InliningOptions.ShortMethod)] - public void ShuffleReduce(ref ReadOnlySpan source, ref Span dest) - => HwIntrinsics.Shuffle4Reduce(ref source, ref dest, this.Control); - - [MethodImpl(InliningOptions.ShortMethod)] - public void RunFallbackShuffle(ReadOnlySpan source, Span dest) - { - ref byte sBase = ref MemoryMarshal.GetReference(source); - ref byte dBase = ref MemoryMarshal.GetReference(dest); - - Shuffle.InverseMMShuffle(this.Control, out uint p3, out uint p2, out uint p1, out uint p0); - - for (nuint i = 0; i < (uint)source.Length; i += 4) - { - Unsafe.Add(ref dBase, i + 0) = Unsafe.Add(ref sBase, p0 + i); - Unsafe.Add(ref dBase, i + 1) = Unsafe.Add(ref sBase, p1 + i); - Unsafe.Add(ref dBase, i + 2) = Unsafe.Add(ref sBase, p2 + i); - Unsafe.Add(ref dBase, i + 3) = Unsafe.Add(ref sBase, p3 + i); - } - } -} - -internal readonly struct WXYZShuffle4 : IShuffle4 -{ - [MethodImpl(InliningOptions.ShortMethod)] - public void ShuffleReduce(ref ReadOnlySpan source, ref Span dest) - => HwIntrinsics.Shuffle4Reduce(ref source, ref dest, Shuffle.MMShuffle2103); - - [MethodImpl(InliningOptions.ShortMethod)] - public void RunFallbackShuffle(ReadOnlySpan source, Span dest) - { - ref uint sBase = ref Unsafe.As(ref MemoryMarshal.GetReference(source)); - ref uint dBase = ref Unsafe.As(ref MemoryMarshal.GetReference(dest)); - uint n = (uint)source.Length / 4; - - for (nuint i = 0; i < n; i++) - { - uint packed = Unsafe.Add(ref sBase, i); - - // packed = [W Z Y X] - // ROTL(8, packed) = [Z Y X W] - Unsafe.Add(ref dBase, i) = (packed << 8) | (packed >> 24); - } - } -} - -internal readonly struct WZYXShuffle4 : IShuffle4 -{ - [MethodImpl(InliningOptions.ShortMethod)] - public void ShuffleReduce(ref ReadOnlySpan source, ref Span dest) - => HwIntrinsics.Shuffle4Reduce(ref source, ref dest, Shuffle.MMShuffle0123); - - [MethodImpl(InliningOptions.ShortMethod)] - public void RunFallbackShuffle(ReadOnlySpan source, Span dest) - { - ref uint sBase = ref Unsafe.As(ref MemoryMarshal.GetReference(source)); - ref uint dBase = ref Unsafe.As(ref MemoryMarshal.GetReference(dest)); - uint n = (uint)source.Length / 4; - - for (nuint i = 0; i < n; i++) - { - uint packed = Unsafe.Add(ref sBase, i); - - // packed = [W Z Y X] - // REVERSE(packedArgb) = [X Y Z W] - Unsafe.Add(ref dBase, i) = BinaryPrimitives.ReverseEndianness(packed); - } - } -} - -internal readonly struct YZWXShuffle4 : IShuffle4 -{ - [MethodImpl(InliningOptions.ShortMethod)] - public void ShuffleReduce(ref ReadOnlySpan source, ref Span dest) - => HwIntrinsics.Shuffle4Reduce(ref source, ref dest, Shuffle.MMShuffle0321); - - [MethodImpl(InliningOptions.ShortMethod)] - public void RunFallbackShuffle(ReadOnlySpan source, Span dest) - { - ref uint sBase = ref Unsafe.As(ref MemoryMarshal.GetReference(source)); - ref uint dBase = ref Unsafe.As(ref MemoryMarshal.GetReference(dest)); - uint n = (uint)source.Length / 4; - - for (nuint i = 0; i < n; i++) - { - uint packed = Unsafe.Add(ref sBase, i); - - // packed = [W Z Y X] - // ROTR(8, packedArgb) = [Y Z W X] - Unsafe.Add(ref dBase, i) = BitOperations.RotateRight(packed, 8); - } - } -} - -internal readonly struct ZYXWShuffle4 : IShuffle4 -{ - [MethodImpl(InliningOptions.ShortMethod)] - public void ShuffleReduce(ref ReadOnlySpan source, ref Span dest) - => HwIntrinsics.Shuffle4Reduce(ref source, ref dest, Shuffle.MMShuffle3012); - - [MethodImpl(InliningOptions.ShortMethod)] - public void RunFallbackShuffle(ReadOnlySpan source, Span dest) - { - ref uint sBase = ref Unsafe.As(ref MemoryMarshal.GetReference(source)); - ref uint dBase = ref Unsafe.As(ref MemoryMarshal.GetReference(dest)); - uint n = (uint)source.Length / 4; - - for (nuint i = 0; i < n; i++) - { - uint packed = Unsafe.Add(ref sBase, i); - - // packed = [W Z Y X] - // tmp1 = [W 0 Y 0] - // tmp2 = [0 Z 0 X] - // tmp3=ROTL(16, tmp2) = [0 X 0 Z] - // tmp1 + tmp3 = [W X Y Z] - uint tmp1 = packed & 0xFF00FF00; - uint tmp2 = packed & 0x00FF00FF; - uint tmp3 = BitOperations.RotateLeft(tmp2, 16); - - Unsafe.Add(ref dBase, i) = tmp1 + tmp3; - } - } -} - -internal readonly struct XWZYShuffle4 : IShuffle4 -{ - [MethodImpl(InliningOptions.ShortMethod)] - public void ShuffleReduce(ref ReadOnlySpan source, ref Span dest) - => HwIntrinsics.Shuffle4Reduce(ref source, ref dest, Shuffle.MMShuffle1230); - - [MethodImpl(InliningOptions.ShortMethod)] - public void RunFallbackShuffle(ReadOnlySpan source, Span dest) - { - ref uint sBase = ref Unsafe.As(ref MemoryMarshal.GetReference(source)); - ref uint dBase = ref Unsafe.As(ref MemoryMarshal.GetReference(dest)); - uint n = (uint)source.Length / 4; - - for (nuint i = 0; i < n; i++) - { - uint packed = Unsafe.Add(ref sBase, i); - - // packed = [W Z Y X] - // tmp1 = [0 Z 0 X] - // tmp2 = [W 0 Y 0] - // tmp3=ROTL(16, tmp2) = [Y 0 W 0] - // tmp1 + tmp3 = [Y Z W X] - uint tmp1 = packed & 0x00FF00FF; - uint tmp2 = packed & 0xFF00FF00; - uint tmp3 = BitOperations.RotateLeft(tmp2, 16); - - Unsafe.Add(ref dBase, i) = tmp1 + tmp3; - } - } + void Shuffle(ReadOnlySpan source, Span destination); } diff --git a/src/ImageSharp/Common/Helpers/Shuffle/IPad3Shuffle4.cs b/src/ImageSharp/Common/Helpers/Shuffle/IPad3Shuffle4.cs index 6cf6eef08e..0f282c7f9a 100644 --- a/src/ImageSharp/Common/Helpers/Shuffle/IPad3Shuffle4.cs +++ b/src/ImageSharp/Common/Helpers/Shuffle/IPad3Shuffle4.cs @@ -1,6 +1,7 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. +using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using static SixLabors.ImageSharp.SimdUtils; @@ -12,24 +13,23 @@ internal interface IPad3Shuffle4 : IComponentShuffle { } -internal readonly struct DefaultPad3Shuffle4 : IPad3Shuffle4 +internal readonly struct DefaultPad3Shuffle4([ConstantExpected] byte control) : IPad3Shuffle4 { - public DefaultPad3Shuffle4(byte control) - => this.Control = control; - - public byte Control { get; } + public byte Control { get; } = control; [MethodImpl(InliningOptions.ShortMethod)] - public void ShuffleReduce(ref ReadOnlySpan source, ref Span dest) - => HwIntrinsics.Pad3Shuffle4Reduce(ref source, ref dest, this.Control); + public void ShuffleReduce(ref ReadOnlySpan source, ref Span destination) +#pragma warning disable CA1857 // A constant is expected for the parameter + => HwIntrinsics.Pad3Shuffle4Reduce(ref source, ref destination, this.Control); +#pragma warning restore CA1857 // A constant is expected for the parameter [MethodImpl(InliningOptions.ShortMethod)] - public void RunFallbackShuffle(ReadOnlySpan source, Span dest) + public void Shuffle(ReadOnlySpan source, Span destination) { ref byte sBase = ref MemoryMarshal.GetReference(source); - ref byte dBase = ref MemoryMarshal.GetReference(dest); + ref byte dBase = ref MemoryMarshal.GetReference(destination); - Shuffle.InverseMMShuffle(this.Control, out uint p3, out uint p2, out uint p1, out uint p0); + SimdUtils.Shuffle.InverseMMShuffle(this.Control, out uint p3, out uint p2, out uint p1, out uint p0); Span temp = stackalloc byte[4]; ref byte t = ref MemoryMarshal.GetReference(temp); @@ -51,14 +51,14 @@ public void RunFallbackShuffle(ReadOnlySpan source, Span dest) internal readonly struct XYZWPad3Shuffle4 : IPad3Shuffle4 { [MethodImpl(InliningOptions.ShortMethod)] - public void ShuffleReduce(ref ReadOnlySpan source, ref Span dest) - => HwIntrinsics.Pad3Shuffle4Reduce(ref source, ref dest, Shuffle.MMShuffle3210); + public void ShuffleReduce(ref ReadOnlySpan source, ref Span destination) + => HwIntrinsics.Pad3Shuffle4Reduce(ref source, ref destination, SimdUtils.Shuffle.MMShuffle3210); [MethodImpl(InliningOptions.ShortMethod)] - public void RunFallbackShuffle(ReadOnlySpan source, Span dest) + public void Shuffle(ReadOnlySpan source, Span destination) { ref byte sBase = ref MemoryMarshal.GetReference(source); - ref byte dBase = ref MemoryMarshal.GetReference(dest); + ref byte dBase = ref MemoryMarshal.GetReference(destination); ref byte sEnd = ref Unsafe.Add(ref sBase, (uint)source.Length); ref byte sLoopEnd = ref Unsafe.Subtract(ref sEnd, 4); diff --git a/src/ImageSharp/Common/Helpers/Shuffle/IShuffle3.cs b/src/ImageSharp/Common/Helpers/Shuffle/IShuffle3.cs index 2cd586212e..3c0973ad69 100644 --- a/src/ImageSharp/Common/Helpers/Shuffle/IShuffle3.cs +++ b/src/ImageSharp/Common/Helpers/Shuffle/IShuffle3.cs @@ -1,6 +1,7 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. +using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using static SixLabors.ImageSharp.SimdUtils; @@ -12,24 +13,23 @@ internal interface IShuffle3 : IComponentShuffle { } -internal readonly struct DefaultShuffle3 : IShuffle3 +internal readonly struct DefaultShuffle3([ConstantExpected] byte control) : IShuffle3 { - public DefaultShuffle3(byte control) - => this.Control = control; - - public byte Control { get; } + public byte Control { get; } = control; [MethodImpl(InliningOptions.ShortMethod)] - public void ShuffleReduce(ref ReadOnlySpan source, ref Span dest) - => HwIntrinsics.Shuffle3Reduce(ref source, ref dest, this.Control); + public void ShuffleReduce(ref ReadOnlySpan source, ref Span destination) +#pragma warning disable CA1857 // A constant is expected for the parameter + => HwIntrinsics.Shuffle3Reduce(ref source, ref destination, this.Control); +#pragma warning restore CA1857 // A constant is expected for the parameter [MethodImpl(InliningOptions.ShortMethod)] - public void RunFallbackShuffle(ReadOnlySpan source, Span dest) + public void Shuffle(ReadOnlySpan source, Span destination) { ref byte sBase = ref MemoryMarshal.GetReference(source); - ref byte dBase = ref MemoryMarshal.GetReference(dest); + ref byte dBase = ref MemoryMarshal.GetReference(destination); - Shuffle.InverseMMShuffle(this.Control, out _, out uint p2, out uint p1, out uint p0); + SimdUtils.Shuffle.InverseMMShuffle(this.Control, out _, out uint p2, out uint p1, out uint p0); for (nuint i = 0; i < (uint)source.Length; i += 3) { diff --git a/src/ImageSharp/Common/Helpers/Shuffle/IShuffle4.cs b/src/ImageSharp/Common/Helpers/Shuffle/IShuffle4.cs new file mode 100644 index 0000000000..d5c6df2c8b --- /dev/null +++ b/src/ImageSharp/Common/Helpers/Shuffle/IShuffle4.cs @@ -0,0 +1,178 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Buffers.Binary; +using System.Diagnostics.CodeAnalysis; +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using static SixLabors.ImageSharp.SimdUtils; + +namespace SixLabors.ImageSharp; + +/// +internal interface IShuffle4 : IComponentShuffle +{ +} + +internal readonly struct DefaultShuffle4([ConstantExpected] byte control) : IShuffle4 +{ + public byte Control { get; } = control; + + [MethodImpl(InliningOptions.ShortMethod)] + public void ShuffleReduce(ref ReadOnlySpan source, ref Span destination) +#pragma warning disable CA1857 // A constant is expected for the parameter + => HwIntrinsics.Shuffle4Reduce(ref source, ref destination, this.Control); +#pragma warning restore CA1857 // A constant is expected for the parameter + + [MethodImpl(InliningOptions.ShortMethod)] + public void Shuffle(ReadOnlySpan source, Span destination) + { + ref byte sBase = ref MemoryMarshal.GetReference(source); + ref byte dBase = ref MemoryMarshal.GetReference(destination); + + SimdUtils.Shuffle.InverseMMShuffle(this.Control, out uint p3, out uint p2, out uint p1, out uint p0); + + for (nuint i = 0; i < (uint)source.Length; i += 4) + { + Unsafe.Add(ref dBase, i + 0) = Unsafe.Add(ref sBase, p0 + i); + Unsafe.Add(ref dBase, i + 1) = Unsafe.Add(ref sBase, p1 + i); + Unsafe.Add(ref dBase, i + 2) = Unsafe.Add(ref sBase, p2 + i); + Unsafe.Add(ref dBase, i + 3) = Unsafe.Add(ref sBase, p3 + i); + } + } +} + +internal readonly struct WXYZShuffle4 : IShuffle4 +{ + [MethodImpl(InliningOptions.ShortMethod)] + public void ShuffleReduce(ref ReadOnlySpan source, ref Span destination) + => HwIntrinsics.Shuffle4Reduce(ref source, ref destination, SimdUtils.Shuffle.MMShuffle2103); + + [MethodImpl(InliningOptions.ShortMethod)] + public void Shuffle(ReadOnlySpan source, Span destination) + { + ref uint sBase = ref Unsafe.As(ref MemoryMarshal.GetReference(source)); + ref uint dBase = ref Unsafe.As(ref MemoryMarshal.GetReference(destination)); + uint n = (uint)source.Length / 4; + + for (nuint i = 0; i < n; i++) + { + uint packed = Unsafe.Add(ref sBase, i); + + // packed = [W Z Y X] + // ROTL(8, packed) = [Z Y X W] + Unsafe.Add(ref dBase, i) = (packed << 8) | (packed >> 24); + } + } +} + +internal readonly struct WZYXShuffle4 : IShuffle4 +{ + [MethodImpl(InliningOptions.ShortMethod)] + public void ShuffleReduce(ref ReadOnlySpan source, ref Span destination) + => HwIntrinsics.Shuffle4Reduce(ref source, ref destination, SimdUtils.Shuffle.MMShuffle0123); + + [MethodImpl(InliningOptions.ShortMethod)] + public void Shuffle(ReadOnlySpan source, Span destination) + { + ref uint sBase = ref Unsafe.As(ref MemoryMarshal.GetReference(source)); + ref uint dBase = ref Unsafe.As(ref MemoryMarshal.GetReference(destination)); + uint n = (uint)source.Length / 4; + + for (nuint i = 0; i < n; i++) + { + uint packed = Unsafe.Add(ref sBase, i); + + // packed = [W Z Y X] + // REVERSE(packedArgb) = [X Y Z W] + Unsafe.Add(ref dBase, i) = BinaryPrimitives.ReverseEndianness(packed); + } + } +} + +internal readonly struct YZWXShuffle4 : IShuffle4 +{ + [MethodImpl(InliningOptions.ShortMethod)] + public void ShuffleReduce(ref ReadOnlySpan source, ref Span destination) + => HwIntrinsics.Shuffle4Reduce(ref source, ref destination, SimdUtils.Shuffle.MMShuffle0321); + + [MethodImpl(InliningOptions.ShortMethod)] + public void Shuffle(ReadOnlySpan source, Span destination) + { + ref uint sBase = ref Unsafe.As(ref MemoryMarshal.GetReference(source)); + ref uint dBase = ref Unsafe.As(ref MemoryMarshal.GetReference(destination)); + uint n = (uint)source.Length / 4; + + for (nuint i = 0; i < n; i++) + { + uint packed = Unsafe.Add(ref sBase, i); + + // packed = [W Z Y X] + // ROTR(8, packedArgb) = [Y Z W X] + Unsafe.Add(ref dBase, i) = BitOperations.RotateRight(packed, 8); + } + } +} + +internal readonly struct ZYXWShuffle4 : IShuffle4 +{ + [MethodImpl(InliningOptions.ShortMethod)] + public void ShuffleReduce(ref ReadOnlySpan source, ref Span destination) + => HwIntrinsics.Shuffle4Reduce(ref source, ref destination, SimdUtils.Shuffle.MMShuffle3012); + + [MethodImpl(InliningOptions.ShortMethod)] + public void Shuffle(ReadOnlySpan source, Span destination) + { + ref uint sBase = ref Unsafe.As(ref MemoryMarshal.GetReference(source)); + ref uint dBase = ref Unsafe.As(ref MemoryMarshal.GetReference(destination)); + uint n = (uint)source.Length / 4; + + for (nuint i = 0; i < n; i++) + { + uint packed = Unsafe.Add(ref sBase, i); + + // packed = [W Z Y X] + // tmp1 = [W 0 Y 0] + // tmp2 = [0 Z 0 X] + // tmp3=ROTL(16, tmp2) = [0 X 0 Z] + // tmp1 + tmp3 = [W X Y Z] + uint tmp1 = packed & 0xFF00FF00; + uint tmp2 = packed & 0x00FF00FF; + uint tmp3 = BitOperations.RotateLeft(tmp2, 16); + + Unsafe.Add(ref dBase, i) = tmp1 + tmp3; + } + } +} + +internal readonly struct XWZYShuffle4 : IShuffle4 +{ + [MethodImpl(InliningOptions.ShortMethod)] + public void ShuffleReduce(ref ReadOnlySpan source, ref Span destination) + => HwIntrinsics.Shuffle4Reduce(ref source, ref destination, SimdUtils.Shuffle.MMShuffle1230); + + [MethodImpl(InliningOptions.ShortMethod)] + public void Shuffle(ReadOnlySpan source, Span destination) + { + ref uint sBase = ref Unsafe.As(ref MemoryMarshal.GetReference(source)); + ref uint dBase = ref Unsafe.As(ref MemoryMarshal.GetReference(destination)); + uint n = (uint)source.Length / 4; + + for (nuint i = 0; i < n; i++) + { + uint packed = Unsafe.Add(ref sBase, i); + + // packed = [W Z Y X] + // tmp1 = [0 Z 0 X] + // tmp2 = [W 0 Y 0] + // tmp3=ROTL(16, tmp2) = [Y 0 W 0] + // tmp1 + tmp3 = [Y Z W X] + uint tmp1 = packed & 0x00FF00FF; + uint tmp2 = packed & 0xFF00FF00; + uint tmp3 = BitOperations.RotateLeft(tmp2, 16); + + Unsafe.Add(ref dBase, i) = tmp1 + tmp3; + } + } +} diff --git a/src/ImageSharp/Common/Helpers/Shuffle/IShuffle4Slice3.cs b/src/ImageSharp/Common/Helpers/Shuffle/IShuffle4Slice3.cs index 5e82973e33..3e7e440664 100644 --- a/src/ImageSharp/Common/Helpers/Shuffle/IShuffle4Slice3.cs +++ b/src/ImageSharp/Common/Helpers/Shuffle/IShuffle4Slice3.cs @@ -1,6 +1,7 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. +using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using static SixLabors.ImageSharp.SimdUtils; @@ -12,26 +13,25 @@ internal interface IShuffle4Slice3 : IComponentShuffle { } -internal readonly struct DefaultShuffle4Slice3 : IShuffle4Slice3 +internal readonly struct DefaultShuffle4Slice3([ConstantExpected] byte control) : IShuffle4Slice3 { - public DefaultShuffle4Slice3(byte control) - => this.Control = control; - - public byte Control { get; } + public byte Control { get; } = control; [MethodImpl(InliningOptions.ShortMethod)] - public void ShuffleReduce(ref ReadOnlySpan source, ref Span dest) - => HwIntrinsics.Shuffle4Slice3Reduce(ref source, ref dest, this.Control); + public void ShuffleReduce(ref ReadOnlySpan source, ref Span destination) +#pragma warning disable CA1857 // A constant is expected for the parameter + => HwIntrinsics.Shuffle4Slice3Reduce(ref source, ref destination, this.Control); +#pragma warning restore CA1857 // A constant is expected for the parameter [MethodImpl(InliningOptions.ShortMethod)] - public void RunFallbackShuffle(ReadOnlySpan source, Span dest) + public void Shuffle(ReadOnlySpan source, Span destination) { ref byte sBase = ref MemoryMarshal.GetReference(source); - ref byte dBase = ref MemoryMarshal.GetReference(dest); + ref byte dBase = ref MemoryMarshal.GetReference(destination); - Shuffle.InverseMMShuffle(this.Control, out _, out uint p2, out uint p1, out uint p0); + SimdUtils.Shuffle.InverseMMShuffle(this.Control, out _, out uint p2, out uint p1, out uint p0); - for (nuint i = 0, j = 0; i < (uint)dest.Length; i += 3, j += 4) + for (nuint i = 0, j = 0; i < (uint)destination.Length; i += 3, j += 4) { Unsafe.Add(ref dBase, i + 0) = Unsafe.Add(ref sBase, p0 + j); Unsafe.Add(ref dBase, i + 1) = Unsafe.Add(ref sBase, p1 + j); @@ -43,14 +43,14 @@ public void RunFallbackShuffle(ReadOnlySpan source, Span dest) internal readonly struct XYZWShuffle4Slice3 : IShuffle4Slice3 { [MethodImpl(InliningOptions.ShortMethod)] - public void ShuffleReduce(ref ReadOnlySpan source, ref Span dest) - => HwIntrinsics.Shuffle4Slice3Reduce(ref source, ref dest, Shuffle.MMShuffle3210); + public void ShuffleReduce(ref ReadOnlySpan source, ref Span destination) + => HwIntrinsics.Shuffle4Slice3Reduce(ref source, ref destination, SimdUtils.Shuffle.MMShuffle3210); [MethodImpl(InliningOptions.ShortMethod)] - public void RunFallbackShuffle(ReadOnlySpan source, Span dest) + public void Shuffle(ReadOnlySpan source, Span destination) { ref uint sBase = ref Unsafe.As(ref MemoryMarshal.GetReference(source)); - ref Byte3 dBase = ref Unsafe.As(ref MemoryMarshal.GetReference(dest)); + ref Byte3 dBase = ref Unsafe.As(ref MemoryMarshal.GetReference(destination)); nint n = (nint)(uint)source.Length / 4; nint m = Numerics.Modulo4(n); diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.Convert.cs b/src/ImageSharp/Common/Helpers/SimdUtils.Convert.cs new file mode 100644 index 0000000000..5318ad0497 --- /dev/null +++ b/src/ImageSharp/Common/Helpers/SimdUtils.Convert.cs @@ -0,0 +1,78 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace SixLabors.ImageSharp; + +internal static partial class SimdUtils +{ + /// + /// Converts all input -s to -s normalized into [0..1]. + /// should be the of the same size as , + /// but there are no restrictions on the span's length. + /// + /// The source span of bytes + /// The destination span of floats + [MethodImpl(InliningOptions.ShortMethod)] + internal static void ByteToNormalizedFloat(ReadOnlySpan source, Span destination) + { + DebugGuard.IsTrue(source.Length == destination.Length, nameof(source), "Input spans must be of same length!"); + + HwIntrinsics.ByteToNormalizedFloatReduce(ref source, ref destination); + + if (source.Length > 0) + { + ConvertByteToNormalizedFloatRemainder(source, destination); + } + } + + /// + /// Convert all values normalized into [0..1] from 'source' into 'destination' buffer of . + /// The values are scaled up into [0-255] and rounded, overflows are clamped. + /// should be the of the same size as , + /// but there are no restrictions on the span's length. + /// + /// The source span of floats + /// The destination span of bytes + [MethodImpl(InliningOptions.ShortMethod)] + internal static void NormalizedFloatToByteSaturate(ReadOnlySpan source, Span destination) + { + DebugGuard.IsTrue(source.Length == destination.Length, nameof(source), "Input spans must be of same length!"); + + HwIntrinsics.NormalizedFloatToByteSaturateReduce(ref source, ref destination); + + if (source.Length > 0) + { + ConvertNormalizedFloatToByteRemainder(source, destination); + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static void ConvertByteToNormalizedFloatRemainder(ReadOnlySpan source, Span destination) + { + ref byte sBase = ref MemoryMarshal.GetReference(source); + ref float dBase = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < source.Length; i++) + { + Unsafe.Add(ref dBase, (uint)i) = Unsafe.Add(ref sBase, (uint)i) / 255f; + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static void ConvertNormalizedFloatToByteRemainder(ReadOnlySpan source, Span destination) + { + ref float sBase = ref MemoryMarshal.GetReference(source); + ref byte dBase = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < source.Length; i++) + { + Unsafe.Add(ref dBase, (uint)i) = ConvertToByte(Unsafe.Add(ref sBase, (uint)i)); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static byte ConvertToByte(float f) => (byte)Numerics.Clamp((f * 255f) + 0.5f, 0, 255f); +} diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs b/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs deleted file mode 100644 index ac122fc7d4..0000000000 --- a/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs +++ /dev/null @@ -1,182 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Numerics; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// ReSharper disable MemberHidesStaticFromOuterClass -namespace SixLabors.ImageSharp; - -internal static partial class SimdUtils -{ - /// - /// Implementation methods based on newer API-s (Vector.Widen, Vector.Narrow, Vector.ConvertTo*). - /// Only accelerated only on RyuJIT having dotnet/coreclr#10662 merged (.NET Core 2.1+ .NET 4.7.2+) - /// See: - /// https://github.com/dotnet/coreclr/pull/10662 - /// API Proposal: - /// https://github.com/dotnet/corefx/issues/15957 - /// - public static class ExtendedIntrinsics - { - public static bool IsAvailable { get; } = Vector.IsHardwareAccelerated; - - /// - /// Widen and convert a vector of values into 2 vectors of -s. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static void ConvertToSingle( - Vector source, - out Vector dest1, - out Vector dest2) - { - Vector.Widen(source, out Vector i1, out Vector i2); - dest1 = Vector.ConvertToSingle(i1); - dest2 = Vector.ConvertToSingle(i2); - } - - /// - /// as many elements as possible, slicing them down (keeping the remainder). - /// - [MethodImpl(InliningOptions.ShortMethod)] - internal static void ByteToNormalizedFloatReduce( - ref ReadOnlySpan source, - ref Span dest) - { - DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!"); - - if (!IsAvailable) - { - return; - } - - int remainder = Numerics.ModuloP2(source.Length, Vector.Count); - int adjustedCount = source.Length - remainder; - - if (adjustedCount > 0) - { - ByteToNormalizedFloat(source[..adjustedCount], dest[..adjustedCount]); - - source = source[adjustedCount..]; - dest = dest[adjustedCount..]; - } - } - - /// - /// as many elements as possible, slicing them down (keeping the remainder). - /// - [MethodImpl(InliningOptions.ShortMethod)] - internal static void NormalizedFloatToByteSaturateReduce( - ref ReadOnlySpan source, - ref Span dest) - { - DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!"); - - if (!IsAvailable) - { - return; - } - - int remainder = Numerics.ModuloP2(source.Length, Vector.Count); - int adjustedCount = source.Length - remainder; - - if (adjustedCount > 0) - { - NormalizedFloatToByteSaturate(source[..adjustedCount], dest[..adjustedCount]); - - source = source[adjustedCount..]; - dest = dest[adjustedCount..]; - } - } - - /// - /// Implementation , which is faster on new RyuJIT runtime. - /// - internal static void ByteToNormalizedFloat(ReadOnlySpan source, Span dest) - { - VerifySpanInput(source, dest, Vector.Count); - - nuint n = dest.VectorCount(); - - ref Vector sourceBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(source)); - ref Vector destBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(dest)); - - for (nuint i = 0; i < n; i++) - { - Vector b = Unsafe.Add(ref sourceBase, i); - - Vector.Widen(b, out Vector s0, out Vector s1); - Vector.Widen(s0, out Vector w0, out Vector w1); - Vector.Widen(s1, out Vector w2, out Vector w3); - - Vector f0 = ConvertToSingle(w0); - Vector f1 = ConvertToSingle(w1); - Vector f2 = ConvertToSingle(w2); - Vector f3 = ConvertToSingle(w3); - - ref Vector d = ref Unsafe.Add(ref destBase, i * 4); - d = f0; - Unsafe.Add(ref d, 1) = f1; - Unsafe.Add(ref d, 2) = f2; - Unsafe.Add(ref d, 3) = f3; - } - } - - /// - /// Implementation of , which is faster on new .NET runtime. - /// - internal static void NormalizedFloatToByteSaturate( - ReadOnlySpan source, - Span dest) - { - VerifySpanInput(source, dest, Vector.Count); - - nuint n = dest.VectorCount(); - - ref Vector sourceBase = - ref Unsafe.As>(ref MemoryMarshal.GetReference(source)); - ref Vector destBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(dest)); - - for (nuint i = 0; i < n; i++) - { - ref Vector s = ref Unsafe.Add(ref sourceBase, i * 4); - - Vector f0 = s; - Vector f1 = Unsafe.Add(ref s, 1); - Vector f2 = Unsafe.Add(ref s, 2); - Vector f3 = Unsafe.Add(ref s, 3); - - Vector w0 = ConvertToUInt32(f0); - Vector w1 = ConvertToUInt32(f1); - Vector w2 = ConvertToUInt32(f2); - Vector w3 = ConvertToUInt32(f3); - - var u0 = Vector.Narrow(w0, w1); - var u1 = Vector.Narrow(w2, w3); - - Unsafe.Add(ref destBase, i) = Vector.Narrow(u0, u1); - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static Vector ConvertToUInt32(Vector vf) - { - var maxBytes = new Vector(255f); - vf *= maxBytes; - vf += new Vector(0.5f); - vf = Vector.Min(Vector.Max(vf, Vector.Zero), maxBytes); - var vi = Vector.ConvertToInt32(vf); - return Vector.AsVectorUInt32(vi); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static Vector ConvertToSingle(Vector u) - { - var vi = Vector.AsVectorInt32(u); - var v = Vector.ConvertToSingle(vi); - v *= new Vector(1f / 255f); - return v; - } - } -} diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.FallbackIntrinsics128.cs b/src/ImageSharp/Common/Helpers/SimdUtils.FallbackIntrinsics128.cs deleted file mode 100644 index a551cebd05..0000000000 --- a/src/ImageSharp/Common/Helpers/SimdUtils.FallbackIntrinsics128.cs +++ /dev/null @@ -1,144 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Numerics; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// ReSharper disable MemberHidesStaticFromOuterClass -namespace SixLabors.ImageSharp; - -internal static partial class SimdUtils -{ - /// - /// Fallback implementation based on (128bit). - /// For , efficient software fallback implementations are present, - /// and we hope that even mono's JIT is able to emit SIMD instructions for that type :P - /// - public static class FallbackIntrinsics128 - { - /// - /// as many elements as possible, slicing them down (keeping the remainder). - /// - [MethodImpl(InliningOptions.ShortMethod)] - internal static void ByteToNormalizedFloatReduce( - ref ReadOnlySpan source, - ref Span dest) - { - DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!"); - - int remainder = Numerics.Modulo4(source.Length); - int adjustedCount = source.Length - remainder; - - if (adjustedCount > 0) - { - ByteToNormalizedFloat(source[..adjustedCount], dest[..adjustedCount]); - - source = source[adjustedCount..]; - dest = dest[adjustedCount..]; - } - } - - /// - /// as many elements as possible, slicing them down (keeping the remainder). - /// - [MethodImpl(InliningOptions.ShortMethod)] - internal static void NormalizedFloatToByteSaturateReduce( - ref ReadOnlySpan source, - ref Span dest) - { - DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!"); - - int remainder = Numerics.Modulo4(source.Length); - int adjustedCount = source.Length - remainder; - - if (adjustedCount > 0) - { - NormalizedFloatToByteSaturate( - source[..adjustedCount], - dest[..adjustedCount]); - - source = source[adjustedCount..]; - dest = dest[adjustedCount..]; - } - } - - /// - /// Implementation of using . - /// - [MethodImpl(InliningOptions.ColdPath)] - internal static void ByteToNormalizedFloat(ReadOnlySpan source, Span dest) - { - VerifySpanInput(source, dest, 4); - - uint count = (uint)dest.Length / 4; - if (count == 0) - { - return; - } - - ref ByteVector4 sBase = ref Unsafe.As(ref MemoryMarshal.GetReference(source)); - ref Vector4 dBase = ref Unsafe.As(ref MemoryMarshal.GetReference(dest)); - - const float scale = 1f / 255f; - Vector4 d = default; - - for (nuint i = 0; i < count; i++) - { - ref ByteVector4 s = ref Unsafe.Add(ref sBase, i); - d.X = s.X; - d.Y = s.Y; - d.Z = s.Z; - d.W = s.W; - d *= scale; - Unsafe.Add(ref dBase, i) = d; - } - } - - /// - /// Implementation of using . - /// - [MethodImpl(InliningOptions.ColdPath)] - internal static void NormalizedFloatToByteSaturate( - ReadOnlySpan source, - Span dest) - { - VerifySpanInput(source, dest, 4); - - uint count = (uint)source.Length / 4; - if (count == 0) - { - return; - } - - ref Vector4 sBase = ref Unsafe.As(ref MemoryMarshal.GetReference(source)); - ref ByteVector4 dBase = ref Unsafe.As(ref MemoryMarshal.GetReference(dest)); - - var half = new Vector4(0.5f); - var maxBytes = new Vector4(255f); - - for (nuint i = 0; i < count; i++) - { - Vector4 s = Unsafe.Add(ref sBase, i); - s *= maxBytes; - s += half; - s = Numerics.Clamp(s, Vector4.Zero, maxBytes); - - ref ByteVector4 d = ref Unsafe.Add(ref dBase, i); - d.X = (byte)s.X; - d.Y = (byte)s.Y; - d.Z = (byte)s.Z; - d.W = (byte)s.W; - } - } - - [StructLayout(LayoutKind.Sequential)] - private struct ByteVector4 - { - public byte X; - public byte Y; - public byte Z; - public byte W; - } - } -} diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.HwIntrinsics.cs b/src/ImageSharp/Common/Helpers/SimdUtils.HwIntrinsics.cs index fc58ef3440..17ccb396d6 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.HwIntrinsics.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.HwIntrinsics.cs @@ -1,12 +1,14 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. +using System.Diagnostics.CodeAnalysis; using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Intrinsics; using System.Runtime.Intrinsics.Arm; using System.Runtime.Intrinsics.X86; +using SixLabors.ImageSharp.Common.Helpers; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp; @@ -15,8 +17,13 @@ internal static partial class SimdUtils { public static class HwIntrinsics { +#pragma warning disable SA1117 // Parameters should be on same line or separate lines +#pragma warning disable SA1137 // Elements should have the same indentation [MethodImpl(MethodImplOptions.AggressiveInlining)] // too much IL for JIT to inline, so give a hint - public static Vector256 PermuteMaskDeinterleave8x32() => Vector256.Create(0, 0, 0, 0, 4, 0, 0, 0, 1, 0, 0, 0, 5, 0, 0, 0, 2, 0, 0, 0, 6, 0, 0, 0, 3, 0, 0, 0, 7, 0, 0, 0).AsInt32(); + public static Vector256 PermuteMaskDeinterleave8x32() => Vector256.Create(0, 4, 1, 5, 2, 6, 3, 7); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector512 PermuteMaskDeinterleave16x32() => Vector512.Create(0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector256 PermuteMaskEvenOdd8x32() => Vector256.Create(0, 0, 0, 0, 2, 0, 0, 0, 4, 0, 0, 0, 6, 0, 0, 0, 1, 0, 0, 0, 3, 0, 0, 0, 5, 0, 0, 0, 7, 0, 0, 0).AsUInt32(); @@ -36,36 +43,46 @@ public static class HwIntrinsics [MethodImpl(MethodImplOptions.AggressiveInlining)] private static Vector128 ShuffleMaskSlice4Nx16() => Vector128.Create(0, 1, 2, 4, 5, 6, 8, 9, 10, 12, 13, 14, 0x80, 0x80, 0x80, 0x80); -#pragma warning disable SA1003, SA1116, SA1117 // Parameters should be on same line or separate lines [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static Vector256 ShuffleMaskShiftAlpha() => Vector256.Create((byte) - 0, 1, 2, 4, 5, 6, 8, 9, 10, 12, 13, 14, 3, 7, 11, 15, - 0, 1, 2, 4, 5, 6, 8, 9, 10, 12, 13, 14, 3, 7, 11, 15); + private static Vector256 ShuffleMaskShiftAlpha() => Vector256.Create( + (byte)0, 1, 2, 4, 5, 6, 8, 9, 10, 12, 13, 14, 3, 7, 11, 15, + 0, 1, 2, 4, 5, 6, 8, 9, 10, 12, 13, 14, 3, 7, 11, 15); [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector256 PermuteMaskShiftAlpha8x32() => Vector256.Create( - 0, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 4, 0, 0, 0, - 5, 0, 0, 0, 6, 0, 0, 0, 3, 0, 0, 0, 7, 0, 0, 0).AsUInt32(); -#pragma warning restore SA1003, SA1116, SA1117 // Parameters should be on same line or separate lines + public static Vector256 PermuteMaskShiftAlpha8x32() => Vector256.Create(0u, 1, 2, 4, 5, 6, 3, 7); +#pragma warning restore SA1137 // Elements should have the same indentation +#pragma warning restore SA1117 // Parameters should be on same line or separate lines /// /// Shuffle single-precision (32-bit) floating-point elements in - /// using the control and store the results in . + /// using the control and store the results in . /// /// The source span of floats. - /// The destination span of floats. + /// The destination span of floats. /// The byte control. [MethodImpl(InliningOptions.ShortMethod)] public static void Shuffle4Reduce( ref ReadOnlySpan source, - ref Span dest, - byte control) + ref Span destination, + [ConstantExpected] byte control) { - if (Avx.IsSupported || Sse.IsSupported) + if ((Vector512.IsHardwareAccelerated && Vector512Utilities.SupportsShuffleFloat) || + (Vector256.IsHardwareAccelerated && Vector256Utilities.SupportsShuffleFloat) || + (Vector128.IsHardwareAccelerated && Vector128Utilities.SupportsShuffleFloat)) { - int remainder = Avx.IsSupported - ? Numerics.ModuloP2(source.Length, Vector256.Count) - : Numerics.ModuloP2(source.Length, Vector128.Count); + int remainder = 0; + if (Vector512.IsHardwareAccelerated) + { + remainder = Numerics.ModuloP2(source.Length, Vector512.Count); + } + else if (Vector256.IsHardwareAccelerated) + { + remainder = Numerics.ModuloP2(source.Length, Vector256.Count); + } + else if (Vector128.IsHardwareAccelerated) + { + remainder = Numerics.ModuloP2(source.Length, Vector128.Count); + } int adjustedCount = source.Length - remainder; @@ -73,33 +90,45 @@ public static void Shuffle4Reduce( { Shuffle4( source[..adjustedCount], - dest[..adjustedCount], + destination[..adjustedCount], control); source = source[adjustedCount..]; - dest = dest[adjustedCount..]; + destination = destination[adjustedCount..]; } } } /// - /// Shuffle 8-bit integers within 128-bit lanes in - /// using the control and store the results in . + /// Shuffle 8-bit integers + /// using the control and store the results in . /// /// The source span of bytes. - /// The destination span of bytes. + /// The destination span of bytes. /// The byte control. [MethodImpl(InliningOptions.ShortMethod)] public static void Shuffle4Reduce( ref ReadOnlySpan source, - ref Span dest, - byte control) + ref Span destination, + [ConstantExpected] byte control) { - if (Avx2.IsSupported || Ssse3.IsSupported) + if ((Vector512.IsHardwareAccelerated && Vector512Utilities.SupportsShuffleByte) || + (Vector256.IsHardwareAccelerated && Vector256Utilities.SupportsShuffleByte) || + (Vector128.IsHardwareAccelerated && Vector128Utilities.SupportsShuffleByte)) { - int remainder = Avx2.IsSupported - ? Numerics.ModuloP2(source.Length, Vector256.Count) - : Numerics.ModuloP2(source.Length, Vector128.Count); + int remainder = 0; + if (Vector512.IsHardwareAccelerated) + { + remainder = Numerics.ModuloP2(source.Length, Vector512.Count); + } + else if (Vector256.IsHardwareAccelerated) + { + remainder = Numerics.ModuloP2(source.Length, Vector256.Count); + } + else if (Vector128.IsHardwareAccelerated) + { + remainder = Numerics.ModuloP2(source.Length, Vector128.Count); + } int adjustedCount = source.Length - remainder; @@ -107,29 +136,29 @@ public static void Shuffle4Reduce( { Shuffle4( source[..adjustedCount], - dest[..adjustedCount], + destination[..adjustedCount], control); source = source[adjustedCount..]; - dest = dest[adjustedCount..]; + destination = destination[adjustedCount..]; } } } /// - /// Shuffles 8-bit integer triplets within 128-bit lanes in - /// using the control and store the results in . + /// Shuffles 8-bit integer triplets in + /// using the control and store the results in . /// /// The source span of bytes. - /// The destination span of bytes. + /// The destination span of bytes. /// The byte control. [MethodImpl(InliningOptions.ShortMethod)] public static void Shuffle3Reduce( ref ReadOnlySpan source, - ref Span dest, - byte control) + ref Span destination, + [ConstantExpected] byte control) { - if (Ssse3.IsSupported) + if (Vector128.IsHardwareAccelerated && Vector128Utilities.SupportsShuffleByte && Vector128Utilities.SupportsRightAlign) { int remainder = source.Length % (Vector128.Count * 3); @@ -139,77 +168,77 @@ public static void Shuffle3Reduce( { Shuffle3( source[..adjustedCount], - dest[..adjustedCount], + destination[..adjustedCount], control); source = source[adjustedCount..]; - dest = dest[adjustedCount..]; + destination = destination[adjustedCount..]; } } } /// - /// Pads then shuffles 8-bit integers within 128-bit lanes in - /// using the control and store the results in . + /// Pads then shuffles 8-bit integers in + /// using the control and store the results in . /// /// The source span of bytes. - /// The destination span of bytes. + /// The destination span of bytes. /// The byte control. [MethodImpl(InliningOptions.ShortMethod)] public static void Pad3Shuffle4Reduce( ref ReadOnlySpan source, - ref Span dest, - byte control) + ref Span destination, + [ConstantExpected] byte control) { - if (Ssse3.IsSupported) + if (Vector128.IsHardwareAccelerated && Vector128Utilities.SupportsShuffleByte && Vector128Utilities.SupportsShiftByte) { int remainder = source.Length % (Vector128.Count * 3); int sourceCount = source.Length - remainder; - int destCount = (int)((uint)sourceCount * 4 / 3); + int destinationCount = (int)((uint)sourceCount * 4 / 3); if (sourceCount > 0) { Pad3Shuffle4( source[..sourceCount], - dest[..destCount], + destination[..destinationCount], control); source = source[sourceCount..]; - dest = dest[destCount..]; + destination = destination[destinationCount..]; } } } /// - /// Shuffles then slices 8-bit integers within 128-bit lanes in - /// using the control and store the results in . + /// Shuffles then slices 8-bit integers in + /// using the control and store the results in . /// /// The source span of bytes. - /// The destination span of bytes. + /// The destination span of bytes. /// The byte control. [MethodImpl(InliningOptions.ShortMethod)] public static void Shuffle4Slice3Reduce( ref ReadOnlySpan source, - ref Span dest, - byte control) + ref Span destination, + [ConstantExpected] byte control) { - if (Ssse3.IsSupported) + if (Vector128.IsHardwareAccelerated && Vector128Utilities.SupportsShuffleByte && Vector128Utilities.SupportsShiftByte) { int remainder = source.Length & ((Vector128.Count * 4) - 1); // bit-hack for modulo int sourceCount = source.Length - remainder; - int destCount = (int)((uint)sourceCount * 3 / 4); + int destinationCount = (int)((uint)sourceCount * 3 / 4); if (sourceCount > 0) { Shuffle4Slice3( source[..sourceCount], - dest[..destCount], + destination[..destinationCount], control); source = source[sourceCount..]; - dest = dest[destCount..]; + destination = destination[destinationCount..]; } } } @@ -217,76 +246,90 @@ public static void Shuffle4Slice3Reduce( [MethodImpl(InliningOptions.ShortMethod)] private static void Shuffle4( ReadOnlySpan source, - Span dest, - byte control) + Span destination, + [ConstantExpected] byte control) { - if (Avx.IsSupported) + if (Vector512.IsHardwareAccelerated && Vector512Utilities.SupportsShuffleFloat) { - ref Vector256 sourceBase = - ref Unsafe.As>(ref MemoryMarshal.GetReference(source)); + ref Vector512 sourceBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(source)); + ref Vector512 destinationBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(destination)); - ref Vector256 destBase = - ref Unsafe.As>(ref MemoryMarshal.GetReference(dest)); + nuint n = (uint)destination.Length / (uint)Vector512.Count; + nuint m = Numerics.Modulo4(n); + nuint u = n - m; - nint n = (nint)dest.Vector256Count(); - nint m = Numerics.Modulo4(n); - nint u = n - m; - - for (nint i = 0; i < u; i += 4) + for (nuint i = 0; i < u; i += 4) { - ref Vector256 vd0 = ref Unsafe.Add(ref destBase, i); - ref Vector256 vs0 = ref Unsafe.Add(ref sourceBase, i); + ref Vector512 vs0 = ref Unsafe.Add(ref sourceBase, i); + ref Vector512 vd0 = ref Unsafe.Add(ref destinationBase, i); - vd0 = Avx.Permute(vs0, control); - Unsafe.Add(ref vd0, 1) = Avx.Permute(Unsafe.Add(ref vs0, 1), control); - Unsafe.Add(ref vd0, 2) = Avx.Permute(Unsafe.Add(ref vs0, 2), control); - Unsafe.Add(ref vd0, 3) = Avx.Permute(Unsafe.Add(ref vs0, 3), control); + vd0 = Vector512Utilities.Shuffle(vs0, control); + Unsafe.Add(ref vd0, (nuint)1) = Vector512Utilities.Shuffle(Unsafe.Add(ref vs0, (nuint)1), control); + Unsafe.Add(ref vd0, (nuint)2) = Vector512Utilities.Shuffle(Unsafe.Add(ref vs0, (nuint)2), control); + Unsafe.Add(ref vd0, (nuint)3) = Vector512Utilities.Shuffle(Unsafe.Add(ref vs0, (nuint)3), control); } if (m > 0) { - for (nint i = u; i < n; i++) + for (nuint i = u; i < n; i++) { - Unsafe.Add(ref destBase, i) = Avx.Permute(Unsafe.Add(ref sourceBase, i), control); + Unsafe.Add(ref destinationBase, i) = Vector512Utilities.Shuffle(Unsafe.Add(ref sourceBase, i), control); } } } - else + else if (Vector256.IsHardwareAccelerated && Vector256Utilities.SupportsShuffleFloat) { - // Sse - ref Vector128 sourceBase = - ref Unsafe.As>(ref MemoryMarshal.GetReference(source)); + ref Vector256 sourceBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(source)); + ref Vector256 destinationBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(destination)); - ref Vector128 destBase = - ref Unsafe.As>(ref MemoryMarshal.GetReference(dest)); + nuint n = (uint)destination.Length / (uint)Vector256.Count; + nuint m = Numerics.Modulo4(n); + nuint u = n - m; - nint n = (nint)((uint)dest.Length / (uint)Vector128.Count); - nint m = Numerics.Modulo4(n); - nint u = n - m; - - for (nint i = 0; i < u; i += 4) + for (nuint i = 0; i < u; i += 4) { - ref Vector128 vd0 = ref Unsafe.Add(ref destBase, i); - ref Vector128 vs0 = ref Unsafe.Add(ref sourceBase, i); + ref Vector256 vs0 = ref Unsafe.Add(ref sourceBase, i); + ref Vector256 vd0 = ref Unsafe.Add(ref destinationBase, i); - vd0 = Sse.Shuffle(vs0, vs0, control); + vd0 = Vector256Utilities.Shuffle(vs0, control); + Unsafe.Add(ref vd0, (nuint)1) = Vector256Utilities.Shuffle(Unsafe.Add(ref vs0, (nuint)1), control); + Unsafe.Add(ref vd0, (nuint)2) = Vector256Utilities.Shuffle(Unsafe.Add(ref vs0, (nuint)2), control); + Unsafe.Add(ref vd0, (nuint)3) = Vector256Utilities.Shuffle(Unsafe.Add(ref vs0, (nuint)3), control); + } - Vector128 vs1 = Unsafe.Add(ref vs0, 1); - Unsafe.Add(ref vd0, 1) = Sse.Shuffle(vs1, vs1, control); + if (m > 0) + { + for (nuint i = u; i < n; i++) + { + Unsafe.Add(ref destinationBase, i) = Vector256Utilities.Shuffle(Unsafe.Add(ref sourceBase, i), control); + } + } + } + else if (Vector128.IsHardwareAccelerated && Vector128Utilities.SupportsShuffleFloat) + { + ref Vector128 sourceBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(source)); + ref Vector128 destinationBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(destination)); - Vector128 vs2 = Unsafe.Add(ref vs0, 2); - Unsafe.Add(ref vd0, 2) = Sse.Shuffle(vs2, vs2, control); + nuint n = (uint)destination.Length / (uint)Vector128.Count; + nuint m = Numerics.Modulo4(n); + nuint u = n - m; - Vector128 vs3 = Unsafe.Add(ref vs0, 3); - Unsafe.Add(ref vd0, 3) = Sse.Shuffle(vs3, vs3, control); + for (nuint i = 0; i < u; i += 4) + { + ref Vector128 vs0 = ref Unsafe.Add(ref sourceBase, i); + ref Vector128 vd0 = ref Unsafe.Add(ref destinationBase, i); + + vd0 = Vector128Utilities.Shuffle(vs0, control); + Unsafe.Add(ref vd0, (nuint)1) = Vector128Utilities.Shuffle(Unsafe.Add(ref vs0, (nuint)1), control); + Unsafe.Add(ref vd0, (nuint)2) = Vector128Utilities.Shuffle(Unsafe.Add(ref vs0, (nuint)2), control); + Unsafe.Add(ref vd0, (nuint)3) = Vector128Utilities.Shuffle(Unsafe.Add(ref vs0, (nuint)3), control); } if (m > 0) { - for (nint i = u; i < n; i++) + for (nuint i = u; i < n; i++) { - Vector128 vs = Unsafe.Add(ref sourceBase, i); - Unsafe.Add(ref destBase, i) = Sse.Shuffle(vs, vs, control); + Unsafe.Add(ref destinationBase, i) = Vector128Utilities.Shuffle(Unsafe.Add(ref sourceBase, i), control); } } } @@ -295,80 +338,102 @@ private static void Shuffle4( [MethodImpl(InliningOptions.ShortMethod)] private static void Shuffle4( ReadOnlySpan source, - Span dest, - byte control) + Span destination, + [ConstantExpected] byte control) { - if (Avx2.IsSupported) + if (Vector512.IsHardwareAccelerated && Vector512Utilities.SupportsShuffleByte) { - // I've chosen to do this for convenience while we determine what - // shuffle controls to add to the library. - // We can add static ROS instances if need be in the future. - Span bytes = stackalloc byte[Vector256.Count]; - Shuffle.MMShuffleSpan(ref bytes, control); - Vector256 vshuffle = Unsafe.As>(ref MemoryMarshal.GetReference(bytes)); + Span temp = stackalloc byte[Vector512.Count]; + Shuffle.MMShuffleSpan(ref temp, control); + Vector512 mask = Unsafe.As>(ref MemoryMarshal.GetReference(temp)); + + ref Vector512 sourceBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(source)); + ref Vector512 destinationBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(destination)); - ref Vector256 sourceBase = - ref Unsafe.As>(ref MemoryMarshal.GetReference(source)); + nuint n = (uint)destination.Length / (uint)Vector512.Count; + nuint m = Numerics.Modulo4(n); + nuint u = n - m; + + for (nuint i = 0; i < u; i += 4) + { + ref Vector512 vs0 = ref Unsafe.Add(ref sourceBase, i); + ref Vector512 vd0 = ref Unsafe.Add(ref destinationBase, i); + + vd0 = Vector512Utilities.Shuffle(vs0, mask); + Unsafe.Add(ref vd0, (nuint)1) = Vector512Utilities.Shuffle(Unsafe.Add(ref vs0, (nuint)1), mask); + Unsafe.Add(ref vd0, (nuint)2) = Vector512Utilities.Shuffle(Unsafe.Add(ref vs0, (nuint)2), mask); + Unsafe.Add(ref vd0, (nuint)3) = Vector512Utilities.Shuffle(Unsafe.Add(ref vs0, (nuint)3), mask); + } + + if (m > 0) + { + for (nuint i = u; i < n; i++) + { + Unsafe.Add(ref destinationBase, i) = Vector512Utilities.Shuffle(Unsafe.Add(ref sourceBase, i), mask); + } + } + } + else if (Vector256.IsHardwareAccelerated && Vector256Utilities.SupportsShuffleByte) + { + Span temp = stackalloc byte[Vector256.Count]; + Shuffle.MMShuffleSpan(ref temp, control); + Vector256 mask = Unsafe.As>(ref MemoryMarshal.GetReference(temp)); - ref Vector256 destBase = - ref Unsafe.As>(ref MemoryMarshal.GetReference(dest)); + ref Vector256 sourceBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(source)); + ref Vector256 destinationBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(destination)); - nint n = (nint)((uint)dest.Length / (uint)Vector256.Count); - nint m = Numerics.Modulo4(n); - nint u = n - m; + nuint n = (uint)destination.Length / (uint)Vector256.Count; + nuint m = Numerics.Modulo4(n); + nuint u = n - m; - for (nint i = 0; i < u; i += 4) + for (nuint i = 0; i < u; i += 4) { ref Vector256 vs0 = ref Unsafe.Add(ref sourceBase, i); - ref Vector256 vd0 = ref Unsafe.Add(ref destBase, i); + ref Vector256 vd0 = ref Unsafe.Add(ref destinationBase, i); - vd0 = Avx2.Shuffle(vs0, vshuffle); - Unsafe.Add(ref vd0, 1) = Avx2.Shuffle(Unsafe.Add(ref vs0, 1), vshuffle); - Unsafe.Add(ref vd0, 2) = Avx2.Shuffle(Unsafe.Add(ref vs0, 2), vshuffle); - Unsafe.Add(ref vd0, 3) = Avx2.Shuffle(Unsafe.Add(ref vs0, 3), vshuffle); + vd0 = Vector256Utilities.Shuffle(vs0, mask); + Unsafe.Add(ref vd0, (nuint)1) = Vector256Utilities.Shuffle(Unsafe.Add(ref vs0, (nuint)1), mask); + Unsafe.Add(ref vd0, (nuint)2) = Vector256Utilities.Shuffle(Unsafe.Add(ref vs0, (nuint)2), mask); + Unsafe.Add(ref vd0, (nuint)3) = Vector256Utilities.Shuffle(Unsafe.Add(ref vs0, (nuint)3), mask); } if (m > 0) { - for (nint i = u; i < n; i++) + for (nuint i = u; i < n; i++) { - Unsafe.Add(ref destBase, i) = Avx2.Shuffle(Unsafe.Add(ref sourceBase, i), vshuffle); + Unsafe.Add(ref destinationBase, i) = Vector256Utilities.Shuffle(Unsafe.Add(ref sourceBase, i), mask); } } } - else + else if (Vector128.IsHardwareAccelerated && Vector128Utilities.SupportsShuffleByte) { - // Ssse3 - Span bytes = stackalloc byte[Vector128.Count]; - Shuffle.MMShuffleSpan(ref bytes, control); - Vector128 vshuffle = Unsafe.As>(ref MemoryMarshal.GetReference(bytes)); - - ref Vector128 sourceBase = - ref Unsafe.As>(ref MemoryMarshal.GetReference(source)); + Span temp = stackalloc byte[Vector128.Count]; + Shuffle.MMShuffleSpan(ref temp, control); + Vector128 mask = Unsafe.As>(ref MemoryMarshal.GetReference(temp)); - ref Vector128 destBase = - ref Unsafe.As>(ref MemoryMarshal.GetReference(dest)); + ref Vector128 sourceBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(source)); + ref Vector128 destinationBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(destination)); - nint n = (nint)((uint)dest.Length / (uint)Vector128.Count); - nint m = Numerics.Modulo4(n); - nint u = n - m; + nuint n = (uint)destination.Length / (uint)Vector128.Count; + nuint m = Numerics.Modulo4(n); + nuint u = n - m; - for (nint i = 0; i < u; i += 4) + for (nuint i = 0; i < u; i += 4) { ref Vector128 vs0 = ref Unsafe.Add(ref sourceBase, i); - ref Vector128 vd0 = ref Unsafe.Add(ref destBase, i); + ref Vector128 vd0 = ref Unsafe.Add(ref destinationBase, i); - vd0 = Ssse3.Shuffle(vs0, vshuffle); - Unsafe.Add(ref vd0, 1) = Ssse3.Shuffle(Unsafe.Add(ref vs0, 1), vshuffle); - Unsafe.Add(ref vd0, 2) = Ssse3.Shuffle(Unsafe.Add(ref vs0, 2), vshuffle); - Unsafe.Add(ref vd0, 3) = Ssse3.Shuffle(Unsafe.Add(ref vs0, 3), vshuffle); + vd0 = Vector128Utilities.Shuffle(vs0, mask); + Unsafe.Add(ref vd0, (nuint)1) = Vector128Utilities.Shuffle(Unsafe.Add(ref vs0, (nuint)1), mask); + Unsafe.Add(ref vd0, (nuint)2) = Vector128Utilities.Shuffle(Unsafe.Add(ref vs0, (nuint)2), mask); + Unsafe.Add(ref vd0, (nuint)3) = Vector128Utilities.Shuffle(Unsafe.Add(ref vs0, (nuint)3), mask); } if (m > 0) { - for (nint i = u; i < n; i++) + for (nuint i = u; i < n; i++) { - Unsafe.Add(ref destBase, i) = Ssse3.Shuffle(Unsafe.Add(ref sourceBase, i), vshuffle); + Unsafe.Add(ref destinationBase, i) = Vector128Utilities.Shuffle(Unsafe.Add(ref sourceBase, i), mask); } } } @@ -377,24 +442,21 @@ private static void Shuffle4( [MethodImpl(InliningOptions.ShortMethod)] private static void Shuffle3( ReadOnlySpan source, - Span dest, - byte control) + Span destination, + [ConstantExpected] byte control) { - if (Ssse3.IsSupported) + if (Vector128.IsHardwareAccelerated && Vector128Utilities.SupportsShuffleByte && Vector128Utilities.SupportsRightAlign) { - Vector128 vmask = ShuffleMaskPad4Nx16(); - Vector128 vmasko = ShuffleMaskSlice4Nx16(); - Vector128 vmaske = Ssse3.AlignRight(vmasko, vmasko, 12); + Vector128 maskPad4Nx16 = ShuffleMaskPad4Nx16(); + Vector128 maskSlice4Nx16 = ShuffleMaskSlice4Nx16(); + Vector128 maskE = Vector128Utilities.AlignRight(maskSlice4Nx16, maskSlice4Nx16, 12); Span bytes = stackalloc byte[Vector128.Count]; Shuffle.MMShuffleSpan(ref bytes, control); - Vector128 vshuffle = Unsafe.As>(ref MemoryMarshal.GetReference(bytes)); + Vector128 mask = Unsafe.As>(ref MemoryMarshal.GetReference(bytes)); - ref Vector128 sourceBase = - ref Unsafe.As>(ref MemoryMarshal.GetReference(source)); - - ref Vector128 destBase = - ref Unsafe.As>(ref MemoryMarshal.GetReference(dest)); + ref Vector128 sourceBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(source)); + ref Vector128 destinationBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(destination)); nuint n = source.Vector128Count(); @@ -403,36 +465,36 @@ private static void Shuffle3( ref Vector128 vs = ref Unsafe.Add(ref sourceBase, i); Vector128 v0 = vs; - Vector128 v1 = Unsafe.Add(ref vs, 1); - Vector128 v2 = Unsafe.Add(ref vs, 2); - Vector128 v3 = Sse2.ShiftRightLogical128BitLane(v2, 4); + Vector128 v1 = Unsafe.Add(ref vs, (nuint)1); + Vector128 v2 = Unsafe.Add(ref vs, (nuint)2); + Vector128 v3 = Vector128Utilities.ShiftRightBytesInVector(v2, 4); - v2 = Ssse3.AlignRight(v2, v1, 8); - v1 = Ssse3.AlignRight(v1, v0, 12); + v2 = Vector128Utilities.AlignRight(v2, v1, 8); + v1 = Vector128Utilities.AlignRight(v1, v0, 12); - v0 = Ssse3.Shuffle(Ssse3.Shuffle(v0, vmask), vshuffle); - v1 = Ssse3.Shuffle(Ssse3.Shuffle(v1, vmask), vshuffle); - v2 = Ssse3.Shuffle(Ssse3.Shuffle(v2, vmask), vshuffle); - v3 = Ssse3.Shuffle(Ssse3.Shuffle(v3, vmask), vshuffle); + v0 = Vector128Utilities.Shuffle(Vector128Utilities.Shuffle(v0, maskPad4Nx16), mask); + v1 = Vector128Utilities.Shuffle(Vector128Utilities.Shuffle(v1, maskPad4Nx16), mask); + v2 = Vector128Utilities.Shuffle(Vector128Utilities.Shuffle(v2, maskPad4Nx16), mask); + v3 = Vector128Utilities.Shuffle(Vector128Utilities.Shuffle(v3, maskPad4Nx16), mask); - v0 = Ssse3.Shuffle(v0, vmaske); - v1 = Ssse3.Shuffle(v1, vmasko); - v2 = Ssse3.Shuffle(v2, vmaske); - v3 = Ssse3.Shuffle(v3, vmasko); + v0 = Vector128Utilities.Shuffle(v0, maskE); + v1 = Vector128Utilities.Shuffle(v1, maskSlice4Nx16); + v2 = Vector128Utilities.Shuffle(v2, maskE); + v3 = Vector128Utilities.Shuffle(v3, maskSlice4Nx16); - v0 = Ssse3.AlignRight(v1, v0, 4); - v3 = Ssse3.AlignRight(v3, v2, 12); + v0 = Vector128Utilities.AlignRight(v1, v0, 4); + v3 = Vector128Utilities.AlignRight(v3, v2, 12); - v1 = Sse2.ShiftLeftLogical128BitLane(v1, 4); - v2 = Sse2.ShiftRightLogical128BitLane(v2, 4); + v1 = Vector128Utilities.ShiftLeftBytesInVector(v1, 4); + v2 = Vector128Utilities.ShiftRightBytesInVector(v2, 4); - v1 = Ssse3.AlignRight(v2, v1, 8); + v1 = Vector128Utilities.AlignRight(v2, v1, 8); - ref Vector128 vd = ref Unsafe.Add(ref destBase, i); + ref Vector128 vd = ref Unsafe.Add(ref destinationBase, i); vd = v0; - Unsafe.Add(ref vd, 1) = v1; - Unsafe.Add(ref vd, 2) = v3; + Unsafe.Add(ref vd, (nuint)1) = v1; + Unsafe.Add(ref vd, (nuint)2) = v3; } } } @@ -440,23 +502,23 @@ private static void Shuffle3( [MethodImpl(InliningOptions.ShortMethod)] private static void Pad3Shuffle4( ReadOnlySpan source, - Span dest, - byte control) + Span destination, + [ConstantExpected] byte control) { - if (Ssse3.IsSupported) + if (Vector128.IsHardwareAccelerated && Vector128Utilities.SupportsShuffleByte && Vector128Utilities.SupportsShiftByte) { - Vector128 vmask = ShuffleMaskPad4Nx16(); - Vector128 vfill = Vector128.Create(0xff000000ff000000ul).AsByte(); + Vector128 maskPad4Nx16 = ShuffleMaskPad4Nx16(); + Vector128 fill = Vector128.Create(0xff000000ff000000ul).AsByte(); - Span bytes = stackalloc byte[Vector128.Count]; - Shuffle.MMShuffleSpan(ref bytes, control); - Vector128 vshuffle = Unsafe.As>(ref MemoryMarshal.GetReference(bytes)); + Span temp = stackalloc byte[Vector128.Count]; + Shuffle.MMShuffleSpan(ref temp, control); + Vector128 mask = Unsafe.As>(ref MemoryMarshal.GetReference(temp)); ref Vector128 sourceBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(source)); - ref Vector128 destBase = - ref Unsafe.As>(ref MemoryMarshal.GetReference(dest)); + ref Vector128 destinationBase = + ref Unsafe.As>(ref MemoryMarshal.GetReference(destination)); nuint n = source.Vector128Count(); @@ -465,17 +527,17 @@ private static void Pad3Shuffle4( ref Vector128 v0 = ref Unsafe.Add(ref sourceBase, i); Vector128 v1 = Unsafe.Add(ref v0, 1); Vector128 v2 = Unsafe.Add(ref v0, 2); - Vector128 v3 = Sse2.ShiftRightLogical128BitLane(v2, 4); + Vector128 v3 = Vector128Utilities.ShiftRightBytesInVector(v2, 4); - v2 = Ssse3.AlignRight(v2, v1, 8); - v1 = Ssse3.AlignRight(v1, v0, 12); + v2 = Vector128Utilities.AlignRight(v2, v1, 8); + v1 = Vector128Utilities.AlignRight(v1, v0, 12); - ref Vector128 vd = ref Unsafe.Add(ref destBase, j); + ref Vector128 vd = ref Unsafe.Add(ref destinationBase, j); - vd = Ssse3.Shuffle(Sse2.Or(Ssse3.Shuffle(v0, vmask), vfill), vshuffle); - Unsafe.Add(ref vd, 1) = Ssse3.Shuffle(Sse2.Or(Ssse3.Shuffle(v1, vmask), vfill), vshuffle); - Unsafe.Add(ref vd, 2) = Ssse3.Shuffle(Sse2.Or(Ssse3.Shuffle(v2, vmask), vfill), vshuffle); - Unsafe.Add(ref vd, 3) = Ssse3.Shuffle(Sse2.Or(Ssse3.Shuffle(v3, vmask), vfill), vshuffle); + vd = Vector128Utilities.Shuffle(Vector128Utilities.Shuffle(v0, maskPad4Nx16) | fill, mask); + Unsafe.Add(ref vd, 1) = Vector128Utilities.Shuffle(Vector128Utilities.Shuffle(v1, maskPad4Nx16) | fill, mask); + Unsafe.Add(ref vd, 2) = Vector128Utilities.Shuffle(Vector128Utilities.Shuffle(v2, maskPad4Nx16) | fill, mask); + Unsafe.Add(ref vd, 3) = Vector128Utilities.Shuffle(Vector128Utilities.Shuffle(v3, maskPad4Nx16) | fill, mask); } } } @@ -483,23 +545,23 @@ private static void Pad3Shuffle4( [MethodImpl(InliningOptions.ShortMethod)] private static void Shuffle4Slice3( ReadOnlySpan source, - Span dest, - byte control) + Span destination, + [ConstantExpected] byte control) { - if (Ssse3.IsSupported) + if (Vector128.IsHardwareAccelerated && Vector128Utilities.SupportsShuffleByte && Vector128Utilities.SupportsShiftByte) { - Vector128 vmasko = ShuffleMaskSlice4Nx16(); - Vector128 vmaske = Ssse3.AlignRight(vmasko, vmasko, 12); + Vector128 maskSlice4Nx16 = ShuffleMaskSlice4Nx16(); + Vector128 maskE = Vector128Utilities.AlignRight(maskSlice4Nx16, maskSlice4Nx16, 12); - Span bytes = stackalloc byte[Vector128.Count]; - Shuffle.MMShuffleSpan(ref bytes, control); - Vector128 vshuffle = Unsafe.As>(ref MemoryMarshal.GetReference(bytes)); + Span temp = stackalloc byte[Vector128.Count]; + Shuffle.MMShuffleSpan(ref temp, control); + Vector128 mask = Unsafe.As>(ref MemoryMarshal.GetReference(temp)); ref Vector128 sourceBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(source)); - ref Vector128 destBase = - ref Unsafe.As>(ref MemoryMarshal.GetReference(dest)); + ref Vector128 destinationBase = + ref Unsafe.As>(ref MemoryMarshal.GetReference(destination)); nuint n = source.Vector128Count(); @@ -512,20 +574,20 @@ private static void Shuffle4Slice3( Vector128 v2 = Unsafe.Add(ref vs, 2); Vector128 v3 = Unsafe.Add(ref vs, 3); - v0 = Ssse3.Shuffle(Ssse3.Shuffle(v0, vshuffle), vmaske); - v1 = Ssse3.Shuffle(Ssse3.Shuffle(v1, vshuffle), vmasko); - v2 = Ssse3.Shuffle(Ssse3.Shuffle(v2, vshuffle), vmaske); - v3 = Ssse3.Shuffle(Ssse3.Shuffle(v3, vshuffle), vmasko); + v0 = Vector128Utilities.Shuffle(Vector128Utilities.Shuffle(v0, mask), maskE); + v1 = Vector128Utilities.Shuffle(Vector128Utilities.Shuffle(v1, mask), maskSlice4Nx16); + v2 = Vector128Utilities.Shuffle(Vector128Utilities.Shuffle(v2, mask), maskE); + v3 = Vector128Utilities.Shuffle(Vector128Utilities.Shuffle(v3, mask), maskSlice4Nx16); - v0 = Ssse3.AlignRight(v1, v0, 4); - v3 = Ssse3.AlignRight(v3, v2, 12); + v0 = Vector128Utilities.AlignRight(v1, v0, 4); + v3 = Vector128Utilities.AlignRight(v3, v2, 12); - v1 = Sse2.ShiftLeftLogical128BitLane(v1, 4); - v2 = Sse2.ShiftRightLogical128BitLane(v2, 4); + v1 = Vector128Utilities.ShiftLeftBytesInVector(v1, 4); + v2 = Vector128Utilities.ShiftRightBytesInVector(v2, 4); - v1 = Ssse3.AlignRight(v2, v1, 8); + v1 = Vector128Utilities.AlignRight(v2, v1, 8); - ref Vector128 vd = ref Unsafe.Add(ref destBase, j); + ref Vector128 vd = ref Unsafe.Add(ref destinationBase, j); vd = v0; Unsafe.Add(ref vd, 1) = v1; @@ -690,17 +752,23 @@ public static ushort TrailingZeroCount(ushort value) /// /// as many elements as possible, slicing them down (keeping the remainder). /// + /// The source buffer. + /// The destination buffer. [MethodImpl(InliningOptions.ShortMethod)] internal static void ByteToNormalizedFloatReduce( ref ReadOnlySpan source, - ref Span dest) + ref Span destination) { - DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!"); + DebugGuard.IsTrue(source.Length == destination.Length, nameof(source), "Input spans must be of same length!"); - if (Avx2.IsSupported || Sse2.IsSupported) + if (Vector128.IsHardwareAccelerated) { int remainder; - if (Avx2.IsSupported) + if (Vector512.IsHardwareAccelerated && Avx512F.IsSupported) + { + remainder = Numerics.ModuloP2(source.Length, Vector512.Count); + } + else if (Avx2.IsSupported) { remainder = Numerics.ModuloP2(source.Length, Vector256.Count); } @@ -713,10 +781,10 @@ internal static void ByteToNormalizedFloatReduce( if (adjustedCount > 0) { - ByteToNormalizedFloat(source[..adjustedCount], dest[..adjustedCount]); + ByteToNormalizedFloat(source[..adjustedCount], destination[..adjustedCount]); source = source[adjustedCount..]; - dest = dest[adjustedCount..]; + destination = destination[adjustedCount..]; } } } @@ -724,97 +792,126 @@ internal static void ByteToNormalizedFloatReduce( /// /// Implementation , which is faster on new RyuJIT runtime. /// + /// The source buffer. + /// The destination buffer. /// /// Implementation is based on MagicScaler code: /// https://github.com/saucecontrol/PhotoSauce/blob/b5811908041200488aa18fdfd17df5fc457415dc/src/MagicScaler/Magic/Processors/ConvertersFloat.cs#L80-L182 /// internal static unsafe void ByteToNormalizedFloat( ReadOnlySpan source, - Span dest) + Span destination) { - fixed (byte* sourceBase = source) + if (Vector512.IsHardwareAccelerated && Avx512F.IsSupported) { - if (Avx2.IsSupported) - { - VerifySpanInput(source, dest, Vector256.Count); - - nuint n = dest.Vector256Count(); + DebugVerifySpanInput(source, destination, Vector512.Count); - ref Vector256 destBase = - ref Unsafe.As>(ref MemoryMarshal.GetReference(dest)); + nuint n = destination.Vector512Count(); - Vector256 scale = Vector256.Create(1 / (float)byte.MaxValue); + ref byte sourceBase = ref MemoryMarshal.GetReference(source); + ref Vector512 destinationBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(destination)); - for (nuint i = 0; i < n; i++) - { - nuint si = (uint)Vector256.Count * i; - Vector256 i0 = Avx2.ConvertToVector256Int32(sourceBase + si); - Vector256 i1 = Avx2.ConvertToVector256Int32(sourceBase + si + Vector256.Count); - Vector256 i2 = Avx2.ConvertToVector256Int32(sourceBase + si + (Vector256.Count * 2)); - Vector256 i3 = Avx2.ConvertToVector256Int32(sourceBase + si + (Vector256.Count * 3)); - - Vector256 f0 = Avx.Multiply(scale, Avx.ConvertToVector256Single(i0)); - Vector256 f1 = Avx.Multiply(scale, Avx.ConvertToVector256Single(i1)); - Vector256 f2 = Avx.Multiply(scale, Avx.ConvertToVector256Single(i2)); - Vector256 f3 = Avx.Multiply(scale, Avx.ConvertToVector256Single(i3)); - - ref Vector256 d = ref Unsafe.Add(ref destBase, i * 4); - - d = f0; - Unsafe.Add(ref d, 1) = f1; - Unsafe.Add(ref d, 2) = f2; - Unsafe.Add(ref d, 3) = f3; - } + for (nuint i = 0; i < n; i++) + { + nuint si = (uint)Vector512.Count * i; + Vector512 i0 = Avx512F.ConvertToVector512Int32(Vector128.LoadUnsafe(ref sourceBase, si)); + Vector512 i1 = Avx512F.ConvertToVector512Int32(Vector128.LoadUnsafe(ref sourceBase, si + (nuint)Vector512.Count)); + Vector512 i2 = Avx512F.ConvertToVector512Int32(Vector128.LoadUnsafe(ref sourceBase, si + (nuint)(Vector512.Count * 2))); + Vector512 i3 = Avx512F.ConvertToVector512Int32(Vector128.LoadUnsafe(ref sourceBase, si + (nuint)(Vector512.Count * 3))); + + // Declare multiplier on each line. Codegen is better. + Vector512 f0 = Vector512.Create(1 / (float)byte.MaxValue) * Avx512F.ConvertToVector512Single(i0); + Vector512 f1 = Vector512.Create(1 / (float)byte.MaxValue) * Avx512F.ConvertToVector512Single(i1); + Vector512 f2 = Vector512.Create(1 / (float)byte.MaxValue) * Avx512F.ConvertToVector512Single(i2); + Vector512 f3 = Vector512.Create(1 / (float)byte.MaxValue) * Avx512F.ConvertToVector512Single(i3); + + ref Vector512 d = ref Unsafe.Add(ref destinationBase, i * 4); + + d = f0; + Unsafe.Add(ref d, 1) = f1; + Unsafe.Add(ref d, 2) = f2; + Unsafe.Add(ref d, 3) = f3; } - else + } + else if (Avx2.IsSupported) + { + DebugVerifySpanInput(source, destination, Vector256.Count); + + nuint n = destination.Vector256Count(); + + ref byte sourceBase = ref MemoryMarshal.GetReference(source); + ref Vector256 destinationBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(destination)); + + for (nuint i = 0; i < n; i++) { - // Sse - VerifySpanInput(source, dest, Vector128.Count); + nuint si = (uint)Vector256.Count * i; + Vector256 i0 = Avx2.ConvertToVector256Int32(Vector128.LoadUnsafe(ref sourceBase, si)); + Vector256 i1 = Avx2.ConvertToVector256Int32(Vector128.LoadUnsafe(ref sourceBase, si + (nuint)Vector256.Count)); + Vector256 i2 = Avx2.ConvertToVector256Int32(Vector128.LoadUnsafe(ref sourceBase, si + (nuint)(Vector256.Count * 2))); + + // Ensure overreads past 16 byte boundary do not happen in debug due to lack of containment. + ref ulong refULong = ref Unsafe.As(ref Unsafe.Add(ref sourceBase, si)); + Vector256 i3 = Avx2.ConvertToVector256Int32(Vector128.CreateScalarUnsafe(Unsafe.Add(ref refULong, 3)).AsByte()); + + // Declare multiplier on each line. Codegen is better. + Vector256 f0 = Vector256.Create(1 / (float)byte.MaxValue) * Avx.ConvertToVector256Single(i0); + Vector256 f1 = Vector256.Create(1 / (float)byte.MaxValue) * Avx.ConvertToVector256Single(i1); + Vector256 f2 = Vector256.Create(1 / (float)byte.MaxValue) * Avx.ConvertToVector256Single(i2); + Vector256 f3 = Vector256.Create(1 / (float)byte.MaxValue) * Avx.ConvertToVector256Single(i3); + + ref Vector256 d = ref Unsafe.Add(ref destinationBase, i * 4); + + d = f0; + Unsafe.Add(ref d, 1) = f1; + Unsafe.Add(ref d, 2) = f2; + Unsafe.Add(ref d, 3) = f3; + } + } + else if (Vector128.IsHardwareAccelerated) + { + DebugVerifySpanInput(source, destination, Vector128.Count); + + nuint n = destination.Vector128Count(); - nuint n = dest.Vector128Count(); + ref byte sourceBase = ref MemoryMarshal.GetReference(source); + ref Vector128 destinationBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(destination)); - ref Vector128 destBase = - ref Unsafe.As>(ref MemoryMarshal.GetReference(dest)); + Vector128 scale = Vector128.Create(1 / (float)byte.MaxValue); - Vector128 scale = Vector128.Create(1 / (float)byte.MaxValue); - Vector128 zero = Vector128.Zero; + for (nuint i = 0; i < n; i++) + { + nuint si = (uint)Vector128.Count * i; - for (nuint i = 0; i < n; i++) + Vector128 i0, i1, i2, i3; + if (Sse41.IsSupported) + { + ref int refInt = ref Unsafe.As(ref Unsafe.Add(ref sourceBase, si)); + + i0 = Sse41.ConvertToVector128Int32(Vector128.CreateScalarUnsafe(refInt).AsByte()); + i1 = Sse41.ConvertToVector128Int32(Vector128.CreateScalarUnsafe(Unsafe.Add(ref refInt, 1)).AsByte()); + i2 = Sse41.ConvertToVector128Int32(Vector128.CreateScalarUnsafe(Unsafe.Add(ref refInt, 2)).AsByte()); + i3 = Sse41.ConvertToVector128Int32(Vector128.CreateScalarUnsafe(Unsafe.Add(ref refInt, 3)).AsByte()); + } + else { - nuint si = (uint)Vector128.Count * i; - - Vector128 i0, i1, i2, i3; - if (Sse41.IsSupported) - { - i0 = Sse41.ConvertToVector128Int32(sourceBase + si); - i1 = Sse41.ConvertToVector128Int32(sourceBase + si + Vector128.Count); - i2 = Sse41.ConvertToVector128Int32(sourceBase + si + (Vector128.Count * 2)); - i3 = Sse41.ConvertToVector128Int32(sourceBase + si + (Vector128.Count * 3)); - } - else - { - Vector128 b = Sse2.LoadVector128(sourceBase + si); - Vector128 s0 = Sse2.UnpackLow(b, zero).AsInt16(); - Vector128 s1 = Sse2.UnpackHigh(b, zero).AsInt16(); - - i0 = Sse2.UnpackLow(s0, zero.AsInt16()).AsInt32(); - i1 = Sse2.UnpackHigh(s0, zero.AsInt16()).AsInt32(); - i2 = Sse2.UnpackLow(s1, zero.AsInt16()).AsInt32(); - i3 = Sse2.UnpackHigh(s1, zero.AsInt16()).AsInt32(); - } - - Vector128 f0 = Sse.Multiply(scale, Sse2.ConvertToVector128Single(i0)); - Vector128 f1 = Sse.Multiply(scale, Sse2.ConvertToVector128Single(i1)); - Vector128 f2 = Sse.Multiply(scale, Sse2.ConvertToVector128Single(i2)); - Vector128 f3 = Sse.Multiply(scale, Sse2.ConvertToVector128Single(i3)); - - ref Vector128 d = ref Unsafe.Add(ref destBase, i * 4); - - d = f0; - Unsafe.Add(ref d, 1) = f1; - Unsafe.Add(ref d, 2) = f2; - Unsafe.Add(ref d, 3) = f3; + // Sse2, AdvSimd, etc + Vector128 b = Vector128.LoadUnsafe(ref sourceBase, si); + (Vector128 s0, Vector128 s1) = Vector128.Widen(b); + (i0, i1) = Vector128.Widen(s0.AsInt16()); + (i2, i3) = Vector128.Widen(s1.AsInt16()); } + + Vector128 f0 = scale * Vector128.ConvertToSingle(i0); + Vector128 f1 = scale * Vector128.ConvertToSingle(i1); + Vector128 f2 = scale * Vector128.ConvertToSingle(i2); + Vector128 f3 = scale * Vector128.ConvertToSingle(i3); + + ref Vector128 d = ref Unsafe.Add(ref destinationBase, i * 4); + + d = f0; + Unsafe.Add(ref d, 1) = f1; + Unsafe.Add(ref d, 2) = f2; + Unsafe.Add(ref d, 3) = f3; } } } @@ -822,17 +919,24 @@ internal static unsafe void ByteToNormalizedFloat( /// /// as many elements as possible, slicing them down (keeping the remainder). /// + /// The source buffer. + /// The destination buffer. [MethodImpl(InliningOptions.ShortMethod)] internal static void NormalizedFloatToByteSaturateReduce( ref ReadOnlySpan source, - ref Span dest) + ref Span destination) { - DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!"); + DebugGuard.IsTrue(source.Length == destination.Length, nameof(source), "Input spans must be of same length!"); - if (Avx2.IsSupported || Sse2.IsSupported) + if (Sse2.IsSupported || AdvSimd.IsSupported) { int remainder; - if (Avx2.IsSupported) + + if (Vector512.IsHardwareAccelerated && Avx512BW.IsSupported) + { + remainder = Numerics.ModuloP2(source.Length, Vector512.Count); + } + else if (Avx2.IsSupported) { remainder = Numerics.ModuloP2(source.Length, Vector256.Count); } @@ -847,10 +951,10 @@ internal static void NormalizedFloatToByteSaturateReduce( { NormalizedFloatToByteSaturate( source[..adjustedCount], - dest[..adjustedCount]); + destination[..adjustedCount]); source = source[adjustedCount..]; - dest = dest[adjustedCount..]; + destination = destination[adjustedCount..]; } } } @@ -858,25 +962,58 @@ internal static void NormalizedFloatToByteSaturateReduce( /// /// Implementation of , which is faster on new .NET runtime. /// + /// The source buffer. + /// The destination buffer. /// /// Implementation is based on MagicScaler code: /// https://github.com/saucecontrol/PhotoSauce/blob/b5811908041200488aa18fdfd17df5fc457415dc/src/MagicScaler/Magic/Processors/ConvertersFloat.cs#L541-L622 /// internal static void NormalizedFloatToByteSaturate( ReadOnlySpan source, - Span dest) + Span destination) { - if (Avx2.IsSupported) + if (Vector512.IsHardwareAccelerated && Avx512BW.IsSupported) { - VerifySpanInput(source, dest, Vector256.Count); + DebugVerifySpanInput(source, destination, Vector512.Count); - nuint n = dest.Vector256Count(); + nuint n = destination.Vector512Count(); - ref Vector256 sourceBase = - ref Unsafe.As>(ref MemoryMarshal.GetReference(source)); + ref Vector512 sourceBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(source)); + ref Vector512 destinationBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(destination)); - ref Vector256 destBase = - ref Unsafe.As>(ref MemoryMarshal.GetReference(dest)); + Vector512 scale = Vector512.Create((float)byte.MaxValue); + Vector512 mask = PermuteMaskDeinterleave16x32(); + + for (nuint i = 0; i < n; i++) + { + ref Vector512 s = ref Unsafe.Add(ref sourceBase, i * 4); + + Vector512 f0 = scale * s; + Vector512 f1 = scale * Unsafe.Add(ref s, 1); + Vector512 f2 = scale * Unsafe.Add(ref s, 2); + Vector512 f3 = scale * Unsafe.Add(ref s, 3); + + Vector512 w0 = Vector512Utilities.ConvertToInt32RoundToEven(f0); + Vector512 w1 = Vector512Utilities.ConvertToInt32RoundToEven(f1); + Vector512 w2 = Vector512Utilities.ConvertToInt32RoundToEven(f2); + Vector512 w3 = Vector512Utilities.ConvertToInt32RoundToEven(f3); + + Vector512 u0 = Avx512BW.PackSignedSaturate(w0, w1); + Vector512 u1 = Avx512BW.PackSignedSaturate(w2, w3); + Vector512 b = Avx512BW.PackUnsignedSaturate(u0, u1); + b = Avx512F.PermuteVar16x32(b.AsInt32(), mask).AsByte(); + + Unsafe.Add(ref destinationBase, i) = b; + } + } + else if (Avx2.IsSupported) + { + DebugVerifySpanInput(source, destination, Vector256.Count); + + nuint n = destination.Vector256Count(); + + ref Vector256 sourceBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(source)); + ref Vector256 destinationBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(destination)); Vector256 scale = Vector256.Create((float)byte.MaxValue); Vector256 mask = PermuteMaskDeinterleave8x32(); @@ -885,36 +1022,33 @@ internal static void NormalizedFloatToByteSaturate( { ref Vector256 s = ref Unsafe.Add(ref sourceBase, i * 4); - Vector256 f0 = Avx.Multiply(scale, s); - Vector256 f1 = Avx.Multiply(scale, Unsafe.Add(ref s, 1)); - Vector256 f2 = Avx.Multiply(scale, Unsafe.Add(ref s, 2)); - Vector256 f3 = Avx.Multiply(scale, Unsafe.Add(ref s, 3)); + Vector256 f0 = scale * s; + Vector256 f1 = scale * Unsafe.Add(ref s, 1); + Vector256 f2 = scale * Unsafe.Add(ref s, 2); + Vector256 f3 = scale * Unsafe.Add(ref s, 3); - Vector256 w0 = Avx.ConvertToVector256Int32(f0); - Vector256 w1 = Avx.ConvertToVector256Int32(f1); - Vector256 w2 = Avx.ConvertToVector256Int32(f2); - Vector256 w3 = Avx.ConvertToVector256Int32(f3); + Vector256 w0 = Vector256Utilities.ConvertToInt32RoundToEven(f0); + Vector256 w1 = Vector256Utilities.ConvertToInt32RoundToEven(f1); + Vector256 w2 = Vector256Utilities.ConvertToInt32RoundToEven(f2); + Vector256 w3 = Vector256Utilities.ConvertToInt32RoundToEven(f3); Vector256 u0 = Avx2.PackSignedSaturate(w0, w1); Vector256 u1 = Avx2.PackSignedSaturate(w2, w3); Vector256 b = Avx2.PackUnsignedSaturate(u0, u1); b = Avx2.PermuteVar8x32(b.AsInt32(), mask).AsByte(); - Unsafe.Add(ref destBase, i) = b; + Unsafe.Add(ref destinationBase, i) = b; } } - else + else if (Sse2.IsSupported || AdvSimd.IsSupported) { - // Sse - VerifySpanInput(source, dest, Vector128.Count); - - nuint n = dest.Vector128Count(); + // Sse, AdvSimd + DebugVerifySpanInput(source, destination, Vector128.Count); - ref Vector128 sourceBase = - ref Unsafe.As>(ref MemoryMarshal.GetReference(source)); + nuint n = destination.Vector128Count(); - ref Vector128 destBase = - ref Unsafe.As>(ref MemoryMarshal.GetReference(dest)); + ref Vector128 sourceBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(source)); + ref Vector128 destinationBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(destination)); Vector128 scale = Vector128.Create((float)byte.MaxValue); @@ -922,20 +1056,20 @@ internal static void NormalizedFloatToByteSaturate( { ref Vector128 s = ref Unsafe.Add(ref sourceBase, i * 4); - Vector128 f0 = Sse.Multiply(scale, s); - Vector128 f1 = Sse.Multiply(scale, Unsafe.Add(ref s, 1)); - Vector128 f2 = Sse.Multiply(scale, Unsafe.Add(ref s, 2)); - Vector128 f3 = Sse.Multiply(scale, Unsafe.Add(ref s, 3)); + Vector128 f0 = scale * s; + Vector128 f1 = scale * Unsafe.Add(ref s, 1); + Vector128 f2 = scale * Unsafe.Add(ref s, 2); + Vector128 f3 = scale * Unsafe.Add(ref s, 3); - Vector128 w0 = Sse2.ConvertToVector128Int32(f0); - Vector128 w1 = Sse2.ConvertToVector128Int32(f1); - Vector128 w2 = Sse2.ConvertToVector128Int32(f2); - Vector128 w3 = Sse2.ConvertToVector128Int32(f3); + Vector128 w0 = Vector128Utilities.ConvertToInt32RoundToEven(f0); + Vector128 w1 = Vector128Utilities.ConvertToInt32RoundToEven(f1); + Vector128 w2 = Vector128Utilities.ConvertToInt32RoundToEven(f2); + Vector128 w3 = Vector128Utilities.ConvertToInt32RoundToEven(f3); - Vector128 u0 = Sse2.PackSignedSaturate(w0, w1); - Vector128 u1 = Sse2.PackSignedSaturate(w2, w3); + Vector128 u0 = Vector128Utilities.PackSignedSaturate(w0, w1); + Vector128 u1 = Vector128Utilities.PackSignedSaturate(w2, w3); - Unsafe.Add(ref destBase, i) = Sse2.PackUnsignedSaturate(u0, u1); + Unsafe.Add(ref destinationBase, i) = Vector128Utilities.PackUnsignedSaturate(u0, u1); } } } diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.Shuffle.cs b/src/ImageSharp/Common/Helpers/SimdUtils.Shuffle.cs index c1437c05e6..dbeb54a80c 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.Shuffle.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.Shuffle.cs @@ -2,6 +2,7 @@ // Licensed under the Six Labors Split License. using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -11,140 +12,140 @@ internal static partial class SimdUtils { /// /// Shuffle single-precision (32-bit) floating-point elements in - /// using the control and store the results in . + /// using the control and store the results in . /// /// The source span of floats. - /// The destination span of floats. + /// The destination span of floats. /// The byte control. [MethodImpl(InliningOptions.ShortMethod)] public static void Shuffle4( ReadOnlySpan source, - Span dest, - byte control) + Span destination, + [ConstantExpected] byte control) { - VerifyShuffle4SpanInput(source, dest); + VerifyShuffle4SpanInput(source, destination); - HwIntrinsics.Shuffle4Reduce(ref source, ref dest, control); + HwIntrinsics.Shuffle4Reduce(ref source, ref destination, control); // Deal with the remainder: if (source.Length > 0) { - Shuffle4Remainder(source, dest, control); + Shuffle4Remainder(source, destination, control); } } /// /// Shuffle 8-bit integers within 128-bit lanes in - /// using the control and store the results in . + /// using the control and store the results in . /// /// The type of shuffle struct. /// The source span of bytes. - /// The destination span of bytes. + /// The destination span of bytes. /// The type of shuffle to perform. [MethodImpl(InliningOptions.ShortMethod)] public static void Shuffle4( ReadOnlySpan source, - Span dest, + Span destination, TShuffle shuffle) where TShuffle : struct, IShuffle4 { - VerifyShuffle4SpanInput(source, dest); + VerifyShuffle4SpanInput(source, destination); - shuffle.ShuffleReduce(ref source, ref dest); + shuffle.ShuffleReduce(ref source, ref destination); // Deal with the remainder: if (source.Length > 0) { - shuffle.RunFallbackShuffle(source, dest); + shuffle.Shuffle(source, destination); } } /// /// Shuffle 8-bit integer triplets within 128-bit lanes in - /// using the control and store the results in . + /// using the control and store the results in . /// /// The type of shuffle struct. /// The source span of bytes. - /// The destination span of bytes. + /// The destination span of bytes. /// The type of shuffle to perform. [MethodImpl(InliningOptions.ShortMethod)] public static void Shuffle3( ReadOnlySpan source, - Span dest, + Span destination, TShuffle shuffle) where TShuffle : struct, IShuffle3 { - // Source length should be smaller than dest length, and divisible by 3. - VerifyShuffle3SpanInput(source, dest); + // Source length should be smaller than destination length, and divisible by 3. + VerifyShuffle3SpanInput(source, destination); - shuffle.ShuffleReduce(ref source, ref dest); + shuffle.ShuffleReduce(ref source, ref destination); // Deal with the remainder: if (source.Length > 0) { - shuffle.RunFallbackShuffle(source, dest); + shuffle.Shuffle(source, destination); } } /// /// Pads then shuffles 8-bit integers within 128-bit lanes in - /// using the control and store the results in . + /// using the control and store the results in . /// /// The type of shuffle struct. /// The source span of bytes. - /// The destination span of bytes. + /// The destination span of bytes. /// The type of shuffle to perform. [MethodImpl(InliningOptions.ShortMethod)] public static void Pad3Shuffle4( ReadOnlySpan source, - Span dest, + Span destination, TShuffle shuffle) where TShuffle : struct, IPad3Shuffle4 { - VerifyPad3Shuffle4SpanInput(source, dest); + VerifyPad3Shuffle4SpanInput(source, destination); - shuffle.ShuffleReduce(ref source, ref dest); + shuffle.ShuffleReduce(ref source, ref destination); // Deal with the remainder: if (source.Length > 0) { - shuffle.RunFallbackShuffle(source, dest); + shuffle.Shuffle(source, destination); } } /// /// Shuffles then slices 8-bit integers within 128-bit lanes in - /// using the control and store the results in . + /// using the control and store the results in . /// /// The type of shuffle struct. /// The source span of bytes. - /// The destination span of bytes. + /// The destination span of bytes. /// The type of shuffle to perform. [MethodImpl(InliningOptions.ShortMethod)] public static void Shuffle4Slice3( ReadOnlySpan source, - Span dest, + Span destination, TShuffle shuffle) where TShuffle : struct, IShuffle4Slice3 { - VerifyShuffle4Slice3SpanInput(source, dest); + VerifyShuffle4Slice3SpanInput(source, destination); - shuffle.ShuffleReduce(ref source, ref dest); + shuffle.ShuffleReduce(ref source, ref destination); // Deal with the remainder: if (source.Length > 0) { - shuffle.RunFallbackShuffle(source, dest); + shuffle.Shuffle(source, destination); } } private static void Shuffle4Remainder( ReadOnlySpan source, - Span dest, + Span destination, byte control) { ref float sBase = ref MemoryMarshal.GetReference(source); - ref float dBase = ref MemoryMarshal.GetReference(dest); + ref float dBase = ref MemoryMarshal.GetReference(destination); Shuffle.InverseMMShuffle(control, out uint p3, out uint p2, out uint p1, out uint p0); for (nuint i = 0; i < (uint)source.Length; i += 4) @@ -157,69 +158,69 @@ private static void Shuffle4Remainder( } [Conditional("DEBUG")] - internal static void VerifyShuffle4SpanInput(ReadOnlySpan source, Span dest) + internal static void VerifyShuffle4SpanInput(ReadOnlySpan source, Span destination) where T : struct { DebugGuard.IsTrue( - source.Length == dest.Length, + source.Length == destination.Length, nameof(source), "Input spans must be of same length!"); DebugGuard.IsTrue( source.Length % 4 == 0, nameof(source), - "Input spans must be divisable by 4!"); + "Input spans must be divisible by 4!"); } [Conditional("DEBUG")] - private static void VerifyShuffle3SpanInput(ReadOnlySpan source, Span dest) + private static void VerifyShuffle3SpanInput(ReadOnlySpan source, Span destination) where T : struct { DebugGuard.IsTrue( - source.Length <= dest.Length, + source.Length <= destination.Length, nameof(source), - "Source should fit into dest!"); + "Source should fit into destination!"); DebugGuard.IsTrue( source.Length % 3 == 0, nameof(source), - "Input spans must be divisable by 3!"); + "Input spans must be divisible by 3!"); } [Conditional("DEBUG")] - private static void VerifyPad3Shuffle4SpanInput(ReadOnlySpan source, Span dest) + private static void VerifyPad3Shuffle4SpanInput(ReadOnlySpan source, Span destination) { DebugGuard.IsTrue( source.Length % 3 == 0, nameof(source), - "Input span must be divisable by 3!"); + "Input span must be divisible by 3!"); DebugGuard.IsTrue( - dest.Length % 4 == 0, - nameof(dest), - "Output span must be divisable by 4!"); + destination.Length % 4 == 0, + nameof(destination), + "Output span must be divisible by 4!"); DebugGuard.IsTrue( - source.Length == dest.Length * 3 / 4, + source.Length == destination.Length * 3 / 4, nameof(source), "Input span must be 3/4 the length of the output span!"); } [Conditional("DEBUG")] - private static void VerifyShuffle4Slice3SpanInput(ReadOnlySpan source, Span dest) + private static void VerifyShuffle4Slice3SpanInput(ReadOnlySpan source, Span destination) { DebugGuard.IsTrue( source.Length % 4 == 0, nameof(source), - "Input span must be divisable by 4!"); + "Input span must be divisible by 4!"); DebugGuard.IsTrue( - dest.Length % 3 == 0, - nameof(dest), - "Output span must be divisable by 3!"); + destination.Length % 3 == 0, + nameof(destination), + "Output span must be divisible by 3!"); DebugGuard.IsTrue( - dest.Length >= source.Length * 3 / 4, + destination.Length >= source.Length * 3 / 4, nameof(source), "Output span must be at least 3/4 the length of the input span!"); } @@ -508,6 +509,27 @@ public static void MMShuffleSpan(ref Span span, byte control) } } + [MethodImpl(InliningOptions.ShortMethod)] + public static void MMShuffleSpan(ref Span span, byte control) + { + InverseMMShuffle( + control, + out uint p3, + out uint p2, + out uint p1, + out uint p0); + + ref int spanBase = ref MemoryMarshal.GetReference(span); + + for (nuint i = 0; i < (uint)span.Length; i += 4) + { + Unsafe.Add(ref spanBase, i + 0) = (int)(p0 + i); + Unsafe.Add(ref spanBase, i + 1) = (int)(p1 + i); + Unsafe.Add(ref spanBase, i + 2) = (int)(p2 + i); + Unsafe.Add(ref spanBase, i + 3) = (int)(p3 + i); + } + } + [MethodImpl(InliningOptions.ShortMethod)] public static void InverseMMShuffle( byte control, diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.cs b/src/ImageSharp/Common/Helpers/SimdUtils.cs index 497e3cc6a0..0279e57cc6 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.cs @@ -22,13 +22,6 @@ internal static partial class SimdUtils public static bool HasVector8 { get; } = Vector.IsHardwareAccelerated && Vector.Count == 8 && Vector.Count == 8; - /// - /// Gets a value indicating whether code is being JIT-ed to SSE instructions - /// where float and integer registers are of size 128 byte. - /// - public static bool HasVector4 { get; } = - Vector.IsHardwareAccelerated && Vector.Count == 4; - /// /// Transform all scalars in 'v' in a way that converting them to would have rounding semantics. /// @@ -69,111 +62,8 @@ internal static Vector FastRound(this Vector v) } } - /// - /// Converts all input -s to -s normalized into [0..1]. - /// should be the of the same size as , - /// but there are no restrictions on the span's length. - /// - /// The source span of bytes - /// The destination span of floats - [MethodImpl(InliningOptions.ShortMethod)] - internal static void ByteToNormalizedFloat(ReadOnlySpan source, Span dest) - { - DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!"); - - HwIntrinsics.ByteToNormalizedFloatReduce(ref source, ref dest); - - // Also deals with the remainder from previous conversions: - FallbackIntrinsics128.ByteToNormalizedFloatReduce(ref source, ref dest); - - // Deal with the remainder: - if (source.Length > 0) - { - ConvertByteToNormalizedFloatRemainder(source, dest); - } - } - - /// - /// Convert all values normalized into [0..1] from 'source' into 'dest' buffer of . - /// The values are scaled up into [0-255] and rounded, overflows are clamped. - /// should be the of the same size as , - /// but there are no restrictions on the span's length. - /// - /// The source span of floats - /// The destination span of bytes - [MethodImpl(InliningOptions.ShortMethod)] - internal static void NormalizedFloatToByteSaturate(ReadOnlySpan source, Span dest) - { - DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!"); - - HwIntrinsics.NormalizedFloatToByteSaturateReduce(ref source, ref dest); - - // Also deals with the remainder from previous conversions: - FallbackIntrinsics128.NormalizedFloatToByteSaturateReduce(ref source, ref dest); - - // Deal with the remainder: - if (source.Length > 0) - { - ConvertNormalizedFloatToByteRemainder(source, dest); - } - } - - [MethodImpl(InliningOptions.ColdPath)] - private static void ConvertByteToNormalizedFloatRemainder(ReadOnlySpan source, Span dest) - { - ref byte sBase = ref MemoryMarshal.GetReference(source); - ref float dBase = ref MemoryMarshal.GetReference(dest); - - // There are at most 3 elements at this point, having a for loop is overkill. - // Let's minimize the no. of instructions! - switch (source.Length) - { - case 3: - Unsafe.Add(ref dBase, 2) = Unsafe.Add(ref sBase, 2) / 255f; - goto case 2; - case 2: - Unsafe.Add(ref dBase, 1) = Unsafe.Add(ref sBase, 1) / 255f; - goto case 1; - case 1: - dBase = sBase / 255f; - break; - } - } - - [MethodImpl(InliningOptions.ColdPath)] - private static void ConvertNormalizedFloatToByteRemainder(ReadOnlySpan source, Span dest) - { - ref float sBase = ref MemoryMarshal.GetReference(source); - ref byte dBase = ref MemoryMarshal.GetReference(dest); - - switch (source.Length) - { - case 3: - Unsafe.Add(ref dBase, 2) = ConvertToByte(Unsafe.Add(ref sBase, 2)); - goto case 2; - case 2: - Unsafe.Add(ref dBase, 1) = ConvertToByte(Unsafe.Add(ref sBase, 1)); - goto case 1; - case 1: - dBase = ConvertToByte(sBase); - break; - } - } - - [MethodImpl(InliningOptions.ShortMethod)] - private static byte ConvertToByte(float f) => (byte)Numerics.Clamp((f * 255F) + 0.5F, 0, 255F); - [Conditional("DEBUG")] - private static void VerifyHasVector8(string operation) - { - if (!HasVector8) - { - throw new NotSupportedException($"{operation} is supported only on AVX2 CPU!"); - } - } - - [Conditional("DEBUG")] - private static void VerifySpanInput(ReadOnlySpan source, Span dest, int shouldBeDivisibleBy) + private static void DebugVerifySpanInput(ReadOnlySpan source, Span dest, int shouldBeDivisibleBy) { DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!"); DebugGuard.IsTrue( @@ -183,11 +73,11 @@ private static void VerifySpanInput(ReadOnlySpan source, Span dest, } [Conditional("DEBUG")] - private static void VerifySpanInput(ReadOnlySpan source, Span dest, int shouldBeDivisibleBy) + private static void DebugVerifySpanInput(ReadOnlySpan source, Span destination, int shouldBeDivisibleBy) { - DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!"); + DebugGuard.IsTrue(source.Length == destination.Length, nameof(source), "Input spans must be of same length!"); DebugGuard.IsTrue( - Numerics.ModuloP2(dest.Length, shouldBeDivisibleBy) == 0, + Numerics.ModuloP2(destination.Length, shouldBeDivisibleBy) == 0, nameof(source), $"length should be divisible by {shouldBeDivisibleBy}!"); } diff --git a/src/ImageSharp/Common/Helpers/Vector128Utilities.cs b/src/ImageSharp/Common/Helpers/Vector128Utilities.cs new file mode 100644 index 0000000000..b6dd319f06 --- /dev/null +++ b/src/ImageSharp/Common/Helpers/Vector128Utilities.cs @@ -0,0 +1,250 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; +using System.Runtime.Intrinsics.X86; + +namespace SixLabors.ImageSharp.Common.Helpers; + +/// +/// Defines utility methods for that have either: +/// +/// Not yet been normalized in the runtime. +/// Produce codegen that is poorly optimized by the runtime. +/// +/// Should only be used if the intrinsics are available. +/// +internal static class Vector128Utilities +{ + /// + /// Gets a value indicating whether shuffle operations are supported. + /// + public static bool SupportsShuffleFloat + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => Sse.IsSupported; + } + + /// + /// Gets a value indicating whether shuffle operations are supported. + /// + public static bool SupportsShuffleByte + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => Ssse3.IsSupported || AdvSimd.Arm64.IsSupported; + } + + /// + /// Gets a value indicating whether right align operations are supported. + /// + public static bool SupportsRightAlign + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => Ssse3.IsSupported || AdvSimd.IsSupported; + } + + /// + /// Gets a value indicating whether right or left byte shift operations are supported. + /// + public static bool SupportsShiftByte + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => Sse2.IsSupported || AdvSimd.IsSupported; + } + + /// + /// Creates a new vector by selecting values from an input vector using the control. + /// + /// The input vector from which values are selected. + /// The shuffle control byte. + /// The . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector128 Shuffle(Vector128 vector, [ConstantExpected] byte control) + { + if (Sse.IsSupported) + { + return Sse.Shuffle(vector, vector, control); + } + + ThrowUnreachableException(); + return default; + } + + /// + /// Creates a new vector by selecting values from an input vector using a set of indices. + /// + /// + /// The input vector from which values are selected. + /// + /// The per-element indices used to select a value from . + /// + /// + /// A new vector containing the values from selected by the given . + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector128 Shuffle(Vector128 vector, Vector128 indices) + { + if (Ssse3.IsSupported) + { + return Ssse3.Shuffle(vector, indices); + } + + if (AdvSimd.Arm64.IsSupported) + { + return AdvSimd.Arm64.VectorTableLookup(vector, indices); + } + + ThrowUnreachableException(); + return default; + } + + /// + /// Shifts a 128-bit value right by a specified number of bytes while shifting in zeros. + /// + /// The value to shift. + /// The number of bytes to shift by. + /// The . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector128 ShiftRightBytesInVector(Vector128 value, [ConstantExpected(Max = (byte)15)] byte numBytes) + { + if (Sse2.IsSupported) + { + return Sse2.ShiftRightLogical128BitLane(value, numBytes); + } + + if (AdvSimd.IsSupported) + { + return AdvSimd.ExtractVector128(value, Vector128.Zero, numBytes); + } + + ThrowUnreachableException(); + return default; + } + + /// + /// Shifts a 128-bit value left by a specified number of bytes while shifting in zeros. + /// + /// The value to shift. + /// The number of bytes to shift by. + /// The . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector128 ShiftLeftBytesInVector(Vector128 value, [ConstantExpected(Max = (byte)15)] byte numBytes) + { + if (Sse2.IsSupported) + { + return Sse2.ShiftLeftLogical128BitLane(value, numBytes); + } + + if (AdvSimd.IsSupported) + { +#pragma warning disable CA1857 // A constant is expected for the parameter + return AdvSimd.ExtractVector128(Vector128.Zero, value, (byte)(Vector128.Count - numBytes)); +#pragma warning restore CA1857 // A constant is expected for the parameter + } + + ThrowUnreachableException(); + return default; + } + + /// + /// Right aligns elements of two source 128-bit values depending on bits in a mask. + /// + /// The left hand source vector. + /// The right hand source vector. + /// An 8-bit mask used for the operation. + /// The . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector128 AlignRight(Vector128 left, Vector128 right, [ConstantExpected(Max = (byte)15)] byte mask) + { + if (Ssse3.IsSupported) + { + return Ssse3.AlignRight(left, right, mask); + } + + if (AdvSimd.IsSupported) + { + return AdvSimd.ExtractVector128(right, left, mask); + } + + ThrowUnreachableException(); + return default; + } + + /// + /// Performs a conversion from a 128-bit vector of 4 single-precision floating-point values to a 128-bit vector of 4 signed 32-bit integer values. + /// Rounding is equivalent to . + /// + /// The value to convert. + /// The . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector128 ConvertToInt32RoundToEven(Vector128 vector) + { + if (Sse2.IsSupported) + { + return Sse2.ConvertToVector128Int32(vector); + } + + if (AdvSimd.IsSupported) + { + return AdvSimd.ConvertToInt32RoundToEven(vector); + } + + Vector128 sign = vector & Vector128.Create(-0.0f); + Vector128 val_2p23_f32 = sign | Vector128.Create(8388608.0f); + + val_2p23_f32 = (vector + val_2p23_f32) - val_2p23_f32; + return Vector128.ConvertToInt32(val_2p23_f32 | sign); + } + + /// + /// Packs signed 16-bit integers to unsigned 8-bit integers and saturates. + /// + /// The left hand source vector. + /// The right hand source vector. + /// The . + public static Vector128 PackUnsignedSaturate(Vector128 left, Vector128 right) + { + if (Sse2.IsSupported) + { + return Sse2.PackUnsignedSaturate(left, right); + } + + if (AdvSimd.IsSupported) + { + return AdvSimd.ExtractNarrowingSaturateUnsignedUpper(AdvSimd.ExtractNarrowingSaturateUnsignedLower(left), right); + } + + ThrowUnreachableException(); + return default; + } + + /// + /// Packs signed 32-bit integers to signed 16-bit integers and saturates. + /// + /// The left hand source vector. + /// The right hand source vector. + /// The . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector128 PackSignedSaturate(Vector128 left, Vector128 right) + { + if (Sse2.IsSupported) + { + return Sse2.PackSignedSaturate(left, right); + } + + if (AdvSimd.IsSupported) + { + return AdvSimd.ExtractNarrowingSaturateUpper(AdvSimd.ExtractNarrowingSaturateLower(left), right); + } + + ThrowUnreachableException(); + return default; + } + + [DoesNotReturn] + private static void ThrowUnreachableException() => throw new UnreachableException(); +} diff --git a/src/ImageSharp/Common/Helpers/Vector256Utilities.cs b/src/ImageSharp/Common/Helpers/Vector256Utilities.cs new file mode 100644 index 0000000000..6e8c0d1de4 --- /dev/null +++ b/src/ImageSharp/Common/Helpers/Vector256Utilities.cs @@ -0,0 +1,115 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; + +namespace SixLabors.ImageSharp.Common.Helpers; + +/// +/// Defines utility methods for that have either: +/// +/// Not yet been normalized in the runtime. +/// Produce codegen that is poorly optimized by the runtime. +/// +/// Should only be used if the intrinsics are available. +/// +internal static class Vector256Utilities +{ + /// + /// Gets a value indicating whether shuffle byte operations are supported. + /// + public static bool SupportsShuffleFloat + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => Avx.IsSupported || Sse.IsSupported; + } + + /// + /// Gets a value indicating whether shuffle byte operations are supported. + /// + public static bool SupportsShuffleByte + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => Avx2.IsSupported; + } + + /// + /// Creates a new vector by selecting values from an input vector using a set of indices. + /// + /// The input vector from which values are selected. + /// The shuffle control byte. + /// The . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector256 Shuffle(Vector256 vector, [ConstantExpected] byte control) + { + if (Avx.IsSupported) + { + return Avx.Shuffle(vector, vector, control); + } + + if (Sse.IsSupported) + { + Vector128 lower = vector.GetLower(); + Vector128 upper = vector.GetUpper(); + return Vector256.Create(Sse.Shuffle(lower, lower, control), Sse.Shuffle(upper, upper, control)); + } + + ThrowUnreachableException(); + return default; + } + + /// + /// Creates a new vector by selecting values from an input vector using a set of indices. + /// + /// The input vector from which values are selected. + /// + /// The per-element indices used to select a value from . + /// + /// The . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector256 Shuffle(Vector256 vector, Vector256 indices) + { + if (Avx2.IsSupported) + { + return Avx2.Shuffle(vector, indices); + } + + ThrowUnreachableException(); + return default; + } + + /// + /// Performs a conversion from a 256-bit vector of 8 single-precision floating-point values to a 256-bit vector of 8 signed 32-bit integer values. + /// Rounding is equivalent to . + /// + /// The value to convert. + /// The . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector256 ConvertToInt32RoundToEven(Vector256 vector) + { + if (Avx.IsSupported) + { + return Avx.ConvertToVector256Int32(vector); + } + + if (Sse2.IsSupported) + { + Vector128 lower = Sse2.ConvertToVector128Int32(vector.GetLower()); + Vector128 upper = Sse2.ConvertToVector128Int32(vector.GetUpper()); + return Vector256.Create(lower, upper); + } + + Vector256 sign = vector & Vector256.Create(-0.0f); + Vector256 val_2p23_f32 = sign | Vector256.Create(8388608.0f); + + val_2p23_f32 = (vector + val_2p23_f32) - val_2p23_f32; + return Vector256.ConvertToInt32(val_2p23_f32 | sign); + } + + [DoesNotReturn] + private static void ThrowUnreachableException() => throw new UnreachableException(); +} diff --git a/src/ImageSharp/Common/Helpers/Vector512Utilities.cs b/src/ImageSharp/Common/Helpers/Vector512Utilities.cs new file mode 100644 index 0000000000..0165af90ef --- /dev/null +++ b/src/ImageSharp/Common/Helpers/Vector512Utilities.cs @@ -0,0 +1,115 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; + +namespace SixLabors.ImageSharp.Common.Helpers; + +/// +/// Defines utility methods for that have either: +/// +/// Not yet been normalized in the runtime. +/// Produce codegen that is poorly optimized by the runtime. +/// +/// Should only be used if the intrinsics are available. +/// +internal static class Vector512Utilities +{ + /// + /// Gets a value indicating whether shuffle float operations are supported. + /// + public static bool SupportsShuffleFloat + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => Avx512F.IsSupported || Avx.IsSupported; + } + + /// + /// Gets a value indicating whether shuffle byte operations are supported. + /// + public static bool SupportsShuffleByte + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => Avx512BW.IsSupported; + } + + /// + /// Creates a new vector by selecting values from an input vector using the control. + /// + /// The input vector from which values are selected. + /// The shuffle control byte. + /// The . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector512 Shuffle(Vector512 vector, [ConstantExpected] byte control) + { + if (Avx512F.IsSupported) + { + return Avx512F.Shuffle(vector, vector, control); + } + + if (Avx.IsSupported) + { + Vector256 lower = vector.GetLower(); + Vector256 upper = vector.GetUpper(); + return Vector512.Create(Avx.Shuffle(lower, lower, control), Avx.Shuffle(upper, upper, control)); + } + + ThrowUnreachableException(); + return default; + } + + /// + /// Creates a new vector by selecting values from an input vector using a set of indices. + /// + /// The input vector from which values are selected. + /// + /// The per-element indices used to select a value from . + /// + /// The . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector512 Shuffle(Vector512 vector, Vector512 indices) + { + if (Avx512BW.IsSupported) + { + return Avx512BW.Shuffle(vector, indices); + } + + ThrowUnreachableException(); + return default; + } + + /// + /// Performs a conversion from a 512-bit vector of 16 single-precision floating-point values to a 512-bit vector of 16 signed 32-bit integer values. + /// Rounding is equivalent to . + /// + /// The value to convert. + /// The . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector512 ConvertToInt32RoundToEven(Vector512 vector) + { + if (Avx512F.IsSupported) + { + return Avx512F.ConvertToVector512Int32(vector); + } + + if (Avx.IsSupported) + { + Vector256 lower = Avx.ConvertToVector256Int32(vector.GetLower()); + Vector256 upper = Avx.ConvertToVector256Int32(vector.GetUpper()); + return Vector512.Create(lower, upper); + } + + Vector512 sign = vector & Vector512.Create(-0.0f); + Vector512 val_2p23_f32 = sign | Vector512.Create(8388608.0f); + + val_2p23_f32 = (vector + val_2p23_f32) - val_2p23_f32; + return Vector512.ConvertToInt32(val_2p23_f32 | sign); + } + + [DoesNotReturn] + private static void ThrowUnreachableException() => throw new UnreachableException(); +} diff --git a/src/ImageSharp/Compression/Zlib/Crc32.Lut.cs b/src/ImageSharp/Compression/Zlib/Crc32.Lut.cs deleted file mode 100644 index 9145ac4a4e..0000000000 --- a/src/ImageSharp/Compression/Zlib/Crc32.Lut.cs +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -namespace SixLabors.ImageSharp.Compression.Zlib; - -/// -/// Contains precalulated tables for scalar calculations. -/// -internal static partial class Crc32 -{ - /// - /// The table of all possible eight bit values for fast scalar lookup. - /// - private static readonly uint[] CrcTable = - { - 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, - 0x706AF48F, 0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, - 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, - 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, - 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, - 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, - 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, - 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, - 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, - 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC, 0x51DE003A, - 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, - 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, - 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190, - 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, - 0x9FBFE4A5, 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E, - 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, - 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, - 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, - 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, - 0xFBD44C65, 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, - 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, - 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, - 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA, 0xBE0B1010, - 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, - 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, - 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, - 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, - 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, - 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, 0xF00F9344, - 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, - 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, - 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, - 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, - 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C, - 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, - 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, - 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, - 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, - 0x2CD99E8B, 0x5BDEAE1D, 0x9B64C2B0, 0xEC63F226, 0x756AA39C, - 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, - 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, - 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, - 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, - 0x18B74777, 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, - 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278, - 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, - 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, - 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, - 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, - 0xCDD70693, 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, - 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, - 0x2D02EF8D - }; -} diff --git a/src/ImageSharp/Compression/Zlib/Crc32.cs b/src/ImageSharp/Compression/Zlib/Crc32.cs deleted file mode 100644 index 2d0a09bd4c..0000000000 --- a/src/ImageSharp/Compression/Zlib/Crc32.cs +++ /dev/null @@ -1,308 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using System.Runtime.Intrinsics; -using System.Runtime.Intrinsics.X86; -using ArmCrc32 = System.Runtime.Intrinsics.Arm.Crc32; - -namespace SixLabors.ImageSharp.Compression.Zlib; - -/// -/// Calculates the 32 bit Cyclic Redundancy Check (CRC) checksum of a given buffer -/// according to the IEEE 802.3 specification. -/// -internal static partial class Crc32 -{ - /// - /// The default initial seed value of a Crc32 checksum calculation. - /// - public const uint SeedValue = 0U; - - private const int MinBufferSize = 64; - private const int ChunksizeMask = 15; - - // Definitions of the bit-reflected domain constants k1, k2, k3, etc and - // the CRC32+Barrett polynomials given at the end of the paper. - private static readonly ulong[] K05Poly = - { - 0x0154442bd4, 0x01c6e41596, // k1, k2 - 0x01751997d0, 0x00ccaa009e, // k3, k4 - 0x0163cd6124, 0x0000000000, // k5, k0 - 0x01db710641, 0x01f7011641 // polynomial - }; - - /// - /// Calculates the CRC checksum with the bytes taken from the span. - /// - /// The readonly span of bytes. - /// The . - [MethodImpl(InliningOptions.ShortMethod)] - public static uint Calculate(ReadOnlySpan buffer) - => Calculate(SeedValue, buffer); - - /// - /// Calculates the CRC checksum with the bytes taken from the span and seed. - /// - /// The input CRC value. - /// The readonly span of bytes. - /// The . - [MethodImpl(InliningOptions.ShortMethod)] - public static uint Calculate(uint crc, ReadOnlySpan buffer) - { - if (buffer.IsEmpty) - { - return crc; - } - - if (Sse41.IsSupported && Pclmulqdq.IsSupported && buffer.Length >= MinBufferSize) - { - return ~CalculateSse(~crc, buffer); - } - - if (ArmCrc32.Arm64.IsSupported) - { - return ~CalculateArm64(~crc, buffer); - } - - if (ArmCrc32.IsSupported) - { - return ~CalculateArm(~crc, buffer); - } - - return ~CalculateScalar(~crc, buffer); - } - - // Based on https://github.com/chromium/chromium/blob/master/third_party/zlib/crc32_simd.c - [MethodImpl(InliningOptions.HotPath | InliningOptions.ShortMethod)] - private static unsafe uint CalculateSse(uint crc, ReadOnlySpan buffer) - { - int chunksize = buffer.Length & ~ChunksizeMask; - int length = chunksize; - - fixed (byte* bufferPtr = buffer) - { - fixed (ulong* k05PolyPtr = K05Poly) - { - byte* localBufferPtr = bufferPtr; - ulong* localK05PolyPtr = k05PolyPtr; - - // There's at least one block of 64. - Vector128 x1 = Sse2.LoadVector128((ulong*)(localBufferPtr + 0x00)); - Vector128 x2 = Sse2.LoadVector128((ulong*)(localBufferPtr + 0x10)); - Vector128 x3 = Sse2.LoadVector128((ulong*)(localBufferPtr + 0x20)); - Vector128 x4 = Sse2.LoadVector128((ulong*)(localBufferPtr + 0x30)); - Vector128 x5; - - x1 = Sse2.Xor(x1, Sse2.ConvertScalarToVector128UInt32(crc).AsUInt64()); - - // k1, k2 - Vector128 x0 = Sse2.LoadVector128(localK05PolyPtr + 0x0); - - localBufferPtr += 64; - length -= 64; - - // Parallel fold blocks of 64, if any. - while (length >= 64) - { - x5 = Pclmulqdq.CarrylessMultiply(x1, x0, 0x00); - Vector128 x6 = Pclmulqdq.CarrylessMultiply(x2, x0, 0x00); - Vector128 x7 = Pclmulqdq.CarrylessMultiply(x3, x0, 0x00); - Vector128 x8 = Pclmulqdq.CarrylessMultiply(x4, x0, 0x00); - - x1 = Pclmulqdq.CarrylessMultiply(x1, x0, 0x11); - x2 = Pclmulqdq.CarrylessMultiply(x2, x0, 0x11); - x3 = Pclmulqdq.CarrylessMultiply(x3, x0, 0x11); - x4 = Pclmulqdq.CarrylessMultiply(x4, x0, 0x11); - - Vector128 y5 = Sse2.LoadVector128((ulong*)(localBufferPtr + 0x00)); - Vector128 y6 = Sse2.LoadVector128((ulong*)(localBufferPtr + 0x10)); - Vector128 y7 = Sse2.LoadVector128((ulong*)(localBufferPtr + 0x20)); - Vector128 y8 = Sse2.LoadVector128((ulong*)(localBufferPtr + 0x30)); - - x1 = Sse2.Xor(x1, x5); - x2 = Sse2.Xor(x2, x6); - x3 = Sse2.Xor(x3, x7); - x4 = Sse2.Xor(x4, x8); - - x1 = Sse2.Xor(x1, y5); - x2 = Sse2.Xor(x2, y6); - x3 = Sse2.Xor(x3, y7); - x4 = Sse2.Xor(x4, y8); - - localBufferPtr += 64; - length -= 64; - } - - // Fold into 128-bits. - // k3, k4 - x0 = Sse2.LoadVector128(k05PolyPtr + 0x2); - - x5 = Pclmulqdq.CarrylessMultiply(x1, x0, 0x00); - x1 = Pclmulqdq.CarrylessMultiply(x1, x0, 0x11); - x1 = Sse2.Xor(x1, x2); - x1 = Sse2.Xor(x1, x5); - - x5 = Pclmulqdq.CarrylessMultiply(x1, x0, 0x00); - x1 = Pclmulqdq.CarrylessMultiply(x1, x0, 0x11); - x1 = Sse2.Xor(x1, x3); - x1 = Sse2.Xor(x1, x5); - - x5 = Pclmulqdq.CarrylessMultiply(x1, x0, 0x00); - x1 = Pclmulqdq.CarrylessMultiply(x1, x0, 0x11); - x1 = Sse2.Xor(x1, x4); - x1 = Sse2.Xor(x1, x5); - - // Single fold blocks of 16, if any. - while (length >= 16) - { - x2 = Sse2.LoadVector128((ulong*)localBufferPtr); - - x5 = Pclmulqdq.CarrylessMultiply(x1, x0, 0x00); - x1 = Pclmulqdq.CarrylessMultiply(x1, x0, 0x11); - x1 = Sse2.Xor(x1, x2); - x1 = Sse2.Xor(x1, x5); - - localBufferPtr += 16; - length -= 16; - } - - // Fold 128 - bits to 64 - bits. - x2 = Pclmulqdq.CarrylessMultiply(x1, x0, 0x10); - x3 = Vector128.Create(~0, 0, ~0, 0).AsUInt64(); // _mm_setr_epi32 on x86 - x1 = Sse2.ShiftRightLogical128BitLane(x1, 8); - x1 = Sse2.Xor(x1, x2); - - // k5, k0 - x0 = Sse2.LoadScalarVector128(localK05PolyPtr + 0x4); - - x2 = Sse2.ShiftRightLogical128BitLane(x1, 4); - x1 = Sse2.And(x1, x3); - x1 = Pclmulqdq.CarrylessMultiply(x1, x0, 0x00); - x1 = Sse2.Xor(x1, x2); - - // Barret reduce to 32-bits. - // polynomial - x0 = Sse2.LoadVector128(localK05PolyPtr + 0x6); - - x2 = Sse2.And(x1, x3); - x2 = Pclmulqdq.CarrylessMultiply(x2, x0, 0x10); - x2 = Sse2.And(x2, x3); - x2 = Pclmulqdq.CarrylessMultiply(x2, x0, 0x00); - x1 = Sse2.Xor(x1, x2); - - crc = (uint)Sse41.Extract(x1.AsInt32(), 1); - return buffer.Length - chunksize == 0 ? crc : CalculateScalar(crc, buffer[chunksize..]); - } - } - } - - [MethodImpl(InliningOptions.HotPath | InliningOptions.ShortMethod)] - private static unsafe uint CalculateArm(uint crc, ReadOnlySpan buffer) - { - fixed (byte* bufferPtr = buffer) - { - byte* localBufferPtr = bufferPtr; - int len = buffer.Length; - - while (len > 0 && ((ulong)localBufferPtr & 3) != 0) - { - crc = ArmCrc32.ComputeCrc32(crc, *localBufferPtr++); - len--; - } - - uint* intBufferPtr = (uint*)localBufferPtr; - - while (len >= 8 * sizeof(uint)) - { - crc = ArmCrc32.ComputeCrc32(crc, *intBufferPtr++); - crc = ArmCrc32.ComputeCrc32(crc, *intBufferPtr++); - crc = ArmCrc32.ComputeCrc32(crc, *intBufferPtr++); - crc = ArmCrc32.ComputeCrc32(crc, *intBufferPtr++); - crc = ArmCrc32.ComputeCrc32(crc, *intBufferPtr++); - crc = ArmCrc32.ComputeCrc32(crc, *intBufferPtr++); - crc = ArmCrc32.ComputeCrc32(crc, *intBufferPtr++); - crc = ArmCrc32.ComputeCrc32(crc, *intBufferPtr++); - len -= 8 * sizeof(uint); - } - - while (len >= sizeof(uint)) - { - crc = ArmCrc32.ComputeCrc32(crc, *intBufferPtr++); - len -= sizeof(uint); - } - - localBufferPtr = (byte*)intBufferPtr; - - while (len > 0) - { - crc = ArmCrc32.ComputeCrc32(crc, *localBufferPtr++); - len--; - } - - return crc; - } - } - - [MethodImpl(InliningOptions.HotPath | InliningOptions.ShortMethod)] - private static unsafe uint CalculateArm64(uint crc, ReadOnlySpan buffer) - { - fixed (byte* bufferPtr = buffer) - { - byte* localBufferPtr = bufferPtr; - int len = buffer.Length; - - while (len > 0 && ((ulong)localBufferPtr & 7) != 0) - { - crc = ArmCrc32.ComputeCrc32(crc, *localBufferPtr++); - len--; - } - - ulong* longBufferPtr = (ulong*)localBufferPtr; - - while (len >= 8 * sizeof(ulong)) - { - crc = ArmCrc32.Arm64.ComputeCrc32(crc, *longBufferPtr++); - crc = ArmCrc32.Arm64.ComputeCrc32(crc, *longBufferPtr++); - crc = ArmCrc32.Arm64.ComputeCrc32(crc, *longBufferPtr++); - crc = ArmCrc32.Arm64.ComputeCrc32(crc, *longBufferPtr++); - crc = ArmCrc32.Arm64.ComputeCrc32(crc, *longBufferPtr++); - crc = ArmCrc32.Arm64.ComputeCrc32(crc, *longBufferPtr++); - crc = ArmCrc32.Arm64.ComputeCrc32(crc, *longBufferPtr++); - crc = ArmCrc32.Arm64.ComputeCrc32(crc, *longBufferPtr++); - len -= 8 * sizeof(ulong); - } - - while (len >= sizeof(ulong)) - { - crc = ArmCrc32.Arm64.ComputeCrc32(crc, *longBufferPtr++); - len -= sizeof(ulong); - } - - localBufferPtr = (byte*)longBufferPtr; - - while (len > 0) - { - crc = ArmCrc32.ComputeCrc32(crc, *localBufferPtr++); - len--; - } - - return crc; - } - } - - [MethodImpl(InliningOptions.HotPath | InliningOptions.ShortMethod)] - private static uint CalculateScalar(uint crc, ReadOnlySpan buffer) - { - ref uint crcTableRef = ref MemoryMarshal.GetReference(CrcTable.AsSpan()); - ref byte bufferRef = ref MemoryMarshal.GetReference(buffer); - - for (int i = 0; i < buffer.Length; i++) - { - crc = Unsafe.Add(ref crcTableRef, (crc ^ Unsafe.Add(ref bufferRef, i)) & 0xFF) ^ (crc >> 8); - } - - return crc; - } -} diff --git a/src/ImageSharp/Compression/Zlib/fast-crc-computation-generic-polynomials-pclmulqdq-paper.pdf b/src/ImageSharp/Compression/Zlib/fast-crc-computation-generic-polynomials-pclmulqdq-paper.pdf deleted file mode 100644 index d0eca86b33..0000000000 Binary files a/src/ImageSharp/Compression/Zlib/fast-crc-computation-generic-polynomials-pclmulqdq-paper.pdf and /dev/null differ diff --git a/src/ImageSharp/Configuration.cs b/src/ImageSharp/Configuration.cs index 39fcef9c40..1d9f3bb85d 100644 --- a/src/ImageSharp/Configuration.cs +++ b/src/ImageSharp/Configuration.cs @@ -4,7 +4,9 @@ using System.Collections.Concurrent; using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.Formats.Bmp; +using SixLabors.ImageSharp.Formats.Cur; using SixLabors.ImageSharp.Formats.Gif; +using SixLabors.ImageSharp.Formats.Ico; using SixLabors.ImageSharp.Formats.Jpeg; using SixLabors.ImageSharp.Formats.Pbm; using SixLabors.ImageSharp.Formats.Png; @@ -87,10 +89,7 @@ public int StreamProcessingBufferSize get => this.streamProcessingBufferSize; set { - if (value <= 0) - { - throw new ArgumentOutOfRangeException(nameof(this.StreamProcessingBufferSize)); - } + ArgumentOutOfRangeException.ThrowIfNegativeOrZero(value); this.streamProcessingBufferSize = value; } @@ -225,5 +224,7 @@ public void Configure(IImageFormatConfigurationModule configuration) new TgaConfigurationModule(), new TiffConfigurationModule(), new WebpConfigurationModule(), - new QoiConfigurationModule()); + new QoiConfigurationModule(), + new IcoConfigurationModule(), + new CurConfigurationModule()); } diff --git a/src/ImageSharp/Diagnostics/CodeAnalysis/UnscopedRefAttribute.cs b/src/ImageSharp/Diagnostics/CodeAnalysis/UnscopedRefAttribute.cs deleted file mode 100644 index dc2c7bd196..0000000000 --- a/src/ImageSharp/Diagnostics/CodeAnalysis/UnscopedRefAttribute.cs +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. -#if NET6_0 -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -namespace System.Diagnostics.CodeAnalysis -{ - /// - /// Used to indicate a byref escapes and is not scoped. - /// - /// - /// - /// There are several cases where the C# compiler treats a as implicitly - /// - where the compiler does not allow the to escape the method. - /// - /// - /// For example: - /// - /// for instance methods. - /// parameters that refer to types. - /// parameters. - /// - /// - /// - /// This attribute is used in those instances where the should be allowed to escape. - /// - /// - /// Applying this attribute, in any form, has impact on consumers of the applicable API. It is necessary for - /// API authors to understand the lifetime implications of applying this attribute and how it may impact their users. - /// - /// - [global::System.AttributeUsage( - global::System.AttributeTargets.Method | - global::System.AttributeTargets.Property | - global::System.AttributeTargets.Parameter, - AllowMultiple = false, - Inherited = false)] - internal sealed class UnscopedRefAttribute : global::System.Attribute - { - } -} -#endif diff --git a/src/ImageSharp/Formats/AnimatedImageFrameMetadata.cs b/src/ImageSharp/Formats/AnimatedImageFrameMetadata.cs index 5f4015180b..8f8e187403 100644 --- a/src/ImageSharp/Formats/AnimatedImageFrameMetadata.cs +++ b/src/ImageSharp/Formats/AnimatedImageFrameMetadata.cs @@ -2,6 +2,7 @@ // Licensed under the Six Labors Split License. namespace SixLabors.ImageSharp.Formats; + internal class AnimatedImageFrameMetadata { /// @@ -29,65 +30,3 @@ internal class AnimatedImageFrameMetadata /// public FrameDisposalMode DisposalMode { get; set; } } - -#pragma warning disable SA1201 // Elements should appear in the correct order -internal enum FrameBlendMode -#pragma warning restore SA1201 // Elements should appear in the correct order -{ - /// - /// Do not blend. Render the current frame on the canvas by overwriting the rectangle covered by the current frame. - /// - Source = 0, - - /// - /// Blend the current frame with the previous frame in the animation sequence within the rectangle covered - /// by the current frame. - /// If the current has any transparent areas, the corresponding areas of the previous frame will be visible - /// through these transparent regions. - /// - Over = 1 -} - -internal enum FrameDisposalMode -{ - /// - /// No disposal specified. - /// The decoder is not required to take any action. - /// - Unspecified = 0, - - /// - /// Do not dispose. The current frame is not disposed of, or in other words, not cleared or altered when moving to - /// the next frame. This means that the next frame is drawn over the current frame, and if the next frame contains - /// transparency, the previous frame will be visible through these transparent areas. - /// - DoNotDispose = 1, - - /// - /// Restore to background color. When transitioning to the next frame, the area occupied by the current frame is - /// filled with the background color specified in the image metadata. - /// This effectively erases the current frame by replacing it with the background color before the next frame is displayed. - /// - RestoreToBackground = 2, - - /// - /// Restore to previous. This method restores the area affected by the current frame to what it was before the - /// current frame was displayed. It essentially "undoes" the current frame, reverting to the state of the image - /// before the frame was displayed, then the next frame is drawn. This is useful for animations where only a small - /// part of the image changes from frame to frame. - /// - RestoreToPrevious = 3 -} - -internal enum FrameColorTableMode -{ - /// - /// The frame uses the shared color table specified by the image metadata. - /// - Global, - - /// - /// The frame uses a color table specified by the frame metadata. - /// - Local -} diff --git a/src/ImageSharp/Formats/AnimatedImageMetadata.cs b/src/ImageSharp/Formats/AnimatedImageMetadata.cs index d89ec41f07..ac3ca29f4f 100644 --- a/src/ImageSharp/Formats/AnimatedImageMetadata.cs +++ b/src/ImageSharp/Formats/AnimatedImageMetadata.cs @@ -2,6 +2,7 @@ // Licensed under the Six Labors Split License. namespace SixLabors.ImageSharp.Formats; + internal class AnimatedImageMetadata { /// diff --git a/src/ImageSharp/Formats/AnimationUtilities.cs b/src/ImageSharp/Formats/AnimationUtilities.cs index 288f3d1329..4605d4daa7 100644 --- a/src/ImageSharp/Formats/AnimationUtilities.cs +++ b/src/ImageSharp/Formats/AnimationUtilities.cs @@ -50,7 +50,7 @@ public static (bool Difference, Rectangle Bounds) DeDuplicatePixels( Span next = buffers.GetSpan().Slice(currentFrame.Width * 2, currentFrame.Width); Span result = buffers.GetSpan()[(currentFrame.Width * 3)..]; - Rgba32 bg = replacement; + Rgba32 bg = replacement.ToPixel(); int top = int.MinValue; int bottom = int.MaxValue; @@ -232,7 +232,7 @@ public static (bool Difference, Rectangle Bounds) DeDuplicatePixels( ref Rgba32 r = ref Unsafe.Add(ref MemoryMarshal.GetReference(result), x); bool peq = c.Rgba == (previousFrame != null ? p.Rgba : bg.Rgba); - Rgba32 val = (blend & peq) ? replacement : c; + Rgba32 val = (blend & peq) ? bg : c; peq &= nextFrame == null || (n.Rgba >> 24 >= c.Rgba >> 24); r = val; diff --git a/src/ImageSharp/Formats/Bmp/BmpBitsPerPixel.cs b/src/ImageSharp/Formats/Bmp/BmpBitsPerPixel.cs index 5700bb444c..3c9e3ce795 100644 --- a/src/ImageSharp/Formats/Bmp/BmpBitsPerPixel.cs +++ b/src/ImageSharp/Formats/Bmp/BmpBitsPerPixel.cs @@ -11,35 +11,35 @@ public enum BmpBitsPerPixel : short /// /// 1 bit per pixel. /// - Pixel1 = 1, + Bit1 = 1, /// /// 2 bits per pixel. /// - Pixel2 = 2, + Bit2 = 2, /// /// 4 bits per pixel. /// - Pixel4 = 4, + Bit4 = 4, /// /// 8 bits per pixel. Each pixel consists of 1 byte. /// - Pixel8 = 8, + Bit8 = 8, /// /// 16 bits per pixel. Each pixel consists of 2 bytes. /// - Pixel16 = 16, + Bit16 = 16, /// /// 24 bits per pixel. Each pixel consists of 3 bytes. /// - Pixel24 = 24, + Bit24 = 24, /// /// 32 bits per pixel. Each pixel consists of 4 bytes. /// - Pixel32 = 32 + Bit32 = 32 } diff --git a/src/ImageSharp/Formats/Bmp/BmpConstants.cs b/src/ImageSharp/Formats/Bmp/BmpConstants.cs index 5cf0c97324..62edfdfdfa 100644 --- a/src/ImageSharp/Formats/Bmp/BmpConstants.cs +++ b/src/ImageSharp/Formats/Bmp/BmpConstants.cs @@ -11,7 +11,12 @@ internal static class BmpConstants /// /// The list of mimetypes that equate to a bmp. /// - public static readonly IEnumerable MimeTypes = new[] { "image/bmp", "image/x-windows-bmp" }; + public static readonly IEnumerable MimeTypes = new[] + { + "image/bmp", + "image/x-windows-bmp", + "image/x-win-bitmap" + }; /// /// The list of file extensions that equate to a bmp. diff --git a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs index 5dc30575d5..94257517d2 100644 --- a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs +++ b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs @@ -6,6 +6,7 @@ using System.Diagnostics.CodeAnalysis; using System.Numerics; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using SixLabors.ImageSharp.Common.Helpers; using SixLabors.ImageSharp.IO; using SixLabors.ImageSharp.Memory; @@ -71,7 +72,7 @@ internal sealed class BmpDecoderCore : ImageDecoderCore /// /// The file header containing general information. /// - private BmpFileHeader fileHeader; + private BmpFileHeader? fileHeader; /// /// Indicates which bitmap file marker was read. @@ -99,6 +100,15 @@ internal sealed class BmpDecoderCore : ImageDecoderCore /// private readonly RleSkippedPixelHandling rleSkippedPixelHandling; + /// + private readonly bool processedAlphaMask; + + /// + private readonly bool skipFileHeader; + + /// + private readonly bool isDoubleHeight; + /// /// Initializes a new instance of the class. /// @@ -109,6 +119,9 @@ public BmpDecoderCore(BmpDecoderOptions options) this.rleSkippedPixelHandling = options.RleSkippedPixelHandling; this.configuration = options.GeneralOptions.Configuration; this.memoryAllocator = this.configuration.MemoryAllocator; + this.processedAlphaMask = options.ProcessedAlphaMask; + this.skipFileHeader = options.SkipFileHeader; + this.isDoubleHeight = options.UseDoubleHeight; } /// @@ -125,38 +138,44 @@ protected override Image Decode(BufferedReadStream stream, Cance switch (this.infoHeader.Compression) { - case BmpCompression.RGB: - if (this.infoHeader.BitsPerPixel == 32) - { - if (this.bmpMetadata.InfoHeaderType == BmpInfoHeaderType.WinVersion3) - { - this.ReadRgb32Slow(stream, pixels, this.infoHeader.Width, this.infoHeader.Height, inverted); - } - else - { - this.ReadRgb32Fast(stream, pixels, this.infoHeader.Width, this.infoHeader.Height, inverted); - } - } - else if (this.infoHeader.BitsPerPixel == 24) - { - this.ReadRgb24(stream, pixels, this.infoHeader.Width, this.infoHeader.Height, inverted); - } - else if (this.infoHeader.BitsPerPixel == 16) - { - this.ReadRgb16(stream, pixels, this.infoHeader.Width, this.infoHeader.Height, inverted); - } - else if (this.infoHeader.BitsPerPixel <= 8) - { - this.ReadRgbPalette( - stream, - pixels, - palette, - this.infoHeader.Width, - this.infoHeader.Height, - this.infoHeader.BitsPerPixel, - bytesPerColorMapEntry, - inverted); - } + case BmpCompression.RGB when this.infoHeader.BitsPerPixel is 32 && this.bmpMetadata.InfoHeaderType is BmpInfoHeaderType.WinVersion3: + this.ReadRgb32Slow(stream, pixels, this.infoHeader.Width, this.infoHeader.Height, inverted); + + break; + case BmpCompression.RGB when this.infoHeader.BitsPerPixel is 32: + this.ReadRgb32Fast(stream, pixels, this.infoHeader.Width, this.infoHeader.Height, inverted); + + break; + case BmpCompression.RGB when this.infoHeader.BitsPerPixel is 24: + this.ReadRgb24(stream, pixels, this.infoHeader.Width, this.infoHeader.Height, inverted); + + break; + case BmpCompression.RGB when this.infoHeader.BitsPerPixel is 16: + this.ReadRgb16(stream, pixels, this.infoHeader.Width, this.infoHeader.Height, inverted); + + break; + case BmpCompression.RGB when this.infoHeader.BitsPerPixel is <= 8 && this.processedAlphaMask: + this.ReadRgbPaletteWithAlphaMask( + stream, + pixels, + palette, + this.infoHeader.Width, + this.infoHeader.Height, + this.infoHeader.BitsPerPixel, + bytesPerColorMapEntry, + inverted); + + break; + case BmpCompression.RGB when this.infoHeader.BitsPerPixel is <= 8: + this.ReadRgbPalette( + stream, + pixels, + palette, + this.infoHeader.Width, + this.infoHeader.Height, + this.infoHeader.BitsPerPixel, + bytesPerColorMapEntry, + inverted); break; @@ -201,7 +220,7 @@ protected override Image Decode(BufferedReadStream stream, Cance protected override ImageInfo Identify(BufferedReadStream stream, CancellationToken cancellationToken) { this.ReadImageHeaders(stream, out _, out _); - return new ImageInfo(new PixelTypeInfo(this.infoHeader.BitsPerPixel), new(this.infoHeader.Width, this.infoHeader.Height), this.metadata); + return new ImageInfo(new(this.infoHeader.Width, this.infoHeader.Height), this.metadata); } /// @@ -287,72 +306,60 @@ private void ReadBitFields(BufferedReadStream stream, Buffer2D p private void ReadRle(BufferedReadStream stream, BmpCompression compression, Buffer2D pixels, byte[] colors, int width, int height, bool inverted) where TPixel : unmanaged, IPixel { - TPixel color = default; - using (IMemoryOwner buffer = this.memoryAllocator.Allocate(width * height, AllocationOptions.Clean)) - using (IMemoryOwner undefinedPixels = this.memoryAllocator.Allocate(width * height, AllocationOptions.Clean)) - using (IMemoryOwner rowsWithUndefinedPixels = this.memoryAllocator.Allocate(height, AllocationOptions.Clean)) + using IMemoryOwner buffer = this.memoryAllocator.Allocate(width * height, AllocationOptions.Clean); + using IMemoryOwner undefinedPixels = this.memoryAllocator.Allocate(width * height, AllocationOptions.Clean); + using IMemoryOwner rowsWithUndefinedPixels = this.memoryAllocator.Allocate(height, AllocationOptions.Clean); + Span rowsWithUndefinedPixelsSpan = rowsWithUndefinedPixels.Memory.Span; + Span undefinedPixelsSpan = undefinedPixels.Memory.Span; + Span bufferSpan = buffer.Memory.Span; + if (compression is BmpCompression.RLE8) { - Span rowsWithUndefinedPixelsSpan = rowsWithUndefinedPixels.Memory.Span; - Span undefinedPixelsSpan = undefinedPixels.Memory.Span; - Span bufferSpan = buffer.Memory.Span; - if (compression is BmpCompression.RLE8) - { - this.UncompressRle8(stream, width, bufferSpan, undefinedPixelsSpan, rowsWithUndefinedPixelsSpan); - } - else - { - this.UncompressRle4(stream, width, bufferSpan, undefinedPixelsSpan, rowsWithUndefinedPixelsSpan); - } + this.UncompressRle8(stream, width, bufferSpan, undefinedPixelsSpan, rowsWithUndefinedPixelsSpan); + } + else + { + this.UncompressRle4(stream, width, bufferSpan, undefinedPixelsSpan, rowsWithUndefinedPixelsSpan); + } - for (int y = 0; y < height; y++) - { - int newY = Invert(y, height, inverted); - int rowStartIdx = y * width; - Span bufferRow = bufferSpan.Slice(rowStartIdx, width); - Span pixelRow = pixels.DangerousGetRowSpan(newY); + for (int y = 0; y < height; y++) + { + int newY = Invert(y, height, inverted); + int rowStartIdx = y * width; + Span bufferRow = bufferSpan.Slice(rowStartIdx, width); + Span pixelRow = pixels.DangerousGetRowSpan(newY); - bool rowHasUndefinedPixels = rowsWithUndefinedPixelsSpan[y]; - if (rowHasUndefinedPixels) + bool rowHasUndefinedPixels = rowsWithUndefinedPixelsSpan[y]; + if (rowHasUndefinedPixels) + { + // Slow path with undefined pixels. + for (int x = 0; x < width; x++) { - // Slow path with undefined pixels. - for (int x = 0; x < width; x++) + byte colorIdx = bufferRow[x]; + if (undefinedPixelsSpan[rowStartIdx + x]) { - byte colorIdx = bufferRow[x]; - if (undefinedPixelsSpan[rowStartIdx + x]) - { - switch (this.rleSkippedPixelHandling) - { - case RleSkippedPixelHandling.FirstColorOfPalette: - color.FromBgr24(Unsafe.As(ref colors[colorIdx * 4])); - break; - case RleSkippedPixelHandling.Transparent: - color.FromScaledVector4(Vector4.Zero); - break; - - // Default handling for skipped pixels is black (which is what System.Drawing is also doing). - default: - color.FromScaledVector4(new Vector4(0.0f, 0.0f, 0.0f, 1.0f)); - break; - } - } - else + pixelRow[x] = this.rleSkippedPixelHandling switch { - color.FromBgr24(Unsafe.As(ref colors[colorIdx * 4])); - } + RleSkippedPixelHandling.FirstColorOfPalette => TPixel.FromBgr24(Unsafe.As(ref colors[colorIdx * 4])), + RleSkippedPixelHandling.Transparent => TPixel.FromScaledVector4(Vector4.Zero), - pixelRow[x] = color; + // Default handling for skipped pixels is black (which is what System.Drawing is also doing). + _ => TPixel.FromScaledVector4(new Vector4(0.0f, 0.0f, 0.0f, 1.0f)), + }; } - } - else - { - // Fast path without any undefined pixels. - for (int x = 0; x < width; x++) + else { - color.FromBgr24(Unsafe.As(ref colors[bufferRow[x] * 4])); - pixelRow[x] = color; + pixelRow[x] = TPixel.FromBgr24(Unsafe.As(ref colors[colorIdx * 4])); } } } + else + { + // Fast path without any undefined pixels. + for (int x = 0; x < width; x++) + { + pixelRow[x] = TPixel.FromBgr24(Unsafe.As(ref colors[bufferRow[x] * 4])); + } + } } } @@ -368,66 +375,54 @@ private void ReadRle(BufferedReadStream stream, BmpCompression compressi private void ReadRle24(BufferedReadStream stream, Buffer2D pixels, int width, int height, bool inverted) where TPixel : unmanaged, IPixel { - TPixel color = default; - using (IMemoryOwner buffer = this.memoryAllocator.Allocate(width * height * 3, AllocationOptions.Clean)) - using (IMemoryOwner undefinedPixels = this.memoryAllocator.Allocate(width * height, AllocationOptions.Clean)) - using (IMemoryOwner rowsWithUndefinedPixels = this.memoryAllocator.Allocate(height, AllocationOptions.Clean)) - { - Span rowsWithUndefinedPixelsSpan = rowsWithUndefinedPixels.Memory.Span; - Span undefinedPixelsSpan = undefinedPixels.Memory.Span; - Span bufferSpan = buffer.GetSpan(); + using IMemoryOwner buffer = this.memoryAllocator.Allocate(width * height * 3, AllocationOptions.Clean); + using IMemoryOwner undefinedPixels = this.memoryAllocator.Allocate(width * height, AllocationOptions.Clean); + using IMemoryOwner rowsWithUndefinedPixels = this.memoryAllocator.Allocate(height, AllocationOptions.Clean); + Span rowsWithUndefinedPixelsSpan = rowsWithUndefinedPixels.Memory.Span; + Span undefinedPixelsSpan = undefinedPixels.Memory.Span; + Span bufferSpan = buffer.GetSpan(); - this.UncompressRle24(stream, width, bufferSpan, undefinedPixelsSpan, rowsWithUndefinedPixelsSpan); - for (int y = 0; y < height; y++) + this.UncompressRle24(stream, width, bufferSpan, undefinedPixelsSpan, rowsWithUndefinedPixelsSpan); + for (int y = 0; y < height; y++) + { + int newY = Invert(y, height, inverted); + Span pixelRow = pixels.DangerousGetRowSpan(newY); + bool rowHasUndefinedPixels = rowsWithUndefinedPixelsSpan[y]; + if (rowHasUndefinedPixels) { - int newY = Invert(y, height, inverted); - Span pixelRow = pixels.DangerousGetRowSpan(newY); - bool rowHasUndefinedPixels = rowsWithUndefinedPixelsSpan[y]; - if (rowHasUndefinedPixels) + // Slow path with undefined pixels. + int yMulWidth = y * width; + int rowStartIdx = yMulWidth * 3; + for (int x = 0; x < width; x++) { - // Slow path with undefined pixels. - int yMulWidth = y * width; - int rowStartIdx = yMulWidth * 3; - for (int x = 0; x < width; x++) + int idx = rowStartIdx + (x * 3); + if (undefinedPixelsSpan[yMulWidth + x]) { - int idx = rowStartIdx + (x * 3); - if (undefinedPixelsSpan[yMulWidth + x]) + pixelRow[x] = this.rleSkippedPixelHandling switch { - switch (this.rleSkippedPixelHandling) - { - case RleSkippedPixelHandling.FirstColorOfPalette: - color.FromBgr24(Unsafe.As(ref bufferSpan[idx])); - break; - case RleSkippedPixelHandling.Transparent: - color.FromScaledVector4(Vector4.Zero); - break; - - // Default handling for skipped pixels is black (which is what System.Drawing is also doing). - default: - color.FromScaledVector4(new Vector4(0.0f, 0.0f, 0.0f, 1.0f)); - break; - } - } - else - { - color.FromBgr24(Unsafe.As(ref bufferSpan[idx])); - } + RleSkippedPixelHandling.FirstColorOfPalette => TPixel.FromBgr24(Unsafe.As(ref bufferSpan[idx])), + RleSkippedPixelHandling.Transparent => TPixel.FromScaledVector4(Vector4.Zero), - pixelRow[x] = color; + // Default handling for skipped pixels is black (which is what System.Drawing is also doing). + _ => TPixel.FromScaledVector4(new Vector4(0.0f, 0.0f, 0.0f, 1.0f)), + }; } - } - else - { - // Fast path without any undefined pixels. - int rowStartIdx = y * width * 3; - for (int x = 0; x < width; x++) + else { - int idx = rowStartIdx + (x * 3); - color.FromBgr24(Unsafe.As(ref bufferSpan[idx])); - pixelRow[x] = color; + pixelRow[x] = TPixel.FromBgr24(Unsafe.As(ref bufferSpan[idx])); } } } + else + { + // Fast path without any undefined pixels. + int rowStartIdx = y * width * 3; + for (int x = 0; x < width; x++) + { + int idx = rowStartIdx + (x * 3); + pixelRow[x] = TPixel.FromBgr24(Unsafe.As(ref bufferSpan[idx])); + } + } } } @@ -485,7 +480,7 @@ private void UncompressRle4(BufferedReadStream stream, int w, Span buffer, int max = cmd[1]; int bytesToRead = (int)(((uint)max + 1) / 2); - Span run = bytesToRead <= 128 ? scratchBuffer.Slice(0, bytesToRead) : new byte[bytesToRead]; + Span run = bytesToRead <= 128 ? scratchBuffer[..bytesToRead] : new byte[bytesToRead]; stream.Read(run); @@ -591,7 +586,7 @@ private void UncompressRle8(BufferedReadStream stream, int w, Span buffer, // Take this number of bytes from the stream as uncompressed data. int length = cmd[1]; - Span run = length <= 128 ? scratchBuffer.Slice(0, length) : new byte[length]; + Span run = length <= 128 ? scratchBuffer[..length] : new byte[length]; stream.Read(run); @@ -673,7 +668,7 @@ private void UncompressRle24(BufferedReadStream stream, int w, Span buffer int length = cmd[1]; int length3 = length * 3; - Span run = length3 <= 128 ? scratchBuffer.Slice(0, length3) : new byte[length3]; + Span run = length3 <= 128 ? scratchBuffer[..length3] : new byte[length3]; stream.Read(run); @@ -828,7 +823,6 @@ private void ReadRgbPalette(BufferedReadStream stream, Buffer2D } using IMemoryOwner row = this.memoryAllocator.Allocate(arrayWidth + padding, AllocationOptions.Clean); - TPixel color = default; Span rowSpan = row.GetSpan(); for (int y = 0; y < height; y++) @@ -849,8 +843,7 @@ private void ReadRgbPalette(BufferedReadStream stream, Buffer2D { int colorIndex = ((rowSpan[offset] >> (8 - bitsPerPixel - (shift * bitsPerPixel))) & mask) * bytesPerColorMapEntry; - color.FromBgr24(Unsafe.As(ref colors[colorIndex])); - pixelRow[newX] = color; + pixelRow[newX] = TPixel.FromBgr24(Unsafe.As(ref colors[colorIndex])); } offset++; @@ -858,6 +851,108 @@ private void ReadRgbPalette(BufferedReadStream stream, Buffer2D } } + /// + private void ReadRgbPaletteWithAlphaMask(BufferedReadStream stream, Buffer2D pixels, byte[] colors, int width, int height, int bitsPerPixel, int bytesPerColorMapEntry, bool inverted) + where TPixel : unmanaged, IPixel + { + // Pixels per byte (bits per pixel). + int ppb = 8 / bitsPerPixel; + + int arrayWidth = (width + ppb - 1) / ppb; + + // Bit mask + int mask = 0xFF >> (8 - bitsPerPixel); + + // Rows are aligned on 4 byte boundaries. + int padding = arrayWidth % 4; + if (padding != 0) + { + padding = 4 - padding; + } + + Bgra32[,] image = new Bgra32[height, width]; + using (IMemoryOwner row = this.memoryAllocator.Allocate(arrayWidth + padding, AllocationOptions.Clean)) + { + Span rowSpan = row.GetSpan(); + + for (int y = 0; y < height; y++) + { + int newY = Invert(y, height, inverted); + if (stream.Read(rowSpan) == 0) + { + BmpThrowHelper.ThrowInvalidImageContentException("Could not read enough data for a pixel row!"); + } + + int offset = 0; + + for (int x = 0; x < arrayWidth; x++) + { + int colOffset = x * ppb; + for (int shift = 0, newX = colOffset; shift < ppb && newX < width; shift++, newX++) + { + int colorIndex = ((rowSpan[offset] >> (8 - bitsPerPixel - (shift * bitsPerPixel))) & mask) * bytesPerColorMapEntry; + + image[newY, newX] = Bgra32.FromBgr24(Unsafe.As(ref colors[colorIndex])); + } + + offset++; + } + } + } + + arrayWidth = width / 8; + padding = arrayWidth % 4; + if (padding != 0) + { + padding = 4 - padding; + } + + for (int y = 0; y < height; y++) + { + int newY = Invert(y, height, inverted); + + for (int i = 0; i < arrayWidth; i++) + { + int x = i * 8; + int and = stream.ReadByte(); + if (and is -1) + { + throw new EndOfStreamException(); + } + + for (int j = 0; j < 8; j++) + { + SetAlpha(ref image[newY, x + j], and, j); + } + } + + stream.Skip(padding); + } + + for (int y = 0; y < height; y++) + { + int newY = Invert(y, height, inverted); + Span pixelRow = pixels.DangerousGetRowSpan(newY); + + for (int x = 0; x < width; x++) + { + pixelRow[x] = TPixel.FromBgra32(image[newY, x]); + } + } + } + + /// + /// Set pixel's alpha with alpha mask. + /// + /// Bgra32 pixel. + /// alpha mask. + /// bit index of pixel. + private static void SetAlpha(ref Bgra32 pixel, in int mask, in int index) + { + bool isTransparently = (mask & (0b10000000 >> index)) is not 0; + pixel.A = isTransparently ? byte.MinValue : byte.MaxValue; + } + /// /// Reads the 16 bit color palette from the stream. /// @@ -875,8 +970,6 @@ private void ReadRgb16(BufferedReadStream stream, Buffer2D pixel { int padding = CalculatePadding(width, 2); int stride = (width * 2) + padding; - TPixel color = default; - int rightShiftRedMask = CalculateRightShift((uint)redMask); int rightShiftGreenMask = CalculateRightShift((uint)greenMask); int rightShiftBlueMask = CalculateRightShift((uint)blueMask); @@ -910,8 +1003,7 @@ private void ReadRgb16(BufferedReadStream stream, Buffer2D pixel int b = (blueMaskBits == 5) ? GetBytesFrom5BitValue((temp & blueMask) >> rightShiftBlueMask) : GetBytesFrom6BitValue((temp & blueMask) >> rightShiftBlueMask); Rgb24 rgb = new((byte)r, (byte)g, (byte)b); - color.FromRgb24(rgb); - pixelRow[x] = color; + pixelRow[x] = TPixel.FromRgb24(rgb); offset += 2; } } @@ -1100,8 +1192,7 @@ private void ReadRgb32Slow(BufferedReadStream stream, Buffer2D p { Bgra32 bgra = bgraRowSpan[x]; bgra.A = byte.MaxValue; - ref TPixel pixel = ref pixelSpan[x]; - pixel.FromBgra32(bgra); + pixelSpan[x] = TPixel.FromBgra32(bgra); } } } @@ -1122,7 +1213,6 @@ private void ReadRgb32Slow(BufferedReadStream stream, Buffer2D p private void ReadRgb32BitFields(BufferedReadStream stream, Buffer2D pixels, int width, int height, bool inverted, int redMask, int greenMask, int blueMask, int alphaMask) where TPixel : unmanaged, IPixel { - TPixel color = default; int padding = CalculatePadding(width, 4); int stride = (width * 4) + padding; @@ -1172,18 +1262,17 @@ private void ReadRgb32BitFields(BufferedReadStream stream, Buffer2D> rightShiftRedMask); byte g = (byte)((temp & greenMask) >> rightShiftGreenMask); byte b = (byte)((temp & blueMask) >> rightShiftBlueMask); - byte a = alphaMask != 0 ? (byte)((temp & alphaMask) >> rightShiftAlphaMask) : (byte)255; - color.FromRgba32(new Rgba32(r, g, b, a)); + byte a = alphaMask != 0 ? (byte)((temp & alphaMask) >> rightShiftAlphaMask) : byte.MaxValue; + pixelRow[x] = TPixel.FromRgba32(new(r, g, b, a)); } - pixelRow[x] = color; offset += 4; } } @@ -1358,6 +1447,11 @@ private void ReadInfoHeader(BufferedReadStream stream) this.metadata.VerticalResolution = Math.Round(UnitConverter.InchToMeter(ImageMetadata.DefaultVerticalResolution)); } + if (this.isDoubleHeight) + { + this.infoHeader.Height >>= 1; + } + ushort bitsPerPixel = this.infoHeader.BitsPerPixel; this.bmpMetadata = this.metadata.GetBmpMetadata(); this.bmpMetadata.InfoHeaderType = infoHeaderType; @@ -1389,9 +1483,9 @@ private void ReadFileHeader(BufferedReadStream stream) // The bitmap file header of the first image follows the array header. stream.Read(buffer, 0, BmpFileHeader.Size); this.fileHeader = BmpFileHeader.Parse(buffer); - if (this.fileHeader.Type != BmpConstants.TypeMarkers.Bitmap) + if (this.fileHeader.Value.Type != BmpConstants.TypeMarkers.Bitmap) { - BmpThrowHelper.ThrowNotSupportedException($"Unsupported bitmap file inside a BitmapArray file. File header bitmap type marker '{this.fileHeader.Type}'."); + BmpThrowHelper.ThrowNotSupportedException($"Unsupported bitmap file inside a BitmapArray file. File header bitmap type marker '{this.fileHeader.Value.Type}'."); } break; @@ -1414,7 +1508,11 @@ private void ReadFileHeader(BufferedReadStream stream) [MemberNotNull(nameof(bmpMetadata))] private int ReadImageHeaders(BufferedReadStream stream, out bool inverted, out byte[] palette) { - this.ReadFileHeader(stream); + if (!this.skipFileHeader) + { + this.ReadFileHeader(stream); + } + this.ReadInfoHeader(stream); // see http://www.drdobbs.com/architecture-and-design/the-bmp-file-format-part-1/184409517 @@ -1438,7 +1536,21 @@ private int ReadImageHeaders(BufferedReadStream stream, out bool inverted, out b switch (this.fileMarkerType) { case BmpFileMarkerType.Bitmap: - colorMapSizeBytes = this.fileHeader.Offset - BmpFileHeader.Size - this.infoHeader.HeaderSize; + if (this.fileHeader.HasValue) + { + colorMapSizeBytes = this.fileHeader.Value.Offset - BmpFileHeader.Size - this.infoHeader.HeaderSize; + } + else + { + colorMapSizeBytes = this.infoHeader.ClrUsed; + if (colorMapSizeBytes is 0 && this.infoHeader.BitsPerPixel is <= 8) + { + colorMapSizeBytes = ColorNumerics.GetColorCountForBitDepth(this.infoHeader.BitsPerPixel); + } + + colorMapSizeBytes *= 4; + } + int colorCountForBitDepth = ColorNumerics.GetColorCountForBitDepth(this.infoHeader.BitsPerPixel); bytesPerColorMapEntry = colorMapSizeBytes / colorCountForBitDepth; @@ -1463,13 +1575,13 @@ private int ReadImageHeaders(BufferedReadStream stream, out bool inverted, out b colorMapSizeBytes = this.infoHeader.ClrUsed * bytesPerColorMapEntry; } - palette = Array.Empty(); + palette = []; if (colorMapSizeBytes > 0) { // Usually the color palette is 1024 byte (256 colors * 4), but the documentation does not mention a size limit. // Make sure, that we will not read pass the bitmap offset (starting position of image data). - if (stream.Position > this.fileHeader.Offset - colorMapSizeBytes) + if (this.fileHeader.HasValue && stream.Position > this.fileHeader.Value.Offset - colorMapSizeBytes) { BmpThrowHelper.ThrowInvalidImageContentException( $"Reading the color map would read beyond the bitmap offset. Either the color map size of '{colorMapSizeBytes}' is invalid or the bitmap offset."); @@ -1483,7 +1595,20 @@ private int ReadImageHeaders(BufferedReadStream stream, out bool inverted, out b } } - int skipAmount = this.fileHeader.Offset - (int)stream.Position; + if (palette.Length > 0) + { + Color[] colorTable = new Color[palette.Length / Unsafe.SizeOf()]; + ReadOnlySpan rgbTable = MemoryMarshal.Cast(palette); + Color.FromPixel(rgbTable, colorTable); + this.bmpMetadata.ColorTable = colorTable; + } + + int skipAmount = 0; + if (this.fileHeader.HasValue) + { + skipAmount = this.fileHeader.Value.Offset - (int)stream.Position; + } + if ((skipAmount + (int)stream.Position) > stream.Length) { BmpThrowHelper.ThrowInvalidImageContentException("Invalid file header offset found. Offset is greater than the stream length."); diff --git a/src/ImageSharp/Formats/Bmp/BmpDecoderOptions.cs b/src/ImageSharp/Formats/Bmp/BmpDecoderOptions.cs index b3387ce808..158a9d4797 100644 --- a/src/ImageSharp/Formats/Bmp/BmpDecoderOptions.cs +++ b/src/ImageSharp/Formats/Bmp/BmpDecoderOptions.cs @@ -16,4 +16,28 @@ public sealed class BmpDecoderOptions : ISpecializedDecoderOptions /// which can occur during decoding run length encoded bitmaps. /// public RleSkippedPixelHandling RleSkippedPixelHandling { get; init; } + + /// + /// Gets a value indicating whether the additional alpha mask is processed at decoding time. + /// + /// + /// Used by the icon decoder. + /// + internal bool ProcessedAlphaMask { get; init; } + + /// + /// Gets a value indicating whether to skip loading the BMP file header. + /// + /// + /// Used by the icon decoder. + /// + internal bool SkipFileHeader { get; init; } + + /// + /// Gets a value indicating whether to treat the height as double of true height. + /// + /// + /// Used by the icon decoder. + /// + internal bool UseDoubleHeight { get; init; } } diff --git a/src/ImageSharp/Formats/Bmp/BmpEncoder.cs b/src/ImageSharp/Formats/Bmp/BmpEncoder.cs index 0081f6a1ae..e255568047 100644 --- a/src/ImageSharp/Formats/Bmp/BmpEncoder.cs +++ b/src/ImageSharp/Formats/Bmp/BmpEncoder.cs @@ -1,7 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Processing; namespace SixLabors.ImageSharp.Formats.Bmp; @@ -29,6 +28,15 @@ public sealed class BmpEncoder : QuantizingImageEncoder /// public bool SupportTransparency { get; init; } + /// + internal bool ProcessedAlphaMask { get; init; } + + /// + internal bool SkipFileHeader { get; init; } + + /// + internal bool UseDoubleHeight { get; init; } + /// protected override void Encode(Image image, Stream stream, CancellationToken cancellationToken) { diff --git a/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs index 187170f898..85786949d8 100644 --- a/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs +++ b/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs @@ -91,6 +91,15 @@ internal sealed class BmpEncoderCore /// private readonly IPixelSamplingStrategy pixelSamplingStrategy; + /// + private readonly bool processedAlphaMask; + + /// + private readonly bool skipFileHeader; + + /// + private readonly bool isDoubleHeight; + /// /// Initializes a new instance of the class. /// @@ -100,9 +109,14 @@ public BmpEncoderCore(BmpEncoder encoder, MemoryAllocator memoryAllocator) { this.memoryAllocator = memoryAllocator; this.bitsPerPixel = encoder.BitsPerPixel; + + // TODO: Use a palette quantizer if supplied. this.quantizer = encoder.Quantizer ?? KnownQuantizers.Octree; this.pixelSamplingStrategy = encoder.PixelSamplingStrategy; this.infoHeaderType = encoder.SupportTransparency ? BmpInfoHeaderType.WinVersion4 : BmpInfoHeaderType.WinVersion3; + this.processedAlphaMask = encoder.ProcessedAlphaMask; + this.skipFileHeader = encoder.SkipFileHeader; + this.isDoubleHeight = encoder.UseDoubleHeight; } /// @@ -118,6 +132,9 @@ public void Encode(Image image, Stream stream, CancellationToken Guard.NotNull(image, nameof(image)); Guard.NotNull(stream, nameof(stream)); + // Stream may not at 0. + long basePosition = stream.Position; + Configuration configuration = image.Configuration; ImageMetadata metadata = image.Metadata; BmpMetadata bmpMetadata = metadata.GetBmpMetadata(); @@ -129,10 +146,10 @@ public void Encode(Image image, Stream stream, CancellationToken int colorPaletteSize = this.bitsPerPixel switch { - BmpBitsPerPixel.Pixel8 => ColorPaletteSize8Bit, - BmpBitsPerPixel.Pixel4 => ColorPaletteSize4Bit, - BmpBitsPerPixel.Pixel2 => ColorPaletteSize2Bit, - BmpBitsPerPixel.Pixel1 => ColorPaletteSize1Bit, + BmpBitsPerPixel.Bit8 => ColorPaletteSize8Bit, + BmpBitsPerPixel.Bit4 => ColorPaletteSize4Bit, + BmpBitsPerPixel.Bit2 => ColorPaletteSize2Bit, + BmpBitsPerPixel.Bit1 => ColorPaletteSize1Bit, _ => 0 }; @@ -153,14 +170,26 @@ public void Encode(Image image, Stream stream, CancellationToken _ => BmpInfoHeader.SizeV3 }; - BmpInfoHeader infoHeader = this.CreateBmpInfoHeader(image.Width, image.Height, infoHeaderSize, bpp, bytesPerLine, metadata, iccProfileData); + // for ico/cur encoder. + int height = image.Height; + if (this.isDoubleHeight) + { + height <<= 1; + } + + BmpInfoHeader infoHeader = this.CreateBmpInfoHeader(image.Width, height, infoHeaderSize, bpp, bytesPerLine, metadata, iccProfileData); Span buffer = stackalloc byte[infoHeaderSize]; - WriteBitmapFileHeader(stream, infoHeaderSize, colorPaletteSize, iccProfileSize, infoHeader, buffer); + // for ico/cur encoder. + if (!this.skipFileHeader) + { + WriteBitmapFileHeader(stream, infoHeaderSize, colorPaletteSize, iccProfileSize, infoHeader, buffer); + } + this.WriteBitmapInfoHeader(stream, infoHeader, buffer, infoHeaderSize); this.WriteImage(configuration, stream, image); - WriteColorProfile(stream, iccProfileData, buffer); + WriteColorProfile(stream, iccProfileData, buffer, basePosition); stream.Flush(); } @@ -219,7 +248,7 @@ private BmpInfoHeader CreateBmpInfoHeader(int width, int height, int infoHeaderS clrUsed: 0, clrImportant: 0); - if ((this.infoHeaderType is BmpInfoHeaderType.WinVersion4 or BmpInfoHeaderType.WinVersion5) && this.bitsPerPixel == BmpBitsPerPixel.Pixel32) + if ((this.infoHeaderType is BmpInfoHeaderType.WinVersion4 or BmpInfoHeaderType.WinVersion5) && this.bitsPerPixel == BmpBitsPerPixel.Bit32) { infoHeader.AlphaMask = Rgba32AlphaMask; infoHeader.RedMask = Rgba32RedMask; @@ -244,16 +273,20 @@ private BmpInfoHeader CreateBmpInfoHeader(int width, int height, int infoHeaderS /// The stream to write to. /// The color profile data. /// The buffer. - private static void WriteColorProfile(Stream stream, byte[]? iccProfileData, Span buffer) + /// The Stream may not be start with 0. + private static void WriteColorProfile(Stream stream, byte[]? iccProfileData, Span buffer, long basePosition) { if (iccProfileData != null) { // The offset, in bytes, from the beginning of the BITMAPV5HEADER structure to the start of the profile data. int streamPositionAfterImageData = (int)stream.Position - BmpFileHeader.Size; stream.Write(iccProfileData); + long position = stream.Position; // Storage Position BinaryPrimitives.WriteInt32LittleEndian(buffer, streamPositionAfterImageData); - stream.Position = BmpFileHeader.Size + 112; + _ = stream.Seek(basePosition, SeekOrigin.Begin); + _ = stream.Seek(BmpFileHeader.Size + 112, SeekOrigin.Current); stream.Write(buffer[..4]); + _ = stream.Seek(position, SeekOrigin.Begin); // Reset Position } } @@ -318,34 +351,39 @@ private void WriteImage(Configuration configuration, Stream stream, Imag Buffer2D pixels = image.Frames.RootFrame.PixelBuffer; switch (this.bitsPerPixel) { - case BmpBitsPerPixel.Pixel32: + case BmpBitsPerPixel.Bit32: this.Write32BitPixelData(configuration, stream, pixels); break; - case BmpBitsPerPixel.Pixel24: + case BmpBitsPerPixel.Bit24: this.Write24BitPixelData(configuration, stream, pixels); break; - case BmpBitsPerPixel.Pixel16: + case BmpBitsPerPixel.Bit16: this.Write16BitPixelData(configuration, stream, pixels); break; - case BmpBitsPerPixel.Pixel8: + case BmpBitsPerPixel.Bit8: this.Write8BitPixelData(configuration, stream, image); break; - case BmpBitsPerPixel.Pixel4: + case BmpBitsPerPixel.Bit4: this.Write4BitPixelData(configuration, stream, image); break; - case BmpBitsPerPixel.Pixel2: + case BmpBitsPerPixel.Bit2: this.Write2BitPixelData(configuration, stream, image); break; - case BmpBitsPerPixel.Pixel1: + case BmpBitsPerPixel.Bit1: this.Write1BitPixelData(configuration, stream, image); break; } + + if (this.processedAlphaMask) + { + ProcessedAlphaMask(stream, image); + } } private IMemoryOwner AllocateRow(int width, int bytesPerPixel) @@ -721,4 +759,45 @@ private static void Write1BitPalette(Stream stream, int startIdx, int endIdx, Re stream.WriteByte(indices); } + + private static void ProcessedAlphaMask(Stream stream, Image image) + where TPixel : unmanaged, IPixel + { + int arrayWidth = image.Width / 8; + int padding = arrayWidth % 4; + if (padding is not 0) + { + padding = 4 - padding; + } + + Span mask = stackalloc byte[arrayWidth]; + for (int y = image.Height - 1; y >= 0; y--) + { + mask.Clear(); + Span row = image.GetRootFramePixelBuffer().DangerousGetRowSpan(y); + + for (int i = 0; i < arrayWidth; i++) + { + int x = i * 8; + + for (int j = 0; j < 8; j++) + { + WriteAlphaMask(row[x + j], ref mask[i], j); + } + } + + stream.Write(mask); + stream.Skip(padding); + } + } + + private static void WriteAlphaMask(in TPixel pixel, ref byte mask, in int index) + where TPixel : unmanaged, IPixel + { + Rgba32 rgba = pixel.ToRgba32(); + if (rgba.A is 0) + { + mask |= unchecked((byte)(0b10000000 >> index)); + } + } } diff --git a/src/ImageSharp/Formats/Bmp/BmpMetadata.cs b/src/ImageSharp/Formats/Bmp/BmpMetadata.cs index a2ed1d21d0..68e99bdc5f 100644 --- a/src/ImageSharp/Formats/Bmp/BmpMetadata.cs +++ b/src/ImageSharp/Formats/Bmp/BmpMetadata.cs @@ -1,12 +1,15 @@ -// Copyright (c) Six Labors. +// Copyright (c) Six Labors. // Licensed under the Six Labors Split License. +using SixLabors.ImageSharp.PixelFormats; + +// TODO: Add color table information. namespace SixLabors.ImageSharp.Formats.Bmp; /// /// Provides Bmp specific metadata information for the image. /// -public class BmpMetadata : IDeepCloneable +public class BmpMetadata : IFormatMetadata { /// /// Initializes a new instance of the class. @@ -23,6 +26,11 @@ private BmpMetadata(BmpMetadata other) { this.BitsPerPixel = other.BitsPerPixel; this.InfoHeaderType = other.InfoHeaderType; + + if (other.ColorTable?.Length > 0) + { + this.ColorTable = other.ColorTable.Value.ToArray(); + } } /// @@ -33,10 +41,117 @@ private BmpMetadata(BmpMetadata other) /// /// Gets or sets the number of bits per pixel. /// - public BmpBitsPerPixel BitsPerPixel { get; set; } = BmpBitsPerPixel.Pixel24; + public BmpBitsPerPixel BitsPerPixel { get; set; } = BmpBitsPerPixel.Bit24; + + /// + /// Gets or sets the color table, if any. + /// + public ReadOnlyMemory? ColorTable { get; set; } + + /// + public static BmpMetadata FromFormatConnectingMetadata(FormatConnectingMetadata metadata) + { + int bpp = metadata.PixelTypeInfo.BitsPerPixel; + return bpp switch + { + 1 => new BmpMetadata { BitsPerPixel = BmpBitsPerPixel.Bit1 }, + 2 => new BmpMetadata { BitsPerPixel = BmpBitsPerPixel.Bit2 }, + <= 4 => new BmpMetadata { BitsPerPixel = BmpBitsPerPixel.Bit4 }, + <= 8 => new BmpMetadata { BitsPerPixel = BmpBitsPerPixel.Bit8 }, + <= 16 => new BmpMetadata + { + BitsPerPixel = BmpBitsPerPixel.Bit16, + InfoHeaderType = BmpInfoHeaderType.WinVersion3 + }, + <= 24 => new BmpMetadata + { + BitsPerPixel = BmpBitsPerPixel.Bit24, + InfoHeaderType = BmpInfoHeaderType.WinVersion4 + }, + _ => new BmpMetadata + { + BitsPerPixel = BmpBitsPerPixel.Bit32, + InfoHeaderType = BmpInfoHeaderType.WinVersion5 + } + }; + } + + /// + public PixelTypeInfo GetPixelTypeInfo() + { + int bpp = (int)this.BitsPerPixel; + + PixelAlphaRepresentation alpha = this.InfoHeaderType switch + { + BmpInfoHeaderType.WinVersion2 or + BmpInfoHeaderType.Os2Version2Short or + BmpInfoHeaderType.WinVersion3 or + BmpInfoHeaderType.AdobeVersion3 or + BmpInfoHeaderType.Os2Version2 => PixelAlphaRepresentation.None, + BmpInfoHeaderType.AdobeVersion3WithAlpha or + BmpInfoHeaderType.WinVersion4 or + BmpInfoHeaderType.WinVersion5 or + _ => bpp < 32 ? PixelAlphaRepresentation.None : PixelAlphaRepresentation.Unassociated + }; + + PixelComponentInfo info; + PixelColorType color; + switch (this.BitsPerPixel) + { + case BmpBitsPerPixel.Bit1: + info = PixelComponentInfo.Create(1, bpp, 1); + color = PixelColorType.Indexed; + break; + case BmpBitsPerPixel.Bit2: + info = PixelComponentInfo.Create(1, bpp, 2); + color = PixelColorType.Indexed; + break; + case BmpBitsPerPixel.Bit4: + info = PixelComponentInfo.Create(1, bpp, 4); + color = PixelColorType.Indexed; + break; + case BmpBitsPerPixel.Bit8: + info = PixelComponentInfo.Create(1, bpp, 8); + color = PixelColorType.Indexed; + break; + + // Could be 555 with padding but 565 is more common in newer bitmaps and offers + // greater accuracy due to extra green precision. + case BmpBitsPerPixel.Bit16: + info = PixelComponentInfo.Create(3, bpp, 5, 6, 5); + color = PixelColorType.RGB; + break; + case BmpBitsPerPixel.Bit24: + info = PixelComponentInfo.Create(3, bpp, 8, 8, 8); + color = PixelColorType.RGB; + break; + case BmpBitsPerPixel.Bit32 or _: + info = PixelComponentInfo.Create(4, bpp, 8, 8, 8, 8); + color = PixelColorType.RGB | PixelColorType.Alpha; + break; + } + + return new PixelTypeInfo(bpp) + { + AlphaRepresentation = alpha, + ComponentInfo = info, + ColorType = color + }; + } /// - public IDeepCloneable DeepClone() => new BmpMetadata(this); + public FormatConnectingMetadata ToFormatConnectingMetadata() + => new() + { + EncodingType = this.BitsPerPixel <= BmpBitsPerPixel.Bit8 + ? EncodingType.Lossy + : EncodingType.Lossless, + PixelTypeInfo = this.GetPixelTypeInfo() + }; - // TODO: Colors used once we support encoding palette bmps. + /// + IDeepCloneable IDeepCloneable.DeepClone() => this.DeepClone(); + + /// + public BmpMetadata DeepClone() => new(this); } diff --git a/src/ImageSharp/Formats/Bmp/MetadataExtensions.cs b/src/ImageSharp/Formats/Bmp/MetadataExtensions.cs deleted file mode 100644 index 5297d0c989..0000000000 --- a/src/ImageSharp/Formats/Bmp/MetadataExtensions.cs +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.Formats.Bmp; -using SixLabors.ImageSharp.Metadata; - -namespace SixLabors.ImageSharp; - -/// -/// Extension methods for the type. -/// -public static partial class MetadataExtensions -{ - /// - /// Gets the bmp format specific metadata for the image. - /// - /// The metadata this method extends. - /// The . - public static BmpMetadata GetBmpMetadata(this ImageMetadata metadata) => metadata.GetFormatMetadata(BmpFormat.Instance); -} diff --git a/src/ImageSharp/Formats/Cur/CurConfigurationModule.cs b/src/ImageSharp/Formats/Cur/CurConfigurationModule.cs new file mode 100644 index 0000000000..879b3f1123 --- /dev/null +++ b/src/ImageSharp/Formats/Cur/CurConfigurationModule.cs @@ -0,0 +1,20 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.Formats.Icon; + +namespace SixLabors.ImageSharp.Formats.Cur; + +/// +/// Registers the image encoders, decoders and mime type detectors for the Ico format. +/// +public sealed class CurConfigurationModule : IImageFormatConfigurationModule +{ + /// + public void Configure(Configuration configuration) + { + configuration.ImageFormatsManager.SetEncoder(CurFormat.Instance, new CurEncoder()); + configuration.ImageFormatsManager.SetDecoder(CurFormat.Instance, CurDecoder.Instance); + configuration.ImageFormatsManager.AddImageFormatDetector(new IconImageFormatDetector()); + } +} diff --git a/src/ImageSharp/Formats/Cur/CurConstants.cs b/src/ImageSharp/Formats/Cur/CurConstants.cs new file mode 100644 index 0000000000..7abf4c812e --- /dev/null +++ b/src/ImageSharp/Formats/Cur/CurConstants.cs @@ -0,0 +1,39 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +namespace SixLabors.ImageSharp.Formats.Cur; + +/// +/// Defines constants relating to ICOs +/// +internal static class CurConstants +{ + /// + /// The list of mime types that equate to a cur. + /// + /// + /// See + /// + public static readonly IEnumerable MimeTypes = + [ + + // IANA-registered + "image/vnd.microsoft.icon", + + // ICO & CUR types used by Windows + "image/x-icon", + + // Erroneous types but have been used + "image/ico", + "image/icon", + "text/ico", + "application/ico", + ]; + + /// + /// The list of file extensions that equate to a cur. + /// + public static readonly IEnumerable FileExtensions = ["cur"]; + + public const uint FileHeader = 0x00_02_00_00; +} diff --git a/src/ImageSharp/Formats/Cur/CurDecoder.cs b/src/ImageSharp/Formats/Cur/CurDecoder.cs new file mode 100644 index 0000000000..cbe646c47b --- /dev/null +++ b/src/ImageSharp/Formats/Cur/CurDecoder.cs @@ -0,0 +1,47 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.PixelFormats; + +namespace SixLabors.ImageSharp.Formats.Cur; + +/// +/// Decoder for generating an image out of a ico encoded stream. +/// +public sealed class CurDecoder : ImageDecoder +{ + private CurDecoder() + { + } + + /// + /// Gets the shared instance. + /// + public static CurDecoder Instance { get; } = new(); + + /// + protected override Image Decode(DecoderOptions options, Stream stream, CancellationToken cancellationToken) + { + Guard.NotNull(options, nameof(options)); + Guard.NotNull(stream, nameof(stream)); + + Image image = new CurDecoderCore(options).Decode(options.Configuration, stream, cancellationToken); + + ScaleToTargetSize(options, image); + + return image; + } + + /// + protected override Image Decode(DecoderOptions options, Stream stream, CancellationToken cancellationToken) + => this.Decode(options, stream, cancellationToken); + + /// + protected override ImageInfo Identify(DecoderOptions options, Stream stream, CancellationToken cancellationToken) + { + Guard.NotNull(options, nameof(options)); + Guard.NotNull(stream, nameof(stream)); + + return new CurDecoderCore(options).Identify(options.Configuration, stream, cancellationToken); + } +} diff --git a/src/ImageSharp/Formats/Cur/CurDecoderCore.cs b/src/ImageSharp/Formats/Cur/CurDecoderCore.cs new file mode 100644 index 0000000000..a8a51878e0 --- /dev/null +++ b/src/ImageSharp/Formats/Cur/CurDecoderCore.cs @@ -0,0 +1,44 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.Formats.Bmp; +using SixLabors.ImageSharp.Formats.Icon; +using SixLabors.ImageSharp.Metadata; + +namespace SixLabors.ImageSharp.Formats.Cur; + +internal sealed class CurDecoderCore : IconDecoderCore +{ + public CurDecoderCore(DecoderOptions options) + : base(options) + { + } + + protected override void SetFrameMetadata( + ImageMetadata imageMetadata, + ImageFrameMetadata frameMetadata, + int index, + in IconDirEntry entry, + IconFrameCompression compression, + BmpBitsPerPixel bitsPerPixel, + ReadOnlyMemory? colorTable) + { + CurFrameMetadata curFrameMetadata = frameMetadata.GetCurMetadata(); + curFrameMetadata.FromIconDirEntry(entry); + curFrameMetadata.Compression = compression; + curFrameMetadata.BmpBitsPerPixel = bitsPerPixel; + curFrameMetadata.ColorTable = colorTable; + + if (index == 0) + { + CurMetadata curMetadata = imageMetadata.GetCurMetadata(); + curMetadata.Compression = compression; + curMetadata.BmpBitsPerPixel = bitsPerPixel; + curMetadata.ColorTable = colorTable; + curMetadata.EncodingWidth = curFrameMetadata.EncodingWidth; + curMetadata.EncodingHeight = curFrameMetadata.EncodingHeight; + curMetadata.HotspotX = curFrameMetadata.HotspotX; + curMetadata.HotspotY = curFrameMetadata.HotspotY; + } + } +} diff --git a/src/ImageSharp/Formats/Cur/CurEncoder.cs b/src/ImageSharp/Formats/Cur/CurEncoder.cs new file mode 100644 index 0000000000..e19a73990c --- /dev/null +++ b/src/ImageSharp/Formats/Cur/CurEncoder.cs @@ -0,0 +1,17 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +namespace SixLabors.ImageSharp.Formats.Cur; + +/// +/// Image encoder for writing an image to a stream as a Windows Cursor. +/// +public sealed class CurEncoder : QuantizingImageEncoder +{ + /// + protected override void Encode(Image image, Stream stream, CancellationToken cancellationToken) + { + CurEncoderCore encoderCore = new(this); + encoderCore.Encode(image, stream, cancellationToken); + } +} diff --git a/src/ImageSharp/Formats/Cur/CurEncoderCore.cs b/src/ImageSharp/Formats/Cur/CurEncoderCore.cs new file mode 100644 index 0000000000..6435587e2f --- /dev/null +++ b/src/ImageSharp/Formats/Cur/CurEncoderCore.cs @@ -0,0 +1,14 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.Formats.Icon; + +namespace SixLabors.ImageSharp.Formats.Cur; + +internal sealed class CurEncoderCore : IconEncoderCore +{ + public CurEncoderCore(QuantizingImageEncoder encoder) + : base(encoder, IconFileType.CUR) + { + } +} diff --git a/src/ImageSharp/Formats/Cur/CurFormat.cs b/src/ImageSharp/Formats/Cur/CurFormat.cs new file mode 100644 index 0000000000..af93382ec0 --- /dev/null +++ b/src/ImageSharp/Formats/Cur/CurFormat.cs @@ -0,0 +1,37 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +namespace SixLabors.ImageSharp.Formats.Cur; + +/// +/// Registers the image encoders, decoders and mime type detectors for the ICO format. +/// +public sealed class CurFormat : IImageFormat +{ + private CurFormat() + { + } + + /// + /// Gets the shared instance. + /// + public static CurFormat Instance { get; } = new(); + + /// + public string Name => "ICO"; + + /// + public string DefaultMimeType => CurConstants.MimeTypes.First(); + + /// + public IEnumerable MimeTypes => CurConstants.MimeTypes; + + /// + public IEnumerable FileExtensions => CurConstants.FileExtensions; + + /// + public CurMetadata CreateDefaultFormatMetadata() => new(); + + /// + public CurFrameMetadata CreateDefaultFormatFrameMetadata() => new(); +} diff --git a/src/ImageSharp/Formats/Cur/CurFrameMetadata.cs b/src/ImageSharp/Formats/Cur/CurFrameMetadata.cs new file mode 100644 index 0000000000..06cf426dc4 --- /dev/null +++ b/src/ImageSharp/Formats/Cur/CurFrameMetadata.cs @@ -0,0 +1,225 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.Formats.Bmp; +using SixLabors.ImageSharp.Formats.Icon; +using SixLabors.ImageSharp.PixelFormats; + +namespace SixLabors.ImageSharp.Formats.Cur; + +/// +/// IcoFrameMetadata. +/// +public class CurFrameMetadata : IFormatFrameMetadata +{ + /// + /// Initializes a new instance of the class. + /// + public CurFrameMetadata() + { + } + + private CurFrameMetadata(CurFrameMetadata other) + { + this.Compression = other.Compression; + this.HotspotX = other.HotspotX; + this.HotspotY = other.HotspotY; + this.EncodingWidth = other.EncodingWidth; + this.EncodingHeight = other.EncodingHeight; + this.BmpBitsPerPixel = other.BmpBitsPerPixel; + } + + /// + /// Gets or sets the frame compressions format. + /// + public IconFrameCompression Compression { get; set; } + + /// + /// Gets or sets the horizontal coordinates of the hotspot in number of pixels from the left. + /// + public ushort HotspotX { get; set; } + + /// + /// Gets or sets the vertical coordinates of the hotspot in number of pixels from the top. + /// + public ushort HotspotY { get; set; } + + /// + /// Gets or sets the encoding width.
+ /// Can be any number between 0 and 255. Value 0 means a frame height of 256 pixels or greater. + ///
+ public byte EncodingWidth { get; set; } + + /// + /// Gets or sets the encoding height.
+ /// Can be any number between 0 and 255. Value 0 means a frame height of 256 pixels or greater. + ///
+ public byte EncodingHeight { get; set; } + + /// + /// Gets or sets the number of bits per pixel.
+ /// Used when is + ///
+ public BmpBitsPerPixel BmpBitsPerPixel { get; set; } = BmpBitsPerPixel.Bit32; + + /// + /// Gets or sets the color table, if any. + /// The underlying pixel format is represented by . + /// + public ReadOnlyMemory? ColorTable { get; set; } + + /// + public static CurFrameMetadata FromFormatConnectingFrameMetadata(FormatConnectingFrameMetadata metadata) + { + if (!metadata.PixelTypeInfo.HasValue) + { + return new CurFrameMetadata + { + BmpBitsPerPixel = BmpBitsPerPixel.Bit32, + Compression = IconFrameCompression.Png + }; + } + + byte encodingWidth = metadata.EncodingWidth switch + { + > 255 => 0, + <= 255 and >= 1 => (byte)metadata.EncodingWidth, + _ => 0 + }; + + byte encodingHeight = metadata.EncodingHeight switch + { + > 255 => 0, + <= 255 and >= 1 => (byte)metadata.EncodingHeight, + _ => 0 + }; + + int bpp = metadata.PixelTypeInfo.Value.BitsPerPixel; + BmpBitsPerPixel bbpp = bpp switch + { + 1 => BmpBitsPerPixel.Bit1, + 2 => BmpBitsPerPixel.Bit2, + <= 4 => BmpBitsPerPixel.Bit4, + <= 8 => BmpBitsPerPixel.Bit8, + <= 16 => BmpBitsPerPixel.Bit16, + <= 24 => BmpBitsPerPixel.Bit24, + _ => BmpBitsPerPixel.Bit32 + }; + + IconFrameCompression compression = IconFrameCompression.Bmp; + if (bbpp is BmpBitsPerPixel.Bit32) + { + compression = IconFrameCompression.Png; + } + + return new CurFrameMetadata + { + BmpBitsPerPixel = bbpp, + Compression = compression, + EncodingWidth = encodingWidth, + EncodingHeight = encodingHeight, + ColorTable = compression == IconFrameCompression.Bmp ? metadata.ColorTable : null + }; + } + + /// + public FormatConnectingFrameMetadata ToFormatConnectingFrameMetadata() + => new() + { + PixelTypeInfo = this.GetPixelTypeInfo(), + ColorTable = this.ColorTable, + EncodingWidth = this.EncodingWidth, + EncodingHeight = this.EncodingHeight + }; + + /// + IDeepCloneable IDeepCloneable.DeepClone() => this.DeepClone(); + + /// + public CurFrameMetadata DeepClone() => new(this); + + internal void FromIconDirEntry(IconDirEntry entry) + { + this.EncodingWidth = entry.Width; + this.EncodingHeight = entry.Height; + this.HotspotX = entry.Planes; + this.HotspotY = entry.BitCount; + } + + internal IconDirEntry ToIconDirEntry() + { + byte colorCount = this.Compression == IconFrameCompression.Png || this.BmpBitsPerPixel > BmpBitsPerPixel.Bit8 + ? (byte)0 + : (byte)ColorNumerics.GetColorCountForBitDepth((int)this.BmpBitsPerPixel); + + return new() + { + Width = this.EncodingWidth, + Height = this.EncodingHeight, + Planes = this.HotspotX, + BitCount = this.HotspotY, + ColorCount = colorCount + }; + } + + private PixelTypeInfo GetPixelTypeInfo() + { + int bpp = (int)this.BmpBitsPerPixel; + PixelComponentInfo info; + PixelColorType color; + PixelAlphaRepresentation alpha = PixelAlphaRepresentation.None; + + if (this.Compression is IconFrameCompression.Png) + { + bpp = 32; + info = PixelComponentInfo.Create(4, bpp, 8, 8, 8, 8); + color = PixelColorType.RGB | PixelColorType.Alpha; + alpha = PixelAlphaRepresentation.Unassociated; + } + else + { + switch (this.BmpBitsPerPixel) + { + case BmpBitsPerPixel.Bit1: + info = PixelComponentInfo.Create(1, bpp, 1); + color = PixelColorType.Binary; + break; + case BmpBitsPerPixel.Bit2: + info = PixelComponentInfo.Create(1, bpp, 2); + color = PixelColorType.Indexed; + break; + case BmpBitsPerPixel.Bit4: + info = PixelComponentInfo.Create(1, bpp, 4); + color = PixelColorType.Indexed; + break; + case BmpBitsPerPixel.Bit8: + info = PixelComponentInfo.Create(1, bpp, 8); + color = PixelColorType.Indexed; + break; + + // Could be 555 with padding but 565 is more common in newer bitmaps and offers + // greater accuracy due to extra green precision. + case BmpBitsPerPixel.Bit16: + info = PixelComponentInfo.Create(3, bpp, 5, 6, 5); + color = PixelColorType.RGB; + break; + case BmpBitsPerPixel.Bit24: + info = PixelComponentInfo.Create(3, bpp, 8, 8, 8); + color = PixelColorType.RGB; + break; + case BmpBitsPerPixel.Bit32 or _: + info = PixelComponentInfo.Create(4, bpp, 8, 8, 8, 8); + color = PixelColorType.RGB | PixelColorType.Alpha; + alpha = PixelAlphaRepresentation.Unassociated; + break; + } + } + + return new PixelTypeInfo(bpp) + { + AlphaRepresentation = alpha, + ComponentInfo = info, + ColorType = color + }; + } +} diff --git a/src/ImageSharp/Formats/Cur/CurMetadata.cs b/src/ImageSharp/Formats/Cur/CurMetadata.cs new file mode 100644 index 0000000000..6e97a8584a --- /dev/null +++ b/src/ImageSharp/Formats/Cur/CurMetadata.cs @@ -0,0 +1,183 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.Formats.Bmp; +using SixLabors.ImageSharp.Formats.Icon; +using SixLabors.ImageSharp.PixelFormats; + +namespace SixLabors.ImageSharp.Formats.Cur; + +/// +/// Provides Cur specific metadata information for the image. +/// +public class CurMetadata : IFormatMetadata +{ + /// + /// Initializes a new instance of the class. + /// + public CurMetadata() + { + } + + private CurMetadata(CurMetadata other) + { + this.Compression = other.Compression; + this.HotspotX = other.HotspotX; + this.HotspotY = other.HotspotY; + this.EncodingWidth = other.EncodingWidth; + this.EncodingHeight = other.EncodingHeight; + this.BmpBitsPerPixel = other.BmpBitsPerPixel; + + if (other.ColorTable?.Length > 0) + { + this.ColorTable = other.ColorTable.Value.ToArray(); + } + } + + /// + /// Gets or sets the frame compressions format. Derived from the root frame. + /// + public IconFrameCompression Compression { get; set; } + + /// + /// Gets or sets the horizontal coordinates of the hotspot in number of pixels from the left. Derived from the root frame. + /// + public ushort HotspotX { get; set; } + + /// + /// Gets or sets the vertical coordinates of the hotspot in number of pixels from the top. Derived from the root frame. + /// + public ushort HotspotY { get; set; } + + /// + /// Gets or sets the encoding width.
+ /// Can be any number between 0 and 255. Value 0 means a frame height of 256 pixels or greater. Derived from the root frame. + ///
+ public byte EncodingWidth { get; set; } + + /// + /// Gets or sets the encoding height.
+ /// Can be any number between 0 and 255. Value 0 means a frame height of 256 pixels or greater. Derived from the root frame. + ///
+ public byte EncodingHeight { get; set; } + + /// + /// Gets or sets the number of bits per pixel.
+ /// Used when is + ///
+ public BmpBitsPerPixel BmpBitsPerPixel { get; set; } = BmpBitsPerPixel.Bit32; + + /// + /// Gets or sets the color table, if any. Derived from the root frame.
+ /// The underlying pixel format is represented by . + ///
+ public ReadOnlyMemory? ColorTable { get; set; } + + /// + public static CurMetadata FromFormatConnectingMetadata(FormatConnectingMetadata metadata) + { + int bpp = metadata.PixelTypeInfo.BitsPerPixel; + BmpBitsPerPixel bbpp = bpp switch + { + 1 => BmpBitsPerPixel.Bit1, + 2 => BmpBitsPerPixel.Bit2, + <= 4 => BmpBitsPerPixel.Bit4, + <= 8 => BmpBitsPerPixel.Bit8, + <= 16 => BmpBitsPerPixel.Bit16, + <= 24 => BmpBitsPerPixel.Bit24, + _ => BmpBitsPerPixel.Bit32 + }; + + IconFrameCompression compression = IconFrameCompression.Bmp; + if (bbpp is BmpBitsPerPixel.Bit32) + { + compression = IconFrameCompression.Png; + } + + return new CurMetadata + { + BmpBitsPerPixel = bbpp, + Compression = compression, + ColorTable = compression == IconFrameCompression.Bmp ? metadata.ColorTable : null + }; + } + + /// + public PixelTypeInfo GetPixelTypeInfo() + { + int bpp = (int)this.BmpBitsPerPixel; + PixelComponentInfo info; + PixelColorType color; + PixelAlphaRepresentation alpha = PixelAlphaRepresentation.None; + + if (this.Compression is IconFrameCompression.Png) + { + bpp = 32; + info = PixelComponentInfo.Create(4, bpp, 8, 8, 8, 8); + color = PixelColorType.RGB | PixelColorType.Alpha; + alpha = PixelAlphaRepresentation.Unassociated; + } + else + { + switch (this.BmpBitsPerPixel) + { + case BmpBitsPerPixel.Bit1: + info = PixelComponentInfo.Create(1, bpp, 1); + color = PixelColorType.Binary; + break; + case BmpBitsPerPixel.Bit2: + info = PixelComponentInfo.Create(1, bpp, 2); + color = PixelColorType.Indexed; + break; + case BmpBitsPerPixel.Bit4: + info = PixelComponentInfo.Create(1, bpp, 4); + color = PixelColorType.Indexed; + break; + case BmpBitsPerPixel.Bit8: + info = PixelComponentInfo.Create(1, bpp, 8); + color = PixelColorType.Indexed; + break; + + // Could be 555 with padding but 565 is more common in newer bitmaps and offers + // greater accuracy due to extra green precision. + case BmpBitsPerPixel.Bit16: + info = PixelComponentInfo.Create(3, bpp, 5, 6, 5); + color = PixelColorType.RGB; + break; + case BmpBitsPerPixel.Bit24: + info = PixelComponentInfo.Create(3, bpp, 8, 8, 8); + color = PixelColorType.RGB; + break; + case BmpBitsPerPixel.Bit32 or _: + info = PixelComponentInfo.Create(4, bpp, 8, 8, 8, 8); + color = PixelColorType.RGB | PixelColorType.Alpha; + alpha = PixelAlphaRepresentation.Unassociated; + break; + } + } + + return new PixelTypeInfo(bpp) + { + AlphaRepresentation = alpha, + ComponentInfo = info, + ColorType = color + }; + } + + /// + public FormatConnectingMetadata ToFormatConnectingMetadata() + => new() + { + EncodingType = this.Compression == IconFrameCompression.Bmp && this.BmpBitsPerPixel <= BmpBitsPerPixel.Bit8 + ? EncodingType.Lossy + : EncodingType.Lossless, + PixelTypeInfo = this.GetPixelTypeInfo(), + ColorTable = this.ColorTable + }; + + /// + IDeepCloneable IDeepCloneable.DeepClone() => this.DeepClone(); + + /// + public CurMetadata DeepClone() => new(this); +} diff --git a/src/ImageSharp/Formats/DecoderOptions.cs b/src/ImageSharp/Formats/DecoderOptions.cs index 6243a071d5..3b16159b7e 100644 --- a/src/ImageSharp/Formats/DecoderOptions.cs +++ b/src/ImageSharp/Formats/DecoderOptions.cs @@ -55,5 +55,10 @@ public sealed class DecoderOptions ///
public uint MaxFrames { get => this.maxFrames; init => this.maxFrames = Math.Clamp(value, 1, int.MaxValue); } + /// + /// Gets the segment error handling strategy to use during decoding. + /// + public SegmentIntegrityHandling SegmentIntegrityHandling { get; init; } = SegmentIntegrityHandling.IgnoreNonCritical; + internal void SetConfiguration(Configuration configuration) => this.configuration = configuration; } diff --git a/src/ImageSharp/Formats/EncodingType.cs b/src/ImageSharp/Formats/EncodingType.cs new file mode 100644 index 0000000000..f4567ca43d --- /dev/null +++ b/src/ImageSharp/Formats/EncodingType.cs @@ -0,0 +1,20 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +namespace SixLabors.ImageSharp.Formats; + +/// +/// Provides a way to specify the type of encoding to be used. +/// +public enum EncodingType +{ + /// + /// Lossless encoding, which compresses data without any loss of information. + /// + Lossless, + + /// + /// Lossy encoding, which compresses data by discarding some of it. + /// + Lossy +} diff --git a/src/ImageSharp/Formats/FormatConnectingFrameMetadata.cs b/src/ImageSharp/Formats/FormatConnectingFrameMetadata.cs new file mode 100644 index 0000000000..ded220c9ad --- /dev/null +++ b/src/ImageSharp/Formats/FormatConnectingFrameMetadata.cs @@ -0,0 +1,54 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.PixelFormats; + +namespace SixLabors.ImageSharp.Formats; + +/// +/// A metadata format designed to allow conversion between different image format frames. +/// +public class FormatConnectingFrameMetadata +{ + /// + /// Gets information about the encoded pixel type if any. + /// + public PixelTypeInfo? PixelTypeInfo { get; init; } + + /// + /// Gets the frame color table if any. + /// + public ReadOnlyMemory? ColorTable { get; init; } + + /// + /// Gets the frame color table mode. + /// + public FrameColorTableMode ColorTableMode { get; init; } + + /// + /// Gets the duration of the frame. + /// + public TimeSpan Duration { get; init; } + + /// + /// Gets the frame alpha blending mode. + /// + public FrameBlendMode BlendMode { get; init; } + + /// + /// Gets the frame disposal mode. + /// + public FrameDisposalMode DisposalMode { get; init; } + + /// + /// Gets or sets the encoding width.
+ /// Used for formats that require a specific frame size. + ///
+ public int? EncodingWidth { get; set; } + + /// + /// Gets or sets the encoding height.
+ /// Used for formats that require a specific frame size. + ///
+ public int? EncodingHeight { get; set; } +} diff --git a/src/ImageSharp/Formats/FormatConnectingMetadata.cs b/src/ImageSharp/Formats/FormatConnectingMetadata.cs new file mode 100644 index 0000000000..baf0a35457 --- /dev/null +++ b/src/ImageSharp/Formats/FormatConnectingMetadata.cs @@ -0,0 +1,70 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.PixelFormats; + +namespace SixLabors.ImageSharp.Formats; + +/// +/// A metadata format designed to allow conversion between different image formats. +/// +public class FormatConnectingMetadata +{ + /// + /// Gets the encoding type. + /// + public EncodingType EncodingType { get; init; } + + /// + /// Gets the quality to use when is . + /// + /// + /// The value is usually between 1 and 100. Defaults to 100. + /// + public int Quality { get; init; } = 100; + + /// + /// Gets information about the encoded pixel type. + /// + public PixelTypeInfo PixelTypeInfo { get; init; } + + /// + /// Gets the shared color table if any. + /// + public ReadOnlyMemory? ColorTable { get; init; } + + /// + /// Gets the shared color table mode. + /// + /// + /// Defaults to . + /// + public FrameColorTableMode ColorTableMode { get; init; } = FrameColorTableMode.Global; + + /// + /// Gets the default background color of the canvas when animating. + /// This color may be used to fill the unused space on the canvas around the frames, + /// as well as the transparent pixels of the first frame. + /// The background color is also used when the disposal mode is . + /// + /// + /// Defaults to . + /// + public Color BackgroundColor { get; init; } = Color.Transparent; + + /// + /// Gets the number of times any animation is repeated. + /// + /// + /// 0 means to repeat indefinitely, count is set as repeat n-1 times. Defaults to 1. + /// + public ushort RepeatCount { get; init; } = 1; + + /// + /// Gets a value indicating whether the root frame is shown as part of the animated sequence. + /// + /// + /// Defaults to . + /// + public bool AnimateRootFrame { get; init; } = true; +} diff --git a/src/ImageSharp/Formats/FrameBlendMode.cs b/src/ImageSharp/Formats/FrameBlendMode.cs new file mode 100644 index 0000000000..5785324e5a --- /dev/null +++ b/src/ImageSharp/Formats/FrameBlendMode.cs @@ -0,0 +1,23 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +namespace SixLabors.ImageSharp.Formats; + +/// +/// Provides a way to specify how the current frame should be blended with the previous frame in the animation sequence. +/// +public enum FrameBlendMode +{ + /// + /// Do not blend. Render the current frame on the canvas by overwriting the rectangle covered by the current frame. + /// + Source = 0, + + /// + /// Blend the current frame with the previous frame in the animation sequence within the rectangle covered + /// by the current frame. + /// If the current has any transparent areas, the corresponding areas of the previous frame will be visible + /// through these transparent regions. + /// + Over = 1 +} diff --git a/src/ImageSharp/Formats/FrameColorTableMode.cs b/src/ImageSharp/Formats/FrameColorTableMode.cs new file mode 100644 index 0000000000..a45b6de0e4 --- /dev/null +++ b/src/ImageSharp/Formats/FrameColorTableMode.cs @@ -0,0 +1,20 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +namespace SixLabors.ImageSharp.Formats; + +/// +/// Provides a way to specify how the color table is used by the frame. +/// +public enum FrameColorTableMode +{ + /// + /// The frame uses the shared color table specified by the image metadata. + /// + Global, + + /// + /// The frame uses a color table specified by the frame metadata. + /// + Local +} diff --git a/src/ImageSharp/Formats/FrameDisposalMode.cs b/src/ImageSharp/Formats/FrameDisposalMode.cs new file mode 100644 index 0000000000..196fdb5ad4 --- /dev/null +++ b/src/ImageSharp/Formats/FrameDisposalMode.cs @@ -0,0 +1,38 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +namespace SixLabors.ImageSharp.Formats; + +/// +/// Provides a way to specify how the current frame should be disposed of before rendering the next frame. +/// +public enum FrameDisposalMode +{ + /// + /// No disposal specified. + /// The decoder is not required to take any action. + /// + Unspecified = 0, + + /// + /// Do not dispose. The current frame is not disposed of, or in other words, not cleared or altered when moving to + /// the next frame. This means that the next frame is drawn over the current frame, and if the next frame contains + /// transparency, the previous frame will be visible through these transparent areas. + /// + DoNotDispose = 1, + + /// + /// Restore to background color. When transitioning to the next frame, the area occupied by the current frame is + /// filled with the background color specified in the image metadata. + /// This effectively erases the current frame by replacing it with the background color before the next frame is displayed. + /// + RestoreToBackground = 2, + + /// + /// Restore to previous. This method restores the area affected by the current frame to what it was before the + /// current frame was displayed. It essentially "undoes" the current frame, reverting to the state of the image + /// before the frame was displayed, then the next frame is drawn. This is useful for animations where only a small + /// part of the image changes from frame to frame. + /// + RestoreToPrevious = 3 +} diff --git a/src/ImageSharp/Formats/Gif/GifColorTableMode.cs b/src/ImageSharp/Formats/Gif/GifColorTableMode.cs deleted file mode 100644 index 0f65f46022..0000000000 --- a/src/ImageSharp/Formats/Gif/GifColorTableMode.cs +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -namespace SixLabors.ImageSharp.Formats.Gif; - -/// -/// Provides enumeration for the available color table modes. -/// -public enum GifColorTableMode -{ - /// - /// A single color table is calculated from the first frame and reused for subsequent frames. - /// - Global, - - /// - /// A unique color table is calculated for each frame. - /// - Local -} diff --git a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs index 68f4e5fa2d..a99b5862dd 100644 --- a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs @@ -178,7 +178,7 @@ protected override ImageInfo Identify(BufferedReadStream stream, CancellationTok { uint frameCount = 0; ImageFrameMetadata? previousFrame = null; - List framesMetadata = new(); + List framesMetadata = []; try { this.ReadLogicalScreenDescriptorAndGlobalColorTable(stream); @@ -242,7 +242,6 @@ protected override ImageInfo Identify(BufferedReadStream stream, CancellationTok } return new ImageInfo( - new PixelTypeInfo(this.logicalScreenDescriptor.BitsPerPixel), new(this.logicalScreenDescriptor.Width, this.logicalScreenDescriptor.Height), this.metadata, framesMetadata); @@ -493,7 +492,7 @@ private void ReadFrameColors( } else { - if (this.graphicsControlExtension.DisposalMethod == GifDisposalMethod.RestoreToPrevious) + if (this.graphicsControlExtension.DisposalMethod == FrameDisposalMode.RestoreToPrevious) { prevFrame = previousFrame; } @@ -581,9 +580,7 @@ private void ReadFrameColors( for (int x = descriptorLeft; x < descriptorRight && x < imageWidth; x++) { int index = Numerics.Clamp(Unsafe.Add(ref indicesRowRef, (uint)(x - descriptorLeft)), 0, colorTableMaxIdx); - ref TPixel pixel = ref Unsafe.Add(ref rowRef, (uint)x); - Rgb24 rgb = colorTable[index]; - pixel.FromRgb24(rgb); + Unsafe.Add(ref rowRef, (uint)x) = TPixel.FromRgb24(colorTable[index]); } } else @@ -598,9 +595,7 @@ private void ReadFrameColors( continue; } - ref TPixel pixel = ref Unsafe.Add(ref rowRef, (uint)x); - Rgb24 rgb = colorTable[index]; - pixel.FromRgb24(rgb); + Unsafe.Add(ref rowRef, (uint)x) = TPixel.FromRgb24(colorTable[index]); } } } @@ -614,7 +609,7 @@ private void ReadFrameColors( previousFrame = currentFrame ?? image.Frames.RootFrame; - if (this.graphicsControlExtension.DisposalMethod == GifDisposalMethod.RestoreToBackground) + if (this.graphicsControlExtension.DisposalMethod == FrameDisposalMode.RestoreToBackground) { this.restoreArea = new Rectangle(descriptor.Left, descriptor.Top, descriptor.Width, descriptor.Height); } @@ -689,21 +684,18 @@ private void SetFrameMetadata(ImageFrameMetadata metadata) && this.logicalScreenDescriptor.GlobalColorTableSize > 0) { GifFrameMetadata gifMeta = metadata.GetGifMetadata(); - gifMeta.ColorTableMode = GifColorTableMode.Global; + gifMeta.ColorTableMode = FrameColorTableMode.Global; } if (this.imageDescriptor.LocalColorTableFlag && this.imageDescriptor.LocalColorTableSize > 0) { GifFrameMetadata gifMeta = metadata.GetGifMetadata(); - gifMeta.ColorTableMode = GifColorTableMode.Local; + gifMeta.ColorTableMode = FrameColorTableMode.Local; Color[] colorTable = new Color[this.imageDescriptor.LocalColorTableSize]; ReadOnlySpan rgbTable = MemoryMarshal.Cast(this.currentLocalColorTable!.GetSpan()[..this.currentLocalColorTableSize]); - for (int i = 0; i < colorTable.Length; i++) - { - colorTable[i] = new Color(rgbTable[i]); - } + Color.FromPixel(rgbTable, colorTable); gifMeta.LocalColorTable = colorTable; } @@ -715,7 +707,7 @@ private void SetFrameMetadata(ImageFrameMetadata metadata) gifMeta.HasTransparency = this.graphicsControlExtension.TransparencyFlag; gifMeta.TransparencyIndex = this.graphicsControlExtension.TransparencyIndex; gifMeta.FrameDelay = this.graphicsControlExtension.DelayTime; - gifMeta.DisposalMethod = this.graphicsControlExtension.DisposalMethod; + gifMeta.DisposalMode = this.graphicsControlExtension.DisposalMethod; } } @@ -762,8 +754,8 @@ private void ReadLogicalScreenDescriptorAndGlobalColorTable(BufferedReadStream s this.metadata = meta; this.gifMetadata = meta.GetGifMetadata(); this.gifMetadata.ColorTableMode = this.logicalScreenDescriptor.GlobalColorTableFlag - ? GifColorTableMode.Global - : GifColorTableMode.Local; + ? FrameColorTableMode.Global + : FrameColorTableMode.Local; if (this.logicalScreenDescriptor.GlobalColorTableFlag) { @@ -778,10 +770,7 @@ private void ReadLogicalScreenDescriptorAndGlobalColorTable(BufferedReadStream s Color[] colorTable = new Color[this.logicalScreenDescriptor.GlobalColorTableSize]; ReadOnlySpan rgbTable = MemoryMarshal.Cast(globalColorTableSpan); - for (int i = 0; i < colorTable.Length; i++) - { - colorTable[i] = new Color(rgbTable[i]); - } + Color.FromPixel(rgbTable, colorTable); this.gifMetadata.GlobalColorTable = colorTable; } diff --git a/src/ImageSharp/Formats/Gif/GifDisposalMethod.cs b/src/ImageSharp/Formats/Gif/GifDisposalMethod.cs deleted file mode 100644 index 12b4239c4f..0000000000 --- a/src/ImageSharp/Formats/Gif/GifDisposalMethod.cs +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -namespace SixLabors.ImageSharp.Formats.Gif; - -/// -/// Provides enumeration for instructing the decoder what to do with the last image -/// in an animation sequence. -/// section 23 -/// -public enum GifDisposalMethod -{ - /// - /// No disposal specified. - /// The decoder is not required to take any action. - /// - Unspecified = 0, - - /// - /// Do not dispose. - /// The graphic is to be left in place. - /// - NotDispose = 1, - - /// - /// Restore to background color. - /// The area used by the graphic must be restored to the background color. - /// - RestoreToBackground = 2, - - /// - /// Restore to previous. - /// The decoder is required to restore the area overwritten by the - /// graphic with what was there prior to rendering the graphic. - /// - RestoreToPrevious = 3 -} diff --git a/src/ImageSharp/Formats/Gif/GifEncoder.cs b/src/ImageSharp/Formats/Gif/GifEncoder.cs index ab05548ac5..6cb8f9d8ce 100644 --- a/src/ImageSharp/Formats/Gif/GifEncoder.cs +++ b/src/ImageSharp/Formats/Gif/GifEncoder.cs @@ -11,7 +11,7 @@ public sealed class GifEncoder : QuantizingImageEncoder /// /// Gets the color table mode: Global or local. /// - public GifColorTableMode? ColorTableMode { get; init; } + public FrameColorTableMode? ColorTableMode { get; init; } /// protected override void Encode(Image image, Stream stream, CancellationToken cancellationToken) diff --git a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs index 1daa713cbc..11185d90b0 100644 --- a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs @@ -5,8 +5,6 @@ using System.Numerics; using System.Runtime.CompilerServices; using SixLabors.ImageSharp.Advanced; -using SixLabors.ImageSharp.Formats.Png; -using SixLabors.ImageSharp.Formats.Webp; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Metadata; using SixLabors.ImageSharp.Metadata.Profiles.Xmp; @@ -49,7 +47,7 @@ internal sealed class GifEncoderCore /// /// The color table mode: Global or local. /// - private GifColorTableMode? colorTableMode; + private FrameColorTableMode? colorTableMode; /// /// The pixel sampling strategy for global quantization. @@ -85,9 +83,9 @@ public void Encode(Image image, Stream stream, CancellationToken Guard.NotNull(image, nameof(image)); Guard.NotNull(stream, nameof(stream)); - GifMetadata gifMetadata = GetGifMetadata(image); + GifMetadata gifMetadata = image.Metadata.CloneGifMetadata(); this.colorTableMode ??= gifMetadata.ColorTableMode; - bool useGlobalTable = this.colorTableMode == GifColorTableMode.Global; + bool useGlobalTable = this.colorTableMode == FrameColorTableMode.Global; // Quantize the first image frame returning a palette. IndexedImageFrame? quantized = null; @@ -99,7 +97,7 @@ public void Encode(Image image, Stream stream, CancellationToken if (this.quantizer is null) { // Is this a gif with color information. If so use that, otherwise use octree. - if (gifMetadata.ColorTableMode == GifColorTableMode.Global && gifMetadata.GlobalColorTable?.Length > 0) + if (gifMetadata.ColorTableMode == FrameColorTableMode.Global && gifMetadata.GlobalColorTable?.Length > 0) { // We avoid dithering by default to preserve the original colors. int transparencyIndex = GetTransparentIndex(quantized, frameMetadata); @@ -169,65 +167,26 @@ public void Encode(Image image, Stream stream, CancellationToken this.EncodeFirstFrame(stream, frameMetadata, quantized); // Capture the global palette for reuse on subsequent frames and cleanup the quantized frame. - TPixel[] globalPalette = image.Frames.Count == 1 ? Array.Empty() : quantized.Palette.ToArray(); + TPixel[] globalPalette = image.Frames.Count == 1 ? [] : quantized.Palette.ToArray(); - this.EncodeAdditionalFrames(stream, image, globalPalette, derivedTransparencyIndex, frameMetadata.DisposalMethod); + this.EncodeAdditionalFrames(stream, image, globalPalette, derivedTransparencyIndex, frameMetadata.DisposalMode); stream.WriteByte(GifConstants.EndIntroducer); quantized?.Dispose(); } - private static GifMetadata GetGifMetadata(Image image) - where TPixel : unmanaged, IPixel - { - if (image.Metadata.TryGetGifMetadata(out GifMetadata? gif)) - { - return (GifMetadata)gif.DeepClone(); - } - - if (image.Metadata.TryGetPngMetadata(out PngMetadata? png)) - { - AnimatedImageMetadata ani = png.ToAnimatedImageMetadata(); - return GifMetadata.FromAnimatedMetadata(ani); - } - - if (image.Metadata.TryGetWebpMetadata(out WebpMetadata? webp)) - { - AnimatedImageMetadata ani = webp.ToAnimatedImageMetadata(); - return GifMetadata.FromAnimatedMetadata(ani); - } - - // Return explicit new instance so we do not mutate the original metadata. - return new(); - } - private static GifFrameMetadata GetGifFrameMetadata(ImageFrame frame, int transparencyIndex) where TPixel : unmanaged, IPixel { - GifFrameMetadata? metadata = null; - if (frame.Metadata.TryGetGifMetadata(out GifFrameMetadata? gif)) - { - metadata = (GifFrameMetadata)gif.DeepClone(); - } - else if (frame.Metadata.TryGetPngMetadata(out PngFrameMetadata? png)) - { - AnimatedImageFrameMetadata ani = png.ToAnimatedImageFrameMetadata(); - metadata = GifFrameMetadata.FromAnimatedMetadata(ani); - } - else if (frame.Metadata.TryGetWebpFrameMetadata(out WebpFrameMetadata? webp)) - { - AnimatedImageFrameMetadata ani = webp.ToAnimatedImageFrameMetadata(); - metadata = GifFrameMetadata.FromAnimatedMetadata(ani); - } - - if (metadata?.ColorTableMode == GifColorTableMode.Global && transparencyIndex > -1) + GifFrameMetadata metadata = frame.Metadata.CloneGifMetadata(); + if (metadata.ColorTableMode == FrameColorTableMode.Global && transparencyIndex > -1) { metadata.HasTransparency = true; metadata.TransparencyIndex = ClampIndex(transparencyIndex); } - return metadata ?? new(); + return metadata; } private void EncodeAdditionalFrames( @@ -235,7 +194,7 @@ private void EncodeAdditionalFrames( Image image, ReadOnlyMemory globalPalette, int globalTransparencyIndex, - GifDisposalMethod previousDisposalMethod) + FrameDisposalMode previousDisposalMode) where TPixel : unmanaged, IPixel { if (image.Frames.Count == 1) @@ -258,7 +217,7 @@ private void EncodeAdditionalFrames( ImageFrame currentFrame = image.Frames[i]; ImageFrame? nextFrame = i < image.Frames.Count - 1 ? image.Frames[i + 1] : null; GifFrameMetadata gifMetadata = GetGifFrameMetadata(currentFrame, globalTransparencyIndex); - bool useLocal = this.colorTableMode == GifColorTableMode.Local || (gifMetadata.ColorTableMode == GifColorTableMode.Local); + bool useLocal = this.colorTableMode == FrameColorTableMode.Local || (gifMetadata.ColorTableMode == FrameColorTableMode.Local); if (!useLocal && !hasPaletteQuantizer && i > 0) { @@ -279,10 +238,10 @@ private void EncodeAdditionalFrames( useLocal, gifMetadata, paletteQuantizer, - previousDisposalMethod); + previousDisposalMode); previousFrame = currentFrame; - previousDisposalMethod = gifMetadata.DisposalMethod; + previousDisposalMode = gifMetadata.DisposalMode; } if (hasPaletteQuantizer) @@ -301,7 +260,7 @@ private void EncodeFirstFrame( Buffer2D indices = ((IPixelSource)quantized).PixelBuffer; Rectangle interest = indices.FullRectangle(); - bool useLocal = this.colorTableMode == GifColorTableMode.Local || (metadata.ColorTableMode == GifColorTableMode.Local); + bool useLocal = this.colorTableMode == FrameColorTableMode.Local || (metadata.ColorTableMode == FrameColorTableMode.Local); int bitDepth = ColorNumerics.GetBitsNeededForColorDepth(quantized.Palette.Length); this.WriteImageDescriptor(interest, useLocal, bitDepth, stream); @@ -323,14 +282,14 @@ private void EncodeAdditionalFrame( bool useLocal, GifFrameMetadata metadata, PaletteQuantizer globalPaletteQuantizer, - GifDisposalMethod previousDisposal) + FrameDisposalMode previousDisposalMode) where TPixel : unmanaged, IPixel { // Capture any explicit transparency index from the metadata. // We use it to determine the value to use to replace duplicate pixels. int transparencyIndex = metadata.HasTransparency ? metadata.TransparencyIndex : -1; - ImageFrame? previous = previousDisposal == GifDisposalMethod.RestoreToBackground ? null : previousFrame; + ImageFrame? previous = previousDisposalMode == FrameDisposalMode.RestoreToBackground ? null : previousFrame; // Deduplicate and quantize the frame capturing only required parts. (bool difference, Rectangle bounds) = @@ -488,8 +447,7 @@ private static int GetTransparentIndex(IndexedImageFrame? quanti int index = -1; if (quantized != null) { - TPixel transparentPixel = default; - transparentPixel.FromScaledVector4(Vector4.Zero); + TPixel transparentPixel = TPixel.FromScaledVector4(Vector4.Zero); ReadOnlySpan palette = quantized.Palette.Span; // Transparent pixels are much more likely to be found at the end of a palette. @@ -665,7 +623,7 @@ private void WriteGraphicalControlExtension(GifFrameMetadata metadata, Stream st bool hasTransparency = metadata.HasTransparency; byte packedValue = GifGraphicControlExtension.GetPackedValue( - disposalMethod: metadata.DisposalMethod, + disposalMode: metadata.DisposalMode, transparencyFlag: hasTransparency); GifGraphicControlExtension extension = new( @@ -693,7 +651,7 @@ private void WriteExtension(TGifExtension extension, Stream strea } IMemoryOwner? owner = null; - Span extensionBuffer = stackalloc byte[0]; // workaround compiler limitation + scoped Span extensionBuffer = []; // workaround compiler limitation if (extensionSize > 128) { owner = this.memoryAllocator.Allocate(extensionSize + 3); diff --git a/src/ImageSharp/Formats/Gif/GifFrameMetadata.cs b/src/ImageSharp/Formats/Gif/GifFrameMetadata.cs index f8734bb5a3..f81329e973 100644 --- a/src/ImageSharp/Formats/Gif/GifFrameMetadata.cs +++ b/src/ImageSharp/Formats/Gif/GifFrameMetadata.cs @@ -9,7 +9,7 @@ namespace SixLabors.ImageSharp.Formats.Gif; /// /// Provides Gif specific metadata information for the image frame. /// -public class GifFrameMetadata : IDeepCloneable +public class GifFrameMetadata : IFormatFrameMetadata { /// /// Initializes a new instance of the class. @@ -26,7 +26,7 @@ private GifFrameMetadata(GifFrameMetadata other) { this.ColorTableMode = other.ColorTableMode; this.FrameDelay = other.FrameDelay; - this.DisposalMethod = other.DisposalMethod; + this.DisposalMode = other.DisposalMode; if (other.LocalColorTable?.Length > 0) { @@ -40,7 +40,7 @@ private GifFrameMetadata(GifFrameMetadata other) /// /// Gets or sets the color table mode. /// - public GifColorTableMode ColorTableMode { get; set; } + public FrameColorTableMode ColorTableMode { get; set; } /// /// Gets or sets the local color table, if any. @@ -73,22 +73,76 @@ private GifFrameMetadata(GifFrameMetadata other) /// Primarily used in Gif animation, this field indicates the way in which the graphic is to /// be treated after being displayed. /// - public GifDisposalMethod DisposalMethod { get; set; } + public FrameDisposalMode DisposalMode { get; set; } + + /// + public static GifFrameMetadata FromFormatConnectingFrameMetadata(FormatConnectingFrameMetadata metadata) + { + int index = -1; + const float background = 1f; + if (metadata.ColorTable.HasValue) + { + ReadOnlySpan colorTable = metadata.ColorTable.Value.Span; + for (int i = 0; i < colorTable.Length; i++) + { + Vector4 vector = colorTable[i].ToScaledVector4(); + if (vector.W < background) + { + index = i; + } + } + } + + bool hasTransparency = index >= 0; + + return new() + { + LocalColorTable = metadata.ColorTable, + ColorTableMode = metadata.ColorTableMode, + FrameDelay = (int)Math.Round(metadata.Duration.TotalMilliseconds / 10), + DisposalMode = metadata.DisposalMode, + HasTransparency = hasTransparency, + TransparencyIndex = hasTransparency ? unchecked((byte)index) : byte.MinValue, + }; + } + + /// + public FormatConnectingFrameMetadata ToFormatConnectingFrameMetadata() + { + // For most scenarios we would consider the blend method to be 'Over' however if a frame has a disposal method of 'RestoreToBackground' or + // has a local palette with 256 colors and is not transparent we should use 'Source'. + bool blendSource = this.DisposalMode == FrameDisposalMode.RestoreToBackground || (this.LocalColorTable?.Length == 256 && !this.HasTransparency); + + // If the color table is global and frame has no transparency. Consider it 'Source' also. + blendSource |= this.ColorTableMode == FrameColorTableMode.Global && !this.HasTransparency; + + return new() + { + ColorTable = this.LocalColorTable, + ColorTableMode = this.ColorTableMode, + Duration = TimeSpan.FromMilliseconds(this.FrameDelay * 10), + DisposalMode = this.DisposalMode, + BlendMode = blendSource ? FrameBlendMode.Source : FrameBlendMode.Over, + }; + } /// - public IDeepCloneable DeepClone() => new GifFrameMetadata(this); + IDeepCloneable IDeepCloneable.DeepClone() => this.DeepClone(); + + /// + public GifFrameMetadata DeepClone() => new(this); internal static GifFrameMetadata FromAnimatedMetadata(AnimatedImageFrameMetadata metadata) { // TODO: v4 How do I link the parent metadata to the frame metadata to get the global color table? int index = -1; - float background = 1f; + const float background = 1f; if (metadata.ColorTable.HasValue) { ReadOnlySpan colorTable = metadata.ColorTable.Value.Span; for (int i = 0; i < colorTable.Length; i++) { - Vector4 vector = (Vector4)colorTable[i]; + Vector4 vector = colorTable[i].ToScaledVector4(); if (vector.W < background) { index = i; @@ -101,19 +155,11 @@ internal static GifFrameMetadata FromAnimatedMetadata(AnimatedImageFrameMetadata return new() { LocalColorTable = metadata.ColorTable, - ColorTableMode = metadata.ColorTableMode == FrameColorTableMode.Global ? GifColorTableMode.Global : GifColorTableMode.Local, + ColorTableMode = metadata.ColorTableMode, FrameDelay = (int)Math.Round(metadata.Duration.TotalMilliseconds / 10), - DisposalMethod = GetMode(metadata.DisposalMode), + DisposalMode = metadata.DisposalMode, HasTransparency = hasTransparency, TransparencyIndex = hasTransparency ? unchecked((byte)index) : byte.MinValue, }; } - - private static GifDisposalMethod GetMode(FrameDisposalMode mode) => mode switch - { - FrameDisposalMode.DoNotDispose => GifDisposalMethod.NotDispose, - FrameDisposalMode.RestoreToBackground => GifDisposalMethod.RestoreToBackground, - FrameDisposalMode.RestoreToPrevious => GifDisposalMethod.RestoreToPrevious, - _ => GifDisposalMethod.Unspecified, - }; } diff --git a/src/ImageSharp/Formats/Gif/GifMetadata.cs b/src/ImageSharp/Formats/Gif/GifMetadata.cs index 1331edee89..565038b55a 100644 --- a/src/ImageSharp/Formats/Gif/GifMetadata.cs +++ b/src/ImageSharp/Formats/Gif/GifMetadata.cs @@ -8,7 +8,7 @@ namespace SixLabors.ImageSharp.Formats.Gif; /// /// Provides Gif specific metadata information for the image. /// -public class GifMetadata : IDeepCloneable +public class GifMetadata : IFormatMetadata { /// /// Initializes a new instance of the class. @@ -49,7 +49,7 @@ private GifMetadata(GifMetadata other) /// /// Gets or sets the color table mode. /// - public GifColorTableMode ColorTableMode { get; set; } + public FrameColorTableMode ColorTableMode { get; set; } /// /// Gets or sets the global color table, if any. @@ -67,12 +67,10 @@ private GifMetadata(GifMetadata other) /// Gets or sets the collection of comments about the graphics, credits, descriptions or any /// other type of non-control and non-graphic data. /// - public IList Comments { get; set; } = new List(); + public IList Comments { get; set; } = []; /// - public IDeepCloneable DeepClone() => new GifMetadata(this); - - internal static GifMetadata FromAnimatedMetadata(AnimatedImageMetadata metadata) + public static GifMetadata FromFormatConnectingMetadata(FormatConnectingMetadata metadata) { int index = 0; Color background = metadata.BackgroundColor; @@ -81,20 +79,60 @@ internal static GifMetadata FromAnimatedMetadata(AnimatedImageMetadata metadata) ReadOnlySpan colorTable = metadata.ColorTable.Value.Span; for (int i = 0; i < colorTable.Length; i++) { - if (background == colorTable[i]) + if (background != colorTable[i]) { - index = i; - break; + continue; } + + index = i; + break; } } return new() { GlobalColorTable = metadata.ColorTable, - ColorTableMode = metadata.ColorTableMode == FrameColorTableMode.Global ? GifColorTableMode.Global : GifColorTableMode.Local, + ColorTableMode = metadata.ColorTableMode, RepeatCount = metadata.RepeatCount, BackgroundColorIndex = (byte)Numerics.Clamp(index, 0, 255), }; } + + /// + public PixelTypeInfo GetPixelTypeInfo() + { + int bpp = this.GlobalColorTable.HasValue + ? Numerics.Clamp(ColorNumerics.GetBitsNeededForColorDepth(this.GlobalColorTable.Value.Length), 1, 8) + : 8; + + return new PixelTypeInfo(bpp) + { + ColorType = PixelColorType.Indexed, + ComponentInfo = PixelComponentInfo.Create(1, bpp, bpp), + }; + } + + /// + public FormatConnectingMetadata ToFormatConnectingMetadata() + { + Color color = this.GlobalColorTable.HasValue && this.GlobalColorTable.Value.Span.Length > this.BackgroundColorIndex + ? this.GlobalColorTable.Value.Span[this.BackgroundColorIndex] + : Color.Transparent; + + return new() + { + AnimateRootFrame = true, + BackgroundColor = color, + ColorTable = this.GlobalColorTable, + ColorTableMode = this.ColorTableMode, + PixelTypeInfo = this.GetPixelTypeInfo(), + RepeatCount = this.RepeatCount, + }; + } + + /// + IDeepCloneable IDeepCloneable.DeepClone() => this.DeepClone(); + + /// + public GifMetadata DeepClone() => new(this); } diff --git a/src/ImageSharp/Formats/Gif/MetadataExtensions.cs b/src/ImageSharp/Formats/Gif/MetadataExtensions.cs deleted file mode 100644 index ad06462e77..0000000000 --- a/src/ImageSharp/Formats/Gif/MetadataExtensions.cs +++ /dev/null @@ -1,105 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Diagnostics.CodeAnalysis; -using SixLabors.ImageSharp.Formats; -using SixLabors.ImageSharp.Formats.Gif; -using SixLabors.ImageSharp.Metadata; - -namespace SixLabors.ImageSharp; - -/// -/// Extension methods for the type. -/// -public static partial class MetadataExtensions -{ - /// - /// Gets the gif format specific metadata for the image. - /// - /// The metadata this method extends. - /// The . - public static GifMetadata GetGifMetadata(this ImageMetadata source) - => source.GetFormatMetadata(GifFormat.Instance); - - /// - /// Gets the gif format specific metadata for the image. - /// - /// The metadata this method extends. - /// - /// When this method returns, contains the metadata associated with the specified image, - /// if found; otherwise, the default value for the type of the metadata parameter. - /// This parameter is passed uninitialized. - /// - /// - /// if the gif metadata exists; otherwise, . - /// - public static bool TryGetGifMetadata(this ImageMetadata source, [NotNullWhen(true)] out GifMetadata? metadata) - => source.TryGetFormatMetadata(GifFormat.Instance, out metadata); - - /// - /// Gets the gif format specific metadata for the image frame. - /// - /// The metadata this method extends. - /// The . - public static GifFrameMetadata GetGifMetadata(this ImageFrameMetadata source) - => source.GetFormatMetadata(GifFormat.Instance); - - /// - /// Gets the gif format specific metadata for the image frame. - /// - /// The metadata this method extends. - /// - /// When this method returns, contains the metadata associated with the specified frame, - /// if found; otherwise, the default value for the type of the metadata parameter. - /// This parameter is passed uninitialized. - /// - /// - /// if the gif frame metadata exists; otherwise, . - /// - public static bool TryGetGifMetadata(this ImageFrameMetadata source, [NotNullWhen(true)] out GifFrameMetadata? metadata) - => source.TryGetFormatMetadata(GifFormat.Instance, out metadata); - - internal static AnimatedImageMetadata ToAnimatedImageMetadata(this GifMetadata source) - { - Color background = Color.Transparent; - if (source.GlobalColorTable != null) - { - background = source.GlobalColorTable.Value.Span[source.BackgroundColorIndex]; - } - - return new() - { - ColorTable = source.GlobalColorTable, - ColorTableMode = source.ColorTableMode == GifColorTableMode.Global ? FrameColorTableMode.Global : FrameColorTableMode.Local, - RepeatCount = source.RepeatCount, - BackgroundColor = background, - }; - } - - internal static AnimatedImageFrameMetadata ToAnimatedImageFrameMetadata(this GifFrameMetadata source) - { - // For most scenarios we would consider the blend method to be 'Over' however if a frame has a disposal method of 'RestoreToBackground' or - // has a local palette with 256 colors and is not transparent we should use 'Source'. - bool blendSource = source.DisposalMethod == GifDisposalMethod.RestoreToBackground || (source.LocalColorTable?.Length == 256 && !source.HasTransparency); - - // If the color table is global and frame has no transparency. Consider it 'Source' also. - blendSource |= source.ColorTableMode == GifColorTableMode.Global && !source.HasTransparency; - - return new() - { - ColorTable = source.LocalColorTable, - ColorTableMode = source.ColorTableMode == GifColorTableMode.Global ? FrameColorTableMode.Global : FrameColorTableMode.Local, - Duration = TimeSpan.FromMilliseconds(source.FrameDelay * 10), - DisposalMode = GetMode(source.DisposalMethod), - BlendMode = blendSource ? FrameBlendMode.Source : FrameBlendMode.Over, - }; - } - - private static FrameDisposalMode GetMode(GifDisposalMethod method) => method switch - { - GifDisposalMethod.NotDispose => FrameDisposalMode.DoNotDispose, - GifDisposalMethod.RestoreToBackground => FrameDisposalMode.RestoreToBackground, - GifDisposalMethod.RestoreToPrevious => FrameDisposalMode.RestoreToPrevious, - _ => FrameDisposalMode.Unspecified, - }; -} diff --git a/src/ImageSharp/Formats/Gif/Sections/GifGraphicControlExtension.cs b/src/ImageSharp/Formats/Gif/Sections/GifGraphicControlExtension.cs index 52052021fc..ad99ac0f42 100644 --- a/src/ImageSharp/Formats/Gif/Sections/GifGraphicControlExtension.cs +++ b/src/ImageSharp/Formats/Gif/Sections/GifGraphicControlExtension.cs @@ -52,7 +52,7 @@ public GifGraphicControlExtension( /// Gets the disposal method which indicates the way in which the /// graphic is to be treated after being displayed. /// - public GifDisposalMethod DisposalMethod => (GifDisposalMethod)((this.Packed & 0x1C) >> 2); + public FrameDisposalMode DisposalMethod => (FrameDisposalMode)((this.Packed & 0x1C) >> 2); /// /// Gets a value indicating whether transparency flag is to be set. @@ -80,7 +80,7 @@ public int WriteTo(Span buffer) public static GifGraphicControlExtension Parse(ReadOnlySpan buffer) => MemoryMarshal.Cast(buffer)[0]; - public static byte GetPackedValue(GifDisposalMethod disposalMethod, bool userInputFlag = false, bool transparencyFlag = false) + public static byte GetPackedValue(FrameDisposalMode disposalMode, bool userInputFlag = false, bool transparencyFlag = false) { /* Reserved | 3 Bits @@ -91,7 +91,7 @@ Transparent Color Flag | 1 Bit byte value = 0; - value |= (byte)((int)disposalMethod << 2); + value |= (byte)((int)disposalMode << 2); if (userInputFlag) { diff --git a/src/ImageSharp/Formats/IFormatFrameMetadata.cs b/src/ImageSharp/Formats/IFormatFrameMetadata.cs new file mode 100644 index 0000000000..4eef93ad34 --- /dev/null +++ b/src/ImageSharp/Formats/IFormatFrameMetadata.cs @@ -0,0 +1,33 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +namespace SixLabors.ImageSharp.Formats; + +/// +/// An interface that provides metadata for a specific image format frames. +/// +public interface IFormatFrameMetadata : IDeepCloneable +{ + /// + /// Converts the metadata to a instance. + /// + /// The . + FormatConnectingFrameMetadata ToFormatConnectingFrameMetadata(); +} + +/// +/// An interface that provides metadata for a specific image format frames. +/// +/// The metadata type implementing this interface. +public interface IFormatFrameMetadata : IFormatFrameMetadata, IDeepCloneable + where TSelf : class, IFormatFrameMetadata +{ + /// + /// Creates a new instance of the class from the given . + /// + /// The . + /// The . +#pragma warning disable CA1000 // Do not declare static members on generic types + static abstract TSelf FromFormatConnectingFrameMetadata(FormatConnectingFrameMetadata metadata); +#pragma warning restore CA1000 // Do not declare static members on generic types +} diff --git a/src/ImageSharp/Formats/IFormatMetadata.cs b/src/ImageSharp/Formats/IFormatMetadata.cs new file mode 100644 index 0000000000..8d695306e4 --- /dev/null +++ b/src/ImageSharp/Formats/IFormatMetadata.cs @@ -0,0 +1,41 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.PixelFormats; + +namespace SixLabors.ImageSharp.Formats; + +/// +/// An interface that provides metadata for a specific image format. +/// +public interface IFormatMetadata : IDeepCloneable +{ + /// + /// Converts the metadata to a instance. + /// + /// The pixel type info. + PixelTypeInfo GetPixelTypeInfo(); + + /// + /// Converts the metadata to a instance. + /// + /// The . + FormatConnectingMetadata ToFormatConnectingMetadata(); +} + +/// +/// An interface that provides metadata for a specific image format. +/// +/// The metadata type implementing this interface. +public interface IFormatMetadata : IFormatMetadata, IDeepCloneable + where TSelf : class, IFormatMetadata +{ + /// + /// Creates a new instance of the class from the given . + /// + /// The . + /// The . +#pragma warning disable CA1000 // Do not declare static members on generic types + static abstract TSelf FromFormatConnectingMetadata(FormatConnectingMetadata metadata); +#pragma warning restore CA1000 // Do not declare static members on generic types +} diff --git a/src/ImageSharp/Formats/IImageFormat.cs b/src/ImageSharp/Formats/IImageFormat.cs index b983219777..5c579eb4f6 100644 --- a/src/ImageSharp/Formats/IImageFormat.cs +++ b/src/ImageSharp/Formats/IImageFormat.cs @@ -1,4 +1,4 @@ -// Copyright (c) Six Labors. +// Copyright (c) Six Labors. // Licensed under the Six Labors Split License. namespace SixLabors.ImageSharp.Formats; @@ -14,12 +14,12 @@ public interface IImageFormat string Name { get; } /// - /// Gets the default mimetype that the image format uses + /// Gets the default mime type that the image format uses /// string DefaultMimeType { get; } /// - /// Gets all the mimetypes that have been used by this image format. + /// Gets all the mime types that have been used by this image format. /// IEnumerable MimeTypes { get; } diff --git a/src/ImageSharp/Formats/Ico/IcoConfigurationModule.cs b/src/ImageSharp/Formats/Ico/IcoConfigurationModule.cs new file mode 100644 index 0000000000..224aaa31ec --- /dev/null +++ b/src/ImageSharp/Formats/Ico/IcoConfigurationModule.cs @@ -0,0 +1,20 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.Formats.Icon; + +namespace SixLabors.ImageSharp.Formats.Ico; + +/// +/// Registers the image encoders, decoders and mime type detectors for the Ico format. +/// +public sealed class IcoConfigurationModule : IImageFormatConfigurationModule +{ + /// + public void Configure(Configuration configuration) + { + configuration.ImageFormatsManager.SetEncoder(IcoFormat.Instance, new IcoEncoder()); + configuration.ImageFormatsManager.SetDecoder(IcoFormat.Instance, IcoDecoder.Instance); + configuration.ImageFormatsManager.AddImageFormatDetector(new IconImageFormatDetector()); + } +} diff --git a/src/ImageSharp/Formats/Ico/IcoConstants.cs b/src/ImageSharp/Formats/Ico/IcoConstants.cs new file mode 100644 index 0000000000..1165793688 --- /dev/null +++ b/src/ImageSharp/Formats/Ico/IcoConstants.cs @@ -0,0 +1,39 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +namespace SixLabors.ImageSharp.Formats.Ico; + +/// +/// Defines constants relating to ICOs +/// +internal static class IcoConstants +{ + /// + /// The list of mime types that equate to a ico. + /// + /// + /// See + /// + public static readonly IEnumerable MimeTypes = + [ + + // IANA-registered + "image/vnd.microsoft.icon", + + // ICO & CUR types used by Windows + "image/x-icon", + + // Erroneous types but have been used + "image/ico", + "image/icon", + "text/ico", + "application/ico", + ]; + + /// + /// The list of file extensions that equate to a ico. + /// + public static readonly IEnumerable FileExtensions = ["ico"]; + + public const uint FileHeader = 0x00_01_00_00; +} diff --git a/src/ImageSharp/Formats/Ico/IcoDecoder.cs b/src/ImageSharp/Formats/Ico/IcoDecoder.cs new file mode 100644 index 0000000000..a0c8a30752 --- /dev/null +++ b/src/ImageSharp/Formats/Ico/IcoDecoder.cs @@ -0,0 +1,47 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.PixelFormats; + +namespace SixLabors.ImageSharp.Formats.Ico; + +/// +/// Decoder for generating an image out of a ico encoded stream. +/// +public sealed class IcoDecoder : ImageDecoder +{ + private IcoDecoder() + { + } + + /// + /// Gets the shared instance. + /// + public static IcoDecoder Instance { get; } = new(); + + /// + protected override Image Decode(DecoderOptions options, Stream stream, CancellationToken cancellationToken) + { + Guard.NotNull(options, nameof(options)); + Guard.NotNull(stream, nameof(stream)); + + Image image = new IcoDecoderCore(options).Decode(options.Configuration, stream, cancellationToken); + + ScaleToTargetSize(options, image); + + return image; + } + + /// + protected override Image Decode(DecoderOptions options, Stream stream, CancellationToken cancellationToken) + => this.Decode(options, stream, cancellationToken); + + /// + protected override ImageInfo Identify(DecoderOptions options, Stream stream, CancellationToken cancellationToken) + { + Guard.NotNull(options, nameof(options)); + Guard.NotNull(stream, nameof(stream)); + + return new IcoDecoderCore(options).Identify(options.Configuration, stream, cancellationToken); + } +} diff --git a/src/ImageSharp/Formats/Ico/IcoDecoderCore.cs b/src/ImageSharp/Formats/Ico/IcoDecoderCore.cs new file mode 100644 index 0000000000..8b59974eb3 --- /dev/null +++ b/src/ImageSharp/Formats/Ico/IcoDecoderCore.cs @@ -0,0 +1,42 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.Formats.Bmp; +using SixLabors.ImageSharp.Formats.Icon; +using SixLabors.ImageSharp.Metadata; + +namespace SixLabors.ImageSharp.Formats.Ico; + +internal sealed class IcoDecoderCore : IconDecoderCore +{ + public IcoDecoderCore(DecoderOptions options) + : base(options) + { + } + + protected override void SetFrameMetadata( + ImageMetadata imageMetadata, + ImageFrameMetadata frameMetadata, + int index, + in IconDirEntry entry, + IconFrameCompression compression, + BmpBitsPerPixel bitsPerPixel, + ReadOnlyMemory? colorTable) + { + IcoFrameMetadata icoFrameMetadata = frameMetadata.GetIcoMetadata(); + icoFrameMetadata.FromIconDirEntry(entry); + icoFrameMetadata.Compression = compression; + icoFrameMetadata.BmpBitsPerPixel = bitsPerPixel; + icoFrameMetadata.ColorTable = colorTable; + + if (index == 0) + { + IcoMetadata curMetadata = imageMetadata.GetIcoMetadata(); + curMetadata.Compression = compression; + curMetadata.BmpBitsPerPixel = bitsPerPixel; + curMetadata.ColorTable = colorTable; + curMetadata.EncodingWidth = icoFrameMetadata.EncodingWidth; + curMetadata.EncodingHeight = icoFrameMetadata.EncodingHeight; + } + } +} diff --git a/src/ImageSharp/Formats/Ico/IcoEncoder.cs b/src/ImageSharp/Formats/Ico/IcoEncoder.cs new file mode 100644 index 0000000000..e729251567 --- /dev/null +++ b/src/ImageSharp/Formats/Ico/IcoEncoder.cs @@ -0,0 +1,17 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +namespace SixLabors.ImageSharp.Formats.Ico; + +/// +/// Image encoder for writing an image to a stream as a Windows Icon. +/// +public sealed class IcoEncoder : QuantizingImageEncoder +{ + /// + protected override void Encode(Image image, Stream stream, CancellationToken cancellationToken) + { + IcoEncoderCore encoderCore = new(this); + encoderCore.Encode(image, stream, cancellationToken); + } +} diff --git a/src/ImageSharp/Formats/Ico/IcoEncoderCore.cs b/src/ImageSharp/Formats/Ico/IcoEncoderCore.cs new file mode 100644 index 0000000000..f3cacb1b96 --- /dev/null +++ b/src/ImageSharp/Formats/Ico/IcoEncoderCore.cs @@ -0,0 +1,14 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.Formats.Icon; + +namespace SixLabors.ImageSharp.Formats.Ico; + +internal sealed class IcoEncoderCore : IconEncoderCore +{ + public IcoEncoderCore(QuantizingImageEncoder encoder) + : base(encoder, IconFileType.ICO) + { + } +} diff --git a/src/ImageSharp/Formats/Ico/IcoFormat.cs b/src/ImageSharp/Formats/Ico/IcoFormat.cs new file mode 100644 index 0000000000..5f89ab7f28 --- /dev/null +++ b/src/ImageSharp/Formats/Ico/IcoFormat.cs @@ -0,0 +1,37 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +namespace SixLabors.ImageSharp.Formats.Ico; + +/// +/// Registers the image encoders, decoders and mime type detectors for the ICO format. +/// +public sealed class IcoFormat : IImageFormat +{ + private IcoFormat() + { + } + + /// + /// Gets the shared instance. + /// + public static IcoFormat Instance { get; } = new(); + + /// + public string Name => "ICO"; + + /// + public string DefaultMimeType => IcoConstants.MimeTypes.First(); + + /// + public IEnumerable MimeTypes => IcoConstants.MimeTypes; + + /// + public IEnumerable FileExtensions => IcoConstants.FileExtensions; + + /// + public IcoMetadata CreateDefaultFormatMetadata() => new(); + + /// + public IcoFrameMetadata CreateDefaultFormatFrameMetadata() => new(); +} diff --git a/src/ImageSharp/Formats/Ico/IcoFrameMetadata.cs b/src/ImageSharp/Formats/Ico/IcoFrameMetadata.cs new file mode 100644 index 0000000000..c244e38981 --- /dev/null +++ b/src/ImageSharp/Formats/Ico/IcoFrameMetadata.cs @@ -0,0 +1,220 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.Formats.Bmp; +using SixLabors.ImageSharp.Formats.Icon; +using SixLabors.ImageSharp.PixelFormats; + +namespace SixLabors.ImageSharp.Formats.Ico; + +/// +/// Provides Ico specific metadata information for the image frame. +/// +public class IcoFrameMetadata : IFormatFrameMetadata +{ + /// + /// Initializes a new instance of the class. + /// + public IcoFrameMetadata() + { + } + + private IcoFrameMetadata(IcoFrameMetadata other) + { + this.Compression = other.Compression; + this.EncodingWidth = other.EncodingWidth; + this.EncodingHeight = other.EncodingHeight; + this.BmpBitsPerPixel = other.BmpBitsPerPixel; + + if (other.ColorTable?.Length > 0) + { + this.ColorTable = other.ColorTable.Value.ToArray(); + } + } + + /// + /// Gets or sets the frame compressions format. + /// + public IconFrameCompression Compression { get; set; } + + /// + /// Gets or sets the encoding width.
+ /// Can be any number between 0 and 255. Value 0 means a frame height of 256 pixels or greater. + ///
+ public byte EncodingWidth { get; set; } + + /// + /// Gets or sets the encoding height.
+ /// Can be any number between 0 and 255. Value 0 means a frame height of 256 pixels or greater. + ///
+ public byte EncodingHeight { get; set; } + + /// + /// Gets or sets the number of bits per pixel.
+ /// Used when is + ///
+ public BmpBitsPerPixel BmpBitsPerPixel { get; set; } = BmpBitsPerPixel.Bit32; + + /// + /// Gets or sets the color table, if any. + /// The underlying pixel format is represented by . + /// + public ReadOnlyMemory? ColorTable { get; set; } + + /// + public static IcoFrameMetadata FromFormatConnectingFrameMetadata(FormatConnectingFrameMetadata metadata) + { + if (!metadata.PixelTypeInfo.HasValue) + { + return new IcoFrameMetadata + { + BmpBitsPerPixel = BmpBitsPerPixel.Bit32, + Compression = IconFrameCompression.Png + }; + } + + byte encodingWidth = metadata.EncodingWidth switch + { + > 255 => 0, + <= 255 and >= 1 => (byte)metadata.EncodingWidth, + _ => 0 + }; + + byte encodingHeight = metadata.EncodingHeight switch + { + > 255 => 0, + <= 255 and >= 1 => (byte)metadata.EncodingHeight, + _ => 0 + }; + + int bpp = metadata.PixelTypeInfo.Value.BitsPerPixel; + BmpBitsPerPixel bbpp = bpp switch + { + 1 => BmpBitsPerPixel.Bit1, + 2 => BmpBitsPerPixel.Bit2, + <= 4 => BmpBitsPerPixel.Bit4, + <= 8 => BmpBitsPerPixel.Bit8, + <= 16 => BmpBitsPerPixel.Bit16, + <= 24 => BmpBitsPerPixel.Bit24, + _ => BmpBitsPerPixel.Bit32 + }; + + IconFrameCompression compression = IconFrameCompression.Bmp; + if (bbpp is BmpBitsPerPixel.Bit32) + { + compression = IconFrameCompression.Png; + } + + return new IcoFrameMetadata + { + BmpBitsPerPixel = bbpp, + Compression = compression, + EncodingWidth = encodingWidth, + EncodingHeight = encodingHeight, + ColorTable = compression == IconFrameCompression.Bmp ? metadata.ColorTable : null + }; + } + + /// + public FormatConnectingFrameMetadata ToFormatConnectingFrameMetadata() + => new() + { + PixelTypeInfo = this.GetPixelTypeInfo(), + ColorTable = this.ColorTable, + EncodingWidth = this.EncodingWidth, + EncodingHeight = this.EncodingHeight + }; + + /// + IDeepCloneable IDeepCloneable.DeepClone() => this.DeepClone(); + + /// + public IcoFrameMetadata DeepClone() => new(this); + + internal void FromIconDirEntry(IconDirEntry entry) + { + this.EncodingWidth = entry.Width; + this.EncodingHeight = entry.Height; + } + + internal IconDirEntry ToIconDirEntry() + { + byte colorCount = this.Compression == IconFrameCompression.Png || this.BmpBitsPerPixel > BmpBitsPerPixel.Bit8 + ? (byte)0 + : (byte)ColorNumerics.GetColorCountForBitDepth((int)this.BmpBitsPerPixel); + + return new() + { + Width = this.EncodingWidth, + Height = this.EncodingHeight, + Planes = 1, + ColorCount = colorCount, + BitCount = this.Compression switch + { + IconFrameCompression.Bmp => (ushort)this.BmpBitsPerPixel, + IconFrameCompression.Png or _ => 32, + }, + }; + } + + private PixelTypeInfo GetPixelTypeInfo() + { + int bpp = (int)this.BmpBitsPerPixel; + PixelComponentInfo info; + PixelColorType color; + PixelAlphaRepresentation alpha = PixelAlphaRepresentation.None; + + if (this.Compression is IconFrameCompression.Png) + { + bpp = 32; + info = PixelComponentInfo.Create(4, bpp, 8, 8, 8, 8); + color = PixelColorType.RGB | PixelColorType.Alpha; + alpha = PixelAlphaRepresentation.Unassociated; + } + else + { + switch (this.BmpBitsPerPixel) + { + case BmpBitsPerPixel.Bit1: + info = PixelComponentInfo.Create(1, bpp, 1); + color = PixelColorType.Binary; + break; + case BmpBitsPerPixel.Bit2: + info = PixelComponentInfo.Create(1, bpp, 2); + color = PixelColorType.Indexed; + break; + case BmpBitsPerPixel.Bit4: + info = PixelComponentInfo.Create(1, bpp, 4); + color = PixelColorType.Indexed; + break; + case BmpBitsPerPixel.Bit8: + info = PixelComponentInfo.Create(1, bpp, 8); + color = PixelColorType.Indexed; + break; + + // Could be 555 with padding but 565 is more common in newer bitmaps and offers + // greater accuracy due to extra green precision. + case BmpBitsPerPixel.Bit16: + info = PixelComponentInfo.Create(3, bpp, 5, 6, 5); + color = PixelColorType.RGB; + break; + case BmpBitsPerPixel.Bit24: + info = PixelComponentInfo.Create(3, bpp, 8, 8, 8); + color = PixelColorType.RGB; + break; + case BmpBitsPerPixel.Bit32 or _: + info = PixelComponentInfo.Create(4, bpp, 8, 8, 8, 8); + color = PixelColorType.RGB | PixelColorType.Alpha; + alpha = PixelAlphaRepresentation.Unassociated; + break; + } + } + + return new PixelTypeInfo(bpp) + { + AlphaRepresentation = alpha, + ComponentInfo = info, + ColorType = color + }; + } +} diff --git a/src/ImageSharp/Formats/Ico/IcoMetadata.cs b/src/ImageSharp/Formats/Ico/IcoMetadata.cs new file mode 100644 index 0000000000..7e31468ecc --- /dev/null +++ b/src/ImageSharp/Formats/Ico/IcoMetadata.cs @@ -0,0 +1,171 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.Formats.Bmp; +using SixLabors.ImageSharp.Formats.Icon; +using SixLabors.ImageSharp.PixelFormats; + +namespace SixLabors.ImageSharp.Formats.Ico; + +/// +/// Provides Ico specific metadata information for the image. +/// +public class IcoMetadata : IFormatMetadata +{ + /// + /// Initializes a new instance of the class. + /// + public IcoMetadata() + { + } + + private IcoMetadata(IcoMetadata other) + { + this.Compression = other.Compression; + this.EncodingWidth = other.EncodingWidth; + this.EncodingHeight = other.EncodingHeight; + this.BmpBitsPerPixel = other.BmpBitsPerPixel; + + if (other.ColorTable?.Length > 0) + { + this.ColorTable = other.ColorTable.Value.ToArray(); + } + } + + /// + /// Gets or sets the frame compressions format. Derived from the root frame. + /// + public IconFrameCompression Compression { get; set; } + + /// + /// Gets or sets the encoding width.
+ /// Can be any number between 0 and 255. Value 0 means a frame height of 256 pixels or greater. Derived from the root frame. + ///
+ public byte EncodingWidth { get; set; } + + /// + /// Gets or sets the encoding height.
+ /// Can be any number between 0 and 255. Value 0 means a frame height of 256 pixels or greater. Derived from the root frame. + ///
+ public byte EncodingHeight { get; set; } + + /// + /// Gets or sets the number of bits per pixel.
+ /// Used when is + ///
+ public BmpBitsPerPixel BmpBitsPerPixel { get; set; } = BmpBitsPerPixel.Bit32; + + /// + /// Gets or sets the color table, if any. Derived from the root frame.
+ /// The underlying pixel format is represented by . + ///
+ public ReadOnlyMemory? ColorTable { get; set; } + + /// + public static IcoMetadata FromFormatConnectingMetadata(FormatConnectingMetadata metadata) + { + int bpp = metadata.PixelTypeInfo.BitsPerPixel; + BmpBitsPerPixel bbpp = bpp switch + { + 1 => BmpBitsPerPixel.Bit1, + 2 => BmpBitsPerPixel.Bit2, + <= 4 => BmpBitsPerPixel.Bit4, + <= 8 => BmpBitsPerPixel.Bit8, + <= 16 => BmpBitsPerPixel.Bit16, + <= 24 => BmpBitsPerPixel.Bit24, + _ => BmpBitsPerPixel.Bit32 + }; + + IconFrameCompression compression = IconFrameCompression.Bmp; + if (bbpp is BmpBitsPerPixel.Bit32) + { + compression = IconFrameCompression.Png; + } + + return new IcoMetadata + { + BmpBitsPerPixel = bbpp, + Compression = compression, + ColorTable = compression == IconFrameCompression.Bmp ? metadata.ColorTable : null + }; + } + + /// + public PixelTypeInfo GetPixelTypeInfo() + { + int bpp = (int)this.BmpBitsPerPixel; + PixelComponentInfo info; + PixelColorType color; + PixelAlphaRepresentation alpha = PixelAlphaRepresentation.None; + + if (this.Compression is IconFrameCompression.Png) + { + bpp = 32; + info = PixelComponentInfo.Create(4, bpp, 8, 8, 8, 8); + color = PixelColorType.RGB | PixelColorType.Alpha; + alpha = PixelAlphaRepresentation.Unassociated; + } + else + { + switch (this.BmpBitsPerPixel) + { + case BmpBitsPerPixel.Bit1: + info = PixelComponentInfo.Create(1, bpp, 1); + color = PixelColorType.Binary; + break; + case BmpBitsPerPixel.Bit2: + info = PixelComponentInfo.Create(1, bpp, 2); + color = PixelColorType.Indexed; + break; + case BmpBitsPerPixel.Bit4: + info = PixelComponentInfo.Create(1, bpp, 4); + color = PixelColorType.Indexed; + break; + case BmpBitsPerPixel.Bit8: + info = PixelComponentInfo.Create(1, bpp, 8); + color = PixelColorType.Indexed; + break; + + // Could be 555 with padding but 565 is more common in newer bitmaps and offers + // greater accuracy due to extra green precision. + case BmpBitsPerPixel.Bit16: + info = PixelComponentInfo.Create(3, bpp, 5, 6, 5); + color = PixelColorType.RGB; + break; + case BmpBitsPerPixel.Bit24: + info = PixelComponentInfo.Create(3, bpp, 8, 8, 8); + color = PixelColorType.RGB; + break; + case BmpBitsPerPixel.Bit32 or _: + info = PixelComponentInfo.Create(4, bpp, 8, 8, 8, 8); + color = PixelColorType.RGB | PixelColorType.Alpha; + alpha = PixelAlphaRepresentation.Unassociated; + break; + } + } + + return new PixelTypeInfo(bpp) + { + AlphaRepresentation = alpha, + ComponentInfo = info, + ColorType = color + }; + } + + /// + public FormatConnectingMetadata ToFormatConnectingMetadata() + => new() + { + EncodingType = this.Compression == IconFrameCompression.Bmp && this.BmpBitsPerPixel <= BmpBitsPerPixel.Bit8 + ? EncodingType.Lossy + : EncodingType.Lossless, + PixelTypeInfo = this.GetPixelTypeInfo(), + ColorTable = this.ColorTable + }; + + /// + IDeepCloneable IDeepCloneable.DeepClone() => this.DeepClone(); + + /// + public IcoMetadata DeepClone() => new(this); +} diff --git a/src/ImageSharp/Formats/Icon/IconDecoderCore.cs b/src/ImageSharp/Formats/Icon/IconDecoderCore.cs new file mode 100644 index 0000000000..caed2dd902 --- /dev/null +++ b/src/ImageSharp/Formats/Icon/IconDecoderCore.cs @@ -0,0 +1,310 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Diagnostics.CodeAnalysis; +using SixLabors.ImageSharp.Formats.Bmp; +using SixLabors.ImageSharp.Formats.Png; +using SixLabors.ImageSharp.IO; +using SixLabors.ImageSharp.Metadata; + +namespace SixLabors.ImageSharp.Formats.Icon; + +internal abstract class IconDecoderCore : ImageDecoderCore +{ + private IconDir fileHeader; + private IconDirEntry[]? entries; + + protected IconDecoderCore(DecoderOptions options) + : base(options) + { + } + + /// + protected override Image Decode(BufferedReadStream stream, CancellationToken cancellationToken) + { + // Stream may not at 0. + long basePosition = stream.Position; + this.ReadHeader(stream); + + Span flag = stackalloc byte[PngConstants.HeaderBytes.Length]; + + List<(Image Image, IconFrameCompression Compression, int Index)> decodedEntries + = new((int)Math.Min(this.entries.Length, this.Options.MaxFrames)); + + for (int i = 0; i < this.entries.Length; i++) + { + if (i == this.Options.MaxFrames) + { + break; + } + + ref IconDirEntry entry = ref this.entries[i]; + + // If we hit the end of the stream we should break. + if (stream.Seek(basePosition + entry.ImageOffset, SeekOrigin.Begin) >= stream.Length) + { + break; + } + + // There should always be enough bytes for this regardless of the entry type. + if (stream.Read(flag) != PngConstants.HeaderBytes.Length) + { + break; + } + + // Reset the stream position. + _ = stream.Seek(-PngConstants.HeaderBytes.Length, SeekOrigin.Current); + + bool isPng = flag.SequenceEqual(PngConstants.HeaderBytes); + + // Decode the frame into a temp image buffer. This is disposed after the frame is copied to the result. + Image temp = this.GetDecoder(isPng).Decode(this.Options.Configuration, stream, cancellationToken); + decodedEntries.Add((temp, isPng ? IconFrameCompression.Png : IconFrameCompression.Bmp, i)); + + // Since Windows Vista, the size of an image is determined from the BITMAPINFOHEADER structure or PNG image data + // which technically allows storing icons with larger than 256 pixels, but such larger sizes are not recommended by Microsoft. + this.Dimensions = new(Math.Max(this.Dimensions.Width, temp.Size.Width), Math.Max(this.Dimensions.Height, temp.Size.Height)); + } + + ImageMetadata metadata = new(); + BmpMetadata? bmpMetadata = null; + PngMetadata? pngMetadata = null; + Image result = new(this.Options.Configuration, metadata, decodedEntries.Select(x => + { + BmpBitsPerPixel bitsPerPixel = BmpBitsPerPixel.Bit32; + ReadOnlyMemory? colorTable = null; + ImageFrame target = new(this.Options.Configuration, this.Dimensions); + ImageFrame source = x.Image.Frames.RootFrameUnsafe; + for (int y = 0; y < source.Height; y++) + { + source.PixelBuffer.DangerousGetRowSpan(y).CopyTo(target.PixelBuffer.DangerousGetRowSpan(y)); + } + + // Copy the format specific frame metadata to the image. + if (x.Compression is IconFrameCompression.Png) + { + if (x.Index == 0) + { + pngMetadata = x.Image.Metadata.GetPngMetadata(); + } + + target.Metadata.SetFormatMetadata(PngFormat.Instance, target.Metadata.GetPngMetadata()); + } + else + { + BmpMetadata meta = x.Image.Metadata.GetBmpMetadata(); + bitsPerPixel = meta.BitsPerPixel; + colorTable = meta.ColorTable; + + if (x.Index == 0) + { + bmpMetadata = meta; + } + } + + this.SetFrameMetadata( + metadata, + target.Metadata, + x.Index, + this.entries[x.Index], + x.Compression, + bitsPerPixel, + colorTable); + + x.Image.Dispose(); + + return target; + }).ToArray()); + + // Copy the format specific metadata to the image. + if (bmpMetadata != null) + { + result.Metadata.SetFormatMetadata(BmpFormat.Instance, bmpMetadata); + } + + if (pngMetadata != null) + { + result.Metadata.SetFormatMetadata(PngFormat.Instance, pngMetadata); + } + + return result; + } + + /// + protected override ImageInfo Identify(BufferedReadStream stream, CancellationToken cancellationToken) + { + // Stream may not at 0. + long basePosition = stream.Position; + this.ReadHeader(stream); + + Span flag = stackalloc byte[PngConstants.HeaderBytes.Length]; + + ImageMetadata metadata = new(); + BmpMetadata? bmpMetadata = null; + PngMetadata? pngMetadata = null; + ImageFrameMetadata[] frames = new ImageFrameMetadata[Math.Min(this.fileHeader.Count, this.Options.MaxFrames)]; + int bpp = 0; + for (int i = 0; i < frames.Length; i++) + { + BmpBitsPerPixel bitsPerPixel = BmpBitsPerPixel.Bit32; + ReadOnlyMemory? colorTable = null; + ref IconDirEntry entry = ref this.entries[i]; + + // If we hit the end of the stream we should break. + if (stream.Seek(basePosition + entry.ImageOffset, SeekOrigin.Begin) >= stream.Length) + { + break; + } + + // There should always be enough bytes for this regardless of the entry type. + if (stream.Read(flag) != PngConstants.HeaderBytes.Length) + { + break; + } + + // Reset the stream position. + _ = stream.Seek(-PngConstants.HeaderBytes.Length, SeekOrigin.Current); + + bool isPng = flag.SequenceEqual(PngConstants.HeaderBytes); + + // Decode the frame into a temp image buffer. This is disposed after the frame is copied to the result. + ImageInfo frameInfo = this.GetDecoder(isPng).Identify(this.Options.Configuration, stream, cancellationToken); + + ImageFrameMetadata frameMetadata = new(); + + if (isPng) + { + if (i == 0) + { + pngMetadata = frameInfo.Metadata.GetPngMetadata(); + } + + frameMetadata.SetFormatMetadata(PngFormat.Instance, frameInfo.FrameMetadataCollection[0].GetPngMetadata()); + } + else + { + BmpMetadata meta = frameInfo.Metadata.GetBmpMetadata(); + bitsPerPixel = meta.BitsPerPixel; + colorTable = meta.ColorTable; + + if (i == 0) + { + bmpMetadata = meta; + } + } + + bpp = Math.Max(bpp, (int)bitsPerPixel); + + frames[i] = frameMetadata; + + this.SetFrameMetadata( + metadata, + frames[i], + i, + this.entries[i], + isPng ? IconFrameCompression.Png : IconFrameCompression.Bmp, + bitsPerPixel, + colorTable); + + // Since Windows Vista, the size of an image is determined from the BITMAPINFOHEADER structure or PNG image data + // which technically allows storing icons with larger than 256 pixels, but such larger sizes are not recommended by Microsoft. + this.Dimensions = new(Math.Max(this.Dimensions.Width, frameInfo.Size.Width), Math.Max(this.Dimensions.Height, frameInfo.Size.Height)); + } + + // Copy the format specific metadata to the image. + if (bmpMetadata != null) + { + metadata.SetFormatMetadata(BmpFormat.Instance, bmpMetadata); + } + + if (pngMetadata != null) + { + metadata.SetFormatMetadata(PngFormat.Instance, pngMetadata); + } + + return new(this.Dimensions, metadata, frames); + } + + protected abstract void SetFrameMetadata( + ImageMetadata imageMetadata, + ImageFrameMetadata frameMetadata, + int index, + in IconDirEntry entry, + IconFrameCompression compression, + BmpBitsPerPixel bitsPerPixel, + ReadOnlyMemory? colorTable); + + [MemberNotNull(nameof(entries))] + protected void ReadHeader(Stream stream) + { + Span buffer = stackalloc byte[IconDirEntry.Size]; + + // ICONDIR + _ = CheckEndOfStream(stream.Read(buffer[..IconDir.Size]), IconDir.Size); + this.fileHeader = IconDir.Parse(buffer); + + // ICONDIRENTRY + this.entries = new IconDirEntry[this.fileHeader.Count]; + for (int i = 0; i < this.entries.Length; i++) + { + _ = CheckEndOfStream(stream.Read(buffer[..IconDirEntry.Size]), IconDirEntry.Size); + this.entries[i] = IconDirEntry.Parse(buffer); + } + + int width = 0; + int height = 0; + foreach (IconDirEntry entry in this.entries) + { + // Since Windows 95 size of an image in the ICONDIRENTRY structure might + // be set to zero, which means 256 pixels. + if (entry.Width == 0) + { + width = 256; + } + + if (entry.Height == 0) + { + height = 256; + } + + if (width == 256 && height == 256) + { + break; + } + + width = Math.Max(width, entry.Width); + height = Math.Max(height, entry.Height); + } + + this.Dimensions = new(width, height); + } + + private ImageDecoderCore GetDecoder(bool isPng) + { + if (isPng) + { + return new PngDecoderCore(new() + { + GeneralOptions = this.Options, + }); + } + + return new BmpDecoderCore(new() + { + GeneralOptions = this.Options, + ProcessedAlphaMask = true, + SkipFileHeader = true, + UseDoubleHeight = true, + }); + } + + private static int CheckEndOfStream(int v, int length) + { + if (v != length) + { + throw new InvalidImageContentException("Not enough bytes to read icon header."); + } + + return v; + } +} diff --git a/src/ImageSharp/Formats/Icon/IconDir.cs b/src/ImageSharp/Formats/Icon/IconDir.cs new file mode 100644 index 0000000000..3e02538c84 --- /dev/null +++ b/src/ImageSharp/Formats/Icon/IconDir.cs @@ -0,0 +1,43 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Runtime.InteropServices; + +namespace SixLabors.ImageSharp.Formats.Icon; + +[StructLayout(LayoutKind.Sequential, Pack = 1, Size = Size)] +internal struct IconDir(ushort reserved, IconFileType type, ushort count) +{ + public const int Size = 3 * sizeof(ushort); + + /// + /// Reserved. Must always be 0. + /// + public ushort Reserved = reserved; + + /// + /// Specifies image type: 1 for icon (.ICO) image, 2 for cursor (.CUR) image. Other values are invalid. + /// + public IconFileType Type = type; + + /// + /// Specifies number of images in the file. + /// + public ushort Count = count; + + public IconDir(IconFileType type) + : this(type, 0) + { + } + + public IconDir(IconFileType type, ushort count) + : this(0, type, count) + { + } + + public static IconDir Parse(ReadOnlySpan data) + => MemoryMarshal.Cast(data)[0]; + + public readonly unsafe void WriteTo(Stream stream) + => stream.Write(MemoryMarshal.Cast([this])); +} diff --git a/src/ImageSharp/Formats/Icon/IconDirEntry.cs b/src/ImageSharp/Formats/Icon/IconDirEntry.cs new file mode 100644 index 0000000000..eab15dd872 --- /dev/null +++ b/src/ImageSharp/Formats/Icon/IconDirEntry.cs @@ -0,0 +1,60 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Runtime.InteropServices; + +namespace SixLabors.ImageSharp.Formats.Icon; + +[StructLayout(LayoutKind.Sequential, Pack = 1, Size = Size)] +internal struct IconDirEntry +{ + public const int Size = (4 * sizeof(byte)) + (2 * sizeof(ushort)) + (2 * sizeof(uint)); + + /// + /// Specifies image width in pixels. Can be any number between 0 and 255. Value 0 means image width is 256 pixels. + /// + public byte Width; + + /// + /// Specifies image height in pixels. Can be any number between 0 and 255. Value 0 means image height is 256 pixels.[ + /// + public byte Height; + + /// + /// Specifies number of colors in the color palette. Should be 0 if the image does not use a color palette. + /// + public byte ColorCount; + + /// + /// Reserved. Should be 0. + /// + public byte Reserved; + + /// + /// In ICO format: Specifies color planes. Should be 0 or 1.
+ /// In CUR format: Specifies the horizontal coordinates of the hotspot in number of pixels from the left. + ///
+ public ushort Planes; + + /// + /// In ICO format: Specifies bits per pixel.
+ /// In CUR format: Specifies the vertical coordinates of the hotspot in number of pixels from the top. + ///
+ public ushort BitCount; + + /// + /// Specifies the size of the image's data in bytes + /// + public uint BytesInRes; + + /// + /// Specifies the offset of BMP or PNG data from the beginning of the ICO/CUR file. + /// + public uint ImageOffset; + + public static IconDirEntry Parse(in ReadOnlySpan data) + => MemoryMarshal.Cast(data)[0]; + + public readonly unsafe void WriteTo(in Stream stream) + => stream.Write(MemoryMarshal.Cast([this])); +} diff --git a/src/ImageSharp/Formats/Icon/IconEncoderCore.cs b/src/ImageSharp/Formats/Icon/IconEncoderCore.cs new file mode 100644 index 0000000000..4b973d5115 --- /dev/null +++ b/src/ImageSharp/Formats/Icon/IconEncoderCore.cs @@ -0,0 +1,186 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Diagnostics.CodeAnalysis; +using SixLabors.ImageSharp.Formats.Bmp; +using SixLabors.ImageSharp.Formats.Cur; +using SixLabors.ImageSharp.Formats.Ico; +using SixLabors.ImageSharp.Formats.Png; +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Processing.Processors.Quantization; + +namespace SixLabors.ImageSharp.Formats.Icon; + +internal abstract class IconEncoderCore +{ + private readonly QuantizingImageEncoder encoder; + private readonly IconFileType iconFileType; + private IconDir fileHeader; + private EncodingFrameMetadata[]? entries; + + protected IconEncoderCore(QuantizingImageEncoder encoder, IconFileType iconFileType) + { + this.encoder = encoder; + this.iconFileType = iconFileType; + } + + public void Encode( + Image image, + Stream stream, + CancellationToken cancellationToken) + where TPixel : unmanaged, IPixel + { + Guard.NotNull(image, nameof(image)); + Guard.NotNull(stream, nameof(stream)); + + // Stream may not at 0. + long basePosition = stream.Position; + this.InitHeader(image); + + // We don't write the header and entries yet as we need to write the image data first. + int dataOffset = IconDir.Size + (IconDirEntry.Size * this.entries.Length); + _ = stream.Seek(dataOffset, SeekOrigin.Current); + + for (int i = 0; i < image.Frames.Count; i++) + { + cancellationToken.ThrowIfCancellationRequested(); + + // Since Windows Vista, the size of an image is determined from the BITMAPINFOHEADER structure or PNG image data + // which technically allows storing icons with larger than 256 pixels, but such larger sizes are not recommended by Microsoft. + ImageFrame frame = image.Frames[i]; + int width = this.entries[i].Entry.Width; + if (width is 0) + { + width = frame.Width; + } + + int height = this.entries[i].Entry.Height; + if (height is 0) + { + height = frame.Height; + } + + this.entries[i].Entry.ImageOffset = (uint)stream.Position; + + // We crop the frame to the size specified in the metadata. + // TODO: we can optimize this by cropping the frame only if the new size is both required and different. + using Image encodingFrame = new(width, height); + for (int y = 0; y < height; y++) + { + frame.PixelBuffer.DangerousGetRowSpan(y)[..width] + .CopyTo(encodingFrame.GetRootFramePixelBuffer().DangerousGetRowSpan(y)); + } + + ref EncodingFrameMetadata encodingMetadata = ref this.entries[i]; + + QuantizingImageEncoder encoder = encodingMetadata.Compression switch + { + IconFrameCompression.Bmp => new BmpEncoder() + { + Quantizer = this.GetQuantizer(encodingMetadata), + ProcessedAlphaMask = true, + UseDoubleHeight = true, + SkipFileHeader = true, + SupportTransparency = false, + BitsPerPixel = encodingMetadata.BmpBitsPerPixel + }, + IconFrameCompression.Png => new PngEncoder() + { + // Only 32bit Png supported. + // https://devblogs.microsoft.com/oldnewthing/20101022-00/?p=12473 + BitDepth = PngBitDepth.Bit8, + ColorType = PngColorType.RgbWithAlpha, + CompressionLevel = PngCompressionLevel.BestCompression + }, + _ => throw new NotSupportedException(), + }; + + encoder.Encode(encodingFrame, stream); + encodingMetadata.Entry.BytesInRes = (uint)stream.Position - encodingMetadata.Entry.ImageOffset; + } + + // We now need to rewind the stream and write the header and the entries. + long endPosition = stream.Position; + _ = stream.Seek(basePosition, SeekOrigin.Begin); + this.fileHeader.WriteTo(stream); + foreach (EncodingFrameMetadata frame in this.entries) + { + frame.Entry.WriteTo(stream); + } + + _ = stream.Seek(endPosition, SeekOrigin.Begin); + } + + [MemberNotNull(nameof(entries))] + private void InitHeader(Image image) + { + this.fileHeader = new(this.iconFileType, (ushort)image.Frames.Count); + this.entries = this.iconFileType switch + { + IconFileType.ICO => + image.Frames.Select(i => + { + IcoFrameMetadata metadata = i.Metadata.GetIcoMetadata(); + return new EncodingFrameMetadata(metadata.Compression, metadata.BmpBitsPerPixel, metadata.ColorTable, metadata.ToIconDirEntry()); + }).ToArray(), + IconFileType.CUR => + image.Frames.Select(i => + { + CurFrameMetadata metadata = i.Metadata.GetCurMetadata(); + return new EncodingFrameMetadata(metadata.Compression, metadata.BmpBitsPerPixel, metadata.ColorTable, metadata.ToIconDirEntry()); + }).ToArray(), + _ => throw new NotSupportedException(), + }; + } + + private IQuantizer? GetQuantizer(EncodingFrameMetadata metadata) + { + if (metadata.Entry.BitCount > 8) + { + return null; + } + + if (this.encoder.Quantizer is not null) + { + return this.encoder.Quantizer; + } + + if (metadata.ColorTable is null) + { + return new WuQuantizer(new() + { + MaxColors = metadata.Entry.ColorCount + }); + } + + // Don't dither if we have a palette. We want to preserve as much information as possible. + return new PaletteQuantizer(metadata.ColorTable.Value, new() { Dither = null }); + } + + internal sealed class EncodingFrameMetadata + { + private IconDirEntry iconDirEntry; + + public EncodingFrameMetadata( + IconFrameCompression compression, + BmpBitsPerPixel bmpBitsPerPixel, + ReadOnlyMemory? colorTable, + IconDirEntry iconDirEntry) + { + this.Compression = compression; + this.BmpBitsPerPixel = compression == IconFrameCompression.Png + ? BmpBitsPerPixel.Bit32 + : bmpBitsPerPixel; + this.ColorTable = colorTable; + this.iconDirEntry = iconDirEntry; + } + + public IconFrameCompression Compression { get; } + + public BmpBitsPerPixel BmpBitsPerPixel { get; } + + public ReadOnlyMemory? ColorTable { get; set; } + + public ref IconDirEntry Entry => ref this.iconDirEntry; + } +} diff --git a/src/ImageSharp/Formats/Icon/IconFileType.cs b/src/ImageSharp/Formats/Icon/IconFileType.cs new file mode 100644 index 0000000000..3450698f11 --- /dev/null +++ b/src/ImageSharp/Formats/Icon/IconFileType.cs @@ -0,0 +1,20 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +namespace SixLabors.ImageSharp.Formats.Icon; + +/// +/// Ico file type +/// +internal enum IconFileType : ushort +{ + /// + /// ICO file + /// + ICO = 1, + + /// + /// CUR file + /// + CUR = 2, +} diff --git a/src/ImageSharp/Formats/Icon/IconFrameCompression.cs b/src/ImageSharp/Formats/Icon/IconFrameCompression.cs new file mode 100644 index 0000000000..5c772c3fe3 --- /dev/null +++ b/src/ImageSharp/Formats/Icon/IconFrameCompression.cs @@ -0,0 +1,20 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +namespace SixLabors.ImageSharp.Formats.Icon; + +/// +/// IconFrameCompression +/// +public enum IconFrameCompression +{ + /// + /// Bmp + /// + Bmp, + + /// + /// Png + /// + Png +} diff --git a/src/ImageSharp/Formats/Icon/IconImageFormatDetector.cs b/src/ImageSharp/Formats/Icon/IconImageFormatDetector.cs new file mode 100644 index 0000000000..9e7d22de22 --- /dev/null +++ b/src/ImageSharp/Formats/Icon/IconImageFormatDetector.cs @@ -0,0 +1,66 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Diagnostics.CodeAnalysis; + +namespace SixLabors.ImageSharp.Formats.Icon; + +/// +/// Detects ico file headers. +/// +public class IconImageFormatDetector : IImageFormatDetector +{ + /// + public int HeaderSize { get; } = IconDir.Size + IconDirEntry.Size; + + /// + public bool TryDetectFormat(ReadOnlySpan header, [NotNullWhen(true)] out IImageFormat? format) + { + format = this.IsSupportedFileFormat(header) switch + { + true => Ico.IcoFormat.Instance, + false => Cur.CurFormat.Instance, + null => default + }; + + return format is not null; + } + + private bool? IsSupportedFileFormat(ReadOnlySpan header) + { + // There are no magic bytes in the first few bytes of a tga file, + // so we try to figure out if its a valid tga by checking for valid tga header bytes. + if (header.Length < this.HeaderSize) + { + return null; + } + + IconDir dir = IconDir.Parse(header); + if (dir is not { Reserved: 0 } // Should be 0. + or not { Type: IconFileType.ICO or IconFileType.CUR } // Unknown Type. + or { Count: 0 }) + { + return null; + } + + IconDirEntry entry = IconDirEntry.Parse(header[IconDir.Size..]); + if (entry is not { Reserved: 0 } // Should be 0. + or { BytesInRes: 0 } // Should not be 0. + || entry.ImageOffset < IconDir.Size + (dir.Count * IconDirEntry.Size)) + { + return null; + } + + if (dir.Type is IconFileType.ICO) + { + if (entry is not { BitCount: 1 or 4 or 8 or 16 or 24 or 32 } or not { Planes: 0 or 1 }) + { + return null; + } + + return true; + } + + return false; + } +} diff --git a/src/ImageSharp/Formats/ImageDecoder.cs b/src/ImageSharp/Formats/ImageDecoder.cs index 549a28d409..e58cd6a6de 100644 --- a/src/ImageSharp/Formats/ImageDecoder.cs +++ b/src/ImageSharp/Formats/ImageDecoder.cs @@ -2,6 +2,7 @@ // Licensed under the Six Labors Split License. using SixLabors.ImageSharp.IO; +using SixLabors.ImageSharp.Metadata; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing; @@ -293,6 +294,11 @@ internal void SetDecoderFormat(Configuration configuration, Image image) if (configuration.ImageFormatsManager.TryFindFormatByDecoder(this, out IImageFormat? format)) { image.Metadata.DecodedImageFormat = format; + + foreach (ImageFrame frame in image.Frames) + { + frame.Metadata.DecodedImageFormat = format; + } } } @@ -301,6 +307,12 @@ internal void SetDecoderFormat(Configuration configuration, ImageInfo info) if (configuration.ImageFormatsManager.TryFindFormatByDecoder(this, out IImageFormat? format)) { info.Metadata.DecodedImageFormat = format; + info.PixelType = info.Metadata.GetDecodedPixelTypeInfo(); + + foreach (ImageFrameMetadata frame in info.FrameMetadataCollection) + { + frame.DecodedImageFormat = format; + } } } } diff --git a/src/ImageSharp/Formats/ImageEncoder.cs b/src/ImageSharp/Formats/ImageEncoder.cs index deb527f698..fdaa5c35dc 100644 --- a/src/ImageSharp/Formats/ImageEncoder.cs +++ b/src/ImageSharp/Formats/ImageEncoder.cs @@ -41,6 +41,8 @@ protected abstract void Encode(Image image, Stream stream, Cance private void EncodeWithSeekableStream(Image image, Stream stream, CancellationToken cancellationToken) where TPixel : unmanaged, IPixel { + image.SynchronizeMetadata(); + Configuration configuration = image.Configuration; if (stream.CanSeek) { @@ -58,6 +60,8 @@ private void EncodeWithSeekableStream(Image image, Stream stream private async Task EncodeWithSeekableStreamAsync(Image image, Stream stream, CancellationToken cancellationToken) where TPixel : unmanaged, IPixel { + image.SynchronizeMetadata(); + Configuration configuration = image.Configuration; if (stream.CanSeek) { @@ -65,7 +69,7 @@ private async Task EncodeWithSeekableStreamAsync(Image image, St } else { - using ChunkedMemoryStream ms = new(configuration.MemoryAllocator); + await using ChunkedMemoryStream ms = new(configuration.MemoryAllocator); await DoEncodeAsync(ms); ms.Position = 0; await ms.CopyToAsync(stream, configuration.StreamProcessingBufferSize, cancellationToken) diff --git a/src/ImageSharp/Formats/ImageFormatManager.cs b/src/ImageSharp/Formats/ImageFormatManager.cs index 0ee4bc79b9..b6b5f87797 100644 --- a/src/ImageSharp/Formats/ImageFormatManager.cs +++ b/src/ImageSharp/Formats/ImageFormatManager.cs @@ -83,10 +83,7 @@ public void AddImageFormat(IImageFormat format) lock (HashLock) { - if (!this.imageFormats.Contains(format)) - { - this.imageFormats.Add(format); - } + this.imageFormats.Add(format); } } diff --git a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs index d432e82d24..018df5f9f4 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs @@ -386,29 +386,33 @@ public void LoadFrom(ref Block8x8 source) public void LoadFromInt16ExtendedAvx2(ref Block8x8 source) { DebugGuard.IsTrue( - SimdUtils.HasVector8, + Avx2.IsSupported, "LoadFromUInt16ExtendedAvx2 only works on AVX2 compatible architecture!"); - ref Vector sRef = ref Unsafe.As>(ref source); - ref Vector dRef = ref Unsafe.As>(ref this); + ref short sRef = ref Unsafe.As(ref source); + ref Vector256 dRef = ref Unsafe.As>(ref this); - // Vector.Count == 16 on AVX2 + // Vector256.Count == 16 on AVX2 // We can process 2 block rows in a single step - SimdUtils.ExtendedIntrinsics.ConvertToSingle(sRef, out Vector top, out Vector bottom); - dRef = top; - Unsafe.Add(ref dRef, 1) = bottom; - - SimdUtils.ExtendedIntrinsics.ConvertToSingle(Unsafe.Add(ref sRef, 1), out top, out bottom); - Unsafe.Add(ref dRef, 2) = top; - Unsafe.Add(ref dRef, 3) = bottom; - - SimdUtils.ExtendedIntrinsics.ConvertToSingle(Unsafe.Add(ref sRef, 2), out top, out bottom); - Unsafe.Add(ref dRef, 4) = top; - Unsafe.Add(ref dRef, 5) = bottom; - - SimdUtils.ExtendedIntrinsics.ConvertToSingle(Unsafe.Add(ref sRef, 3), out top, out bottom); - Unsafe.Add(ref dRef, 6) = top; - Unsafe.Add(ref dRef, 7) = bottom; + Vector256 top = Avx2.ConvertToVector256Int32(Vector128.LoadUnsafe(ref sRef)); + Vector256 bottom = Avx2.ConvertToVector256Int32(Vector128.LoadUnsafe(ref sRef, (nuint)Vector256.Count)); + dRef = Avx.ConvertToVector256Single(top); + Unsafe.Add(ref dRef, 1) = Avx.ConvertToVector256Single(bottom); + + top = Avx2.ConvertToVector256Int32(Vector128.LoadUnsafe(ref sRef, (nuint)(Vector256.Count * 2))); + bottom = Avx2.ConvertToVector256Int32(Vector128.LoadUnsafe(ref sRef, (nuint)(Vector256.Count * 3))); + Unsafe.Add(ref dRef, 2) = Avx.ConvertToVector256Single(top); + Unsafe.Add(ref dRef, 3) = Avx.ConvertToVector256Single(bottom); + + top = Avx2.ConvertToVector256Int32(Vector128.LoadUnsafe(ref sRef, (nuint)(Vector256.Count * 4))); + bottom = Avx2.ConvertToVector256Int32(Vector128.LoadUnsafe(ref sRef, (nuint)(Vector256.Count * 5))); + Unsafe.Add(ref dRef, 4) = Avx.ConvertToVector256Single(top); + Unsafe.Add(ref dRef, 5) = Avx.ConvertToVector256Single(bottom); + + top = Avx2.ConvertToVector256Int32(Vector128.LoadUnsafe(ref sRef, (nuint)(Vector256.Count * 6))); + bottom = Avx2.ConvertToVector256Int32(Vector128.LoadUnsafe(ref sRef, (nuint)(Vector256.Count * 7))); + Unsafe.Add(ref dRef, 6) = Avx.ConvertToVector256Single(top); + Unsafe.Add(ref dRef, 7) = Avx.ConvertToVector256Single(bottom); } /// diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegFrame.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegFrame.cs index c3cd95c028..f251df3bf2 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegFrame.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegFrame.cs @@ -133,7 +133,7 @@ public void Init(int maxSubFactorH, int maxSubFactorV) for (int i = 0; i < this.ComponentCount; i++) { - IJpegComponent component = this.Components[i]; + JpegComponent component = this.Components[i]; component.Init(maxSubFactorH, maxSubFactorV); } } @@ -143,7 +143,7 @@ public void AllocateComponents() bool fullScan = this.Progressive || !this.Interleaved; for (int i = 0; i < this.ComponentCount; i++) { - IJpegComponent component = this.Components[i]; + JpegComponent component = this.Components[i]; component.AllocateSpectral(fullScan); } } diff --git a/src/ImageSharp/Formats/Jpeg/Components/Encoder/EncodingConfigs/JpegFrameConfig.cs b/src/ImageSharp/Formats/Jpeg/Components/Encoder/EncodingConfigs/JpegFrameConfig.cs index 5a59837e58..0b7b21f90b 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Encoder/EncodingConfigs/JpegFrameConfig.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Encoder/EncodingConfigs/JpegFrameConfig.cs @@ -5,7 +5,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder; internal class JpegFrameConfig { - public JpegFrameConfig(JpegColorSpace colorType, JpegEncodingColor encodingColor, JpegComponentConfig[] components, JpegHuffmanTableConfig[] huffmanTables, JpegQuantizationTableConfig[] quantTables) + public JpegFrameConfig(JpegColorSpace colorType, JpegColorType encodingColor, JpegComponentConfig[] components, JpegHuffmanTableConfig[] huffmanTables, JpegQuantizationTableConfig[] quantTables) { this.ColorType = colorType; this.EncodingColor = encodingColor; @@ -25,7 +25,7 @@ public JpegFrameConfig(JpegColorSpace colorType, JpegEncodingColor encodingColor public JpegColorSpace ColorType { get; } - public JpegEncodingColor EncodingColor { get; } + public JpegColorType EncodingColor { get; } public JpegComponentConfig[] Components { get; } diff --git a/src/ImageSharp/Formats/Jpeg/Components/Encoder/HuffmanScanEncoder.cs b/src/ImageSharp/Formats/Jpeg/Components/Encoder/HuffmanScanEncoder.cs index d74494f9e5..ac527ff312 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Encoder/HuffmanScanEncoder.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Encoder/HuffmanScanEncoder.cs @@ -139,13 +139,13 @@ public void BuildHuffmanTable(JpegHuffmanTableConfig tableConfig) /// Frame to encode. /// Converter from color to spectral. /// The token to request cancellation. - public void EncodeScanBaselineInterleaved(JpegEncodingColor color, JpegFrame frame, SpectralConverter converter, CancellationToken cancellationToken) + public void EncodeScanBaselineInterleaved(JpegColorType color, JpegFrame frame, SpectralConverter converter, CancellationToken cancellationToken) where TPixel : unmanaged, IPixel { switch (color) { - case JpegEncodingColor.YCbCrRatio444: - case JpegEncodingColor.Rgb: + case JpegColorType.YCbCrRatio444: + case JpegColorType.Rgb: this.EncodeThreeComponentBaselineInterleavedScanNoSubsampling(frame, converter, cancellationToken); break; default: diff --git a/src/ImageSharp/Formats/Jpeg/Components/Encoder/HuffmanSpec.cs b/src/ImageSharp/Formats/Jpeg/Components/Encoder/HuffmanSpec.cs index faba3d5afc..f5666f7799 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Encoder/HuffmanSpec.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Encoder/HuffmanSpec.cs @@ -6,7 +6,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder; /// /// The Huffman encoding specifications. /// -public readonly struct HuffmanSpec +internal readonly struct HuffmanSpec { /// /// Huffman talbe specification for luminance DC. diff --git a/src/ImageSharp/Formats/Jpeg/JpegEncodingColor.cs b/src/ImageSharp/Formats/Jpeg/JpegColorType.cs similarity index 98% rename from src/ImageSharp/Formats/Jpeg/JpegEncodingColor.cs rename to src/ImageSharp/Formats/Jpeg/JpegColorType.cs index 779ccf61e1..a8429273fe 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegEncodingColor.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegColorType.cs @@ -6,7 +6,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg; /// /// Provides enumeration of available JPEG color types. /// -public enum JpegEncodingColor : byte +public enum JpegColorType : byte { /// /// YCbCr (luminance, blue chroma, red chroma) color as defined in the ITU-T T.871 specification. diff --git a/src/ImageSharp/Formats/Jpeg/JpegComData.cs b/src/ImageSharp/Formats/Jpeg/JpegComData.cs new file mode 100644 index 0000000000..4e832d9030 --- /dev/null +++ b/src/ImageSharp/Formats/Jpeg/JpegComData.cs @@ -0,0 +1,32 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +namespace SixLabors.ImageSharp.Formats.Jpeg; + +/// +/// Represents a JPEG comment +/// +public readonly struct JpegComData +{ + /// + /// Initializes a new instance of the struct. + /// + /// The comment buffer. + public JpegComData(ReadOnlyMemory value) + => this.Value = value; + + /// + /// Gets the value. + /// + public ReadOnlyMemory Value { get; } + + /// + /// Converts string to + /// + /// The comment string. + /// The + public static JpegComData FromString(string value) => new(value.AsMemory()); + + /// + public override string ToString() => this.Value.ToString(); +} diff --git a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs index b0bc66008a..2320fe1791 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs @@ -219,7 +219,7 @@ protected override ImageInfo Identify(BufferedReadStream stream, CancellationTok this.InitDerivedMetadataProperties(); Size pixelSize = this.Frame.PixelSize; - return new ImageInfo(new PixelTypeInfo(this.Frame.BitsPerPixel), new(pixelSize.Width, pixelSize.Height), this.Metadata); + return new ImageInfo(new(pixelSize.Width, pixelSize.Height), this.Metadata); } /// @@ -473,9 +473,11 @@ internal void ParseStream(BufferedReadStream stream, SpectralConverter spectralC break; case JpegConstants.Markers.APP15: - case JpegConstants.Markers.COM: stream.Skip(markerContentByteSize); break; + case JpegConstants.Markers.COM: + this.ProcessComMarker(stream, markerContentByteSize); + break; case JpegConstants.Markers.DAC: if (metadataOnly) @@ -508,6 +510,25 @@ public void Dispose() this.scanDecoder = null; } + /// + /// Assigns COM marker bytes to comment property + /// + /// The input stream. + /// The remaining bytes in the segment block. + private void ProcessComMarker(BufferedReadStream stream, int markerContentByteSize) + { + char[] chars = new char[markerContentByteSize]; + JpegMetadata metadata = this.Metadata.GetFormatMetadata(JpegFormat.Instance); + + for (int i = 0; i < markerContentByteSize; i++) + { + int read = stream.ReadByte(); + chars[i] = (char)read; + } + + metadata.Comments.Add(new JpegComData(chars)); + } + /// /// Returns encoded colorspace based on the adobe APP14 marker. /// @@ -575,58 +596,58 @@ internal static JpegColorSpace DeduceJpegColorSpace(byte componentCount) /// Returns the jpeg color type based on the colorspace and subsampling used. /// /// Jpeg color type. - private JpegEncodingColor DeduceJpegColorType() + private JpegColorType DeduceJpegColorType() { switch (this.ColorSpace) { case JpegColorSpace.Grayscale: - return JpegEncodingColor.Luminance; + return JpegColorType.Luminance; case JpegColorSpace.RGB: - return JpegEncodingColor.Rgb; + return JpegColorType.Rgb; case JpegColorSpace.YCbCr: if (this.Frame.Components[0].HorizontalSamplingFactor == 1 && this.Frame.Components[0].VerticalSamplingFactor == 1 && this.Frame.Components[1].HorizontalSamplingFactor == 1 && this.Frame.Components[1].VerticalSamplingFactor == 1 && this.Frame.Components[2].HorizontalSamplingFactor == 1 && this.Frame.Components[2].VerticalSamplingFactor == 1) { - return JpegEncodingColor.YCbCrRatio444; + return JpegColorType.YCbCrRatio444; } else if (this.Frame.Components[0].HorizontalSamplingFactor == 2 && this.Frame.Components[0].VerticalSamplingFactor == 1 && this.Frame.Components[1].HorizontalSamplingFactor == 1 && this.Frame.Components[1].VerticalSamplingFactor == 1 && this.Frame.Components[2].HorizontalSamplingFactor == 1 && this.Frame.Components[2].VerticalSamplingFactor == 1) { - return JpegEncodingColor.YCbCrRatio422; + return JpegColorType.YCbCrRatio422; } else if (this.Frame.Components[0].HorizontalSamplingFactor == 2 && this.Frame.Components[0].VerticalSamplingFactor == 2 && this.Frame.Components[1].HorizontalSamplingFactor == 1 && this.Frame.Components[1].VerticalSamplingFactor == 1 && this.Frame.Components[2].HorizontalSamplingFactor == 1 && this.Frame.Components[2].VerticalSamplingFactor == 1) { - return JpegEncodingColor.YCbCrRatio420; + return JpegColorType.YCbCrRatio420; } else if (this.Frame.Components[0].HorizontalSamplingFactor == 4 && this.Frame.Components[0].VerticalSamplingFactor == 1 && this.Frame.Components[1].HorizontalSamplingFactor == 1 && this.Frame.Components[1].VerticalSamplingFactor == 1 && this.Frame.Components[2].HorizontalSamplingFactor == 1 && this.Frame.Components[2].VerticalSamplingFactor == 1) { - return JpegEncodingColor.YCbCrRatio411; + return JpegColorType.YCbCrRatio411; } else if (this.Frame.Components[0].HorizontalSamplingFactor == 4 && this.Frame.Components[0].VerticalSamplingFactor == 2 && this.Frame.Components[1].HorizontalSamplingFactor == 1 && this.Frame.Components[1].VerticalSamplingFactor == 1 && this.Frame.Components[2].HorizontalSamplingFactor == 1 && this.Frame.Components[2].VerticalSamplingFactor == 1) { - return JpegEncodingColor.YCbCrRatio410; + return JpegColorType.YCbCrRatio410; } else { - return JpegEncodingColor.YCbCrRatio420; + return JpegColorType.YCbCrRatio420; } case JpegColorSpace.Cmyk: - return JpegEncodingColor.Cmyk; + return JpegColorType.Cmyk; case JpegColorSpace.Ycck: - return JpegEncodingColor.Ycck; + return JpegColorType.Ycck; default: - return JpegEncodingColor.YCbCrRatio420; + return JpegColorType.YCbCrRatio420; } } diff --git a/src/ImageSharp/Formats/Jpeg/JpegEncoder.cs b/src/ImageSharp/Formats/Jpeg/JpegEncoder.cs index 5ff4b1694d..0daaae112c 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegEncoder.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegEncoder.cs @@ -45,7 +45,7 @@ public int? Quality /// /// Gets the jpeg color for encoding. /// - public JpegEncodingColor? ColorType { get; init; } + public JpegColorType? ColorType { get; init; } /// protected override void Encode(Image image, Stream stream, CancellationToken cancellationToken) diff --git a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.FrameConfig.cs b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.FrameConfig.cs index 4aed795825..71f852a092 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.FrameConfig.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.FrameConfig.cs @@ -40,7 +40,7 @@ private static JpegFrameConfig[] CreateFrameConfigs() // YCbCr 4:4:4 new JpegFrameConfig( JpegColorSpace.YCbCr, - JpegEncodingColor.YCbCrRatio444, + JpegColorType.YCbCrRatio444, new JpegComponentConfig[] { new JpegComponentConfig(id: 1, hsf: 1, vsf: 1, quantIndex: 0, dcIndex: 0, acIndex: 0), @@ -53,7 +53,7 @@ private static JpegFrameConfig[] CreateFrameConfigs() // YCbCr 4:2:2 new JpegFrameConfig( JpegColorSpace.YCbCr, - JpegEncodingColor.YCbCrRatio422, + JpegColorType.YCbCrRatio422, new JpegComponentConfig[] { new JpegComponentConfig(id: 1, hsf: 2, vsf: 1, quantIndex: 0, dcIndex: 0, acIndex: 0), @@ -66,7 +66,7 @@ private static JpegFrameConfig[] CreateFrameConfigs() // YCbCr 4:2:0 new JpegFrameConfig( JpegColorSpace.YCbCr, - JpegEncodingColor.YCbCrRatio420, + JpegColorType.YCbCrRatio420, new JpegComponentConfig[] { new JpegComponentConfig(id: 1, hsf: 2, vsf: 2, quantIndex: 0, dcIndex: 0, acIndex: 0), @@ -79,7 +79,7 @@ private static JpegFrameConfig[] CreateFrameConfigs() // YCbCr 4:1:1 new JpegFrameConfig( JpegColorSpace.YCbCr, - JpegEncodingColor.YCbCrRatio411, + JpegColorType.YCbCrRatio411, new JpegComponentConfig[] { new JpegComponentConfig(id: 1, hsf: 4, vsf: 1, quantIndex: 0, dcIndex: 0, acIndex: 0), @@ -92,7 +92,7 @@ private static JpegFrameConfig[] CreateFrameConfigs() // YCbCr 4:1:0 new JpegFrameConfig( JpegColorSpace.YCbCr, - JpegEncodingColor.YCbCrRatio410, + JpegColorType.YCbCrRatio410, new JpegComponentConfig[] { new JpegComponentConfig(id: 1, hsf: 4, vsf: 2, quantIndex: 0, dcIndex: 0, acIndex: 0), @@ -105,7 +105,7 @@ private static JpegFrameConfig[] CreateFrameConfigs() // Luminance new JpegFrameConfig( JpegColorSpace.Grayscale, - JpegEncodingColor.Luminance, + JpegColorType.Luminance, new JpegComponentConfig[] { new JpegComponentConfig(id: 0, hsf: 1, vsf: 1, quantIndex: 0, dcIndex: 0, acIndex: 0), @@ -123,7 +123,7 @@ private static JpegFrameConfig[] CreateFrameConfigs() // Rgb new JpegFrameConfig( JpegColorSpace.RGB, - JpegEncodingColor.Rgb, + JpegColorType.Rgb, new JpegComponentConfig[] { new JpegComponentConfig(id: 82, hsf: 1, vsf: 1, quantIndex: 0, dcIndex: 0, acIndex: 0), @@ -146,7 +146,7 @@ private static JpegFrameConfig[] CreateFrameConfigs() // Cmyk new JpegFrameConfig( JpegColorSpace.Cmyk, - JpegEncodingColor.Cmyk, + JpegColorType.Cmyk, new JpegComponentConfig[] { new JpegComponentConfig(id: 1, hsf: 1, vsf: 1, quantIndex: 0, dcIndex: 0, acIndex: 0), @@ -170,7 +170,7 @@ private static JpegFrameConfig[] CreateFrameConfigs() // YccK new JpegFrameConfig( JpegColorSpace.Ycck, - JpegEncodingColor.Ycck, + JpegColorType.Ycck, new JpegComponentConfig[] { new JpegComponentConfig(id: 1, hsf: 1, vsf: 1, quantIndex: 0, dcIndex: 0, acIndex: 0), diff --git a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs index 4477df35cd..a6ff623660 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs @@ -2,6 +2,7 @@ // Licensed under the Six Labors Split License. #nullable disable +using System.Buffers; using System.Buffers.Binary; using SixLabors.ImageSharp.Common.Helpers; using SixLabors.ImageSharp.Formats.Jpeg.Components; @@ -25,6 +26,9 @@ internal sealed unsafe partial class JpegEncoderCore /// private static readonly JpegFrameConfig[] FrameConfigs = CreateFrameConfigs(); + /// + /// The current calling encoder. + /// private readonly JpegEncoder encoder; /// @@ -68,7 +72,7 @@ public void Encode(Image image, Stream stream, CancellationToken JpegMetadata jpegMetadata = metadata.GetJpegMetadata(); JpegFrameConfig frameConfig = this.GetFrameConfig(jpegMetadata); - bool interleaved = this.encoder.Interleaved ?? jpegMetadata.Interleaved ?? true; + bool interleaved = this.encoder.Interleaved ?? jpegMetadata.Interleaved; using JpegFrame frame = new(image, frameConfig, interleaved); // Write the Start Of Image marker. @@ -89,6 +93,9 @@ public void Encode(Image image, Stream stream, CancellationToken // Write Exif, XMP, ICC and IPTC profiles this.WriteProfiles(metadata, buffer); + // Write comments + this.WriteComments(image.Configuration, jpegMetadata); + // Write the image dimensions. this.WriteStartOfFrame(image.Width, image.Height, frameConfig, buffer); @@ -167,6 +174,51 @@ private void WriteJfifApplicationHeader(ImageMetadata meta, Span buffer) this.outputStream.Write(buffer, 0, 18); } + /// + /// Writes the COM tags. + /// + /// The configuration. + /// The image metadata. + private void WriteComments(Configuration configuration, JpegMetadata metadata) + { + if (metadata.Comments.Count == 0) + { + return; + } + + const int maxCommentLength = 65533; + using IMemoryOwner bufferOwner = configuration.MemoryAllocator.Allocate(maxCommentLength); + Span buffer = bufferOwner.Memory.Span; + foreach (JpegComData comment in metadata.Comments) + { + int totalLength = comment.Value.Length; + if (totalLength == 0) + { + continue; + } + + // Loop through and split the comment into multiple comments if the comment length + // is greater than the maximum allowed length. + while (totalLength > 0) + { + int currentLength = Math.Min(totalLength, maxCommentLength); + + // Write the marker header. + this.WriteMarkerHeader(JpegConstants.Markers.COM, currentLength + 2, buffer); + + ReadOnlySpan commentValue = comment.Value.Span.Slice(comment.Value.Length - totalLength, currentLength); + for (int i = 0; i < commentValue.Length; i++) + { + buffer[i] = (byte)commentValue[i]; + } + + // Write the comment. + this.outputStream.Write(buffer, 0, currentLength); + totalLength -= currentLength; + } + } + } + /// /// Writes the Define Huffman Table marker and tables. /// @@ -176,10 +228,7 @@ private void WriteJfifApplicationHeader(ImageMetadata meta, Span buffer) /// is . private void WriteDefineHuffmanTables(JpegHuffmanTableConfig[] tableConfigs, HuffmanScanEncoder scanEncoder, Span buffer) { - if (tableConfigs is null) - { - throw new ArgumentNullException(nameof(tableConfigs)); - } + ArgumentNullException.ThrowIfNull(tableConfigs); int markerlen = 2; @@ -490,17 +539,11 @@ private void WriteIccProfile(IccProfile iccProfile, Span buffer) /// Temporary buffer. private void WriteProfiles(ImageMetadata metadata, Span buffer) { - if (metadata is null) - { - return; - } - // For compatibility, place the profiles in the following order: // - APP1 EXIF // - APP1 XMP // - APP2 ICC // - APP13 IPTC - metadata.SyncProfiles(); this.WriteExifProfile(metadata.ExifProfile, buffer); this.WriteXmpProfile(metadata.XmpProfile, buffer); this.WriteIccProfile(metadata.IccProfile, buffer); @@ -731,7 +774,7 @@ private void WriteDefineQuantizationTables(JpegQuantizationTableConfig[] configs private JpegFrameConfig GetFrameConfig(JpegMetadata metadata) { - JpegEncodingColor color = this.encoder.ColorType ?? metadata.ColorType ?? JpegEncodingColor.YCbCrRatio420; + JpegColorType color = this.encoder.ColorType ?? metadata.ColorType; JpegFrameConfig frameConfig = Array.Find( FrameConfigs, cfg => cfg.EncodingColor == color); diff --git a/src/ImageSharp/Formats/Jpeg/JpegMetadata.cs b/src/ImageSharp/Formats/Jpeg/JpegMetadata.cs index 59fc2f9cba..f2f34ec496 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegMetadata.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegMetadata.cs @@ -2,13 +2,14 @@ // Licensed under the Six Labors Split License. using SixLabors.ImageSharp.Formats.Jpeg.Components; +using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Formats.Jpeg; /// /// Provides Jpeg specific metadata information for the image. /// -public class JpegMetadata : IDeepCloneable +public class JpegMetadata : IFormatMetadata { /// /// Initializes a new instance of the class. @@ -25,6 +26,7 @@ private JpegMetadata(JpegMetadata other) { this.ColorType = other.ColorType; + this.Comments = other.Comments; this.LuminanceQuality = other.LuminanceQuality; this.ChrominanceQuality = other.ChrominanceQuality; } @@ -34,7 +36,7 @@ private JpegMetadata(JpegMetadata other) /// /// /// This value might not be accurate if it was calculated during jpeg decoding - /// with non-complient ITU quantization tables. + /// with non-compliant ITU quantization tables. /// internal int? LuminanceQuality { get; set; } @@ -43,16 +45,17 @@ private JpegMetadata(JpegMetadata other) /// /// /// This value might not be accurate if it was calculated during jpeg decoding - /// with non-complient ITU quantization tables. + /// with non-compliant ITU quantization tables. /// internal int? ChrominanceQuality { get; set; } /// - /// Gets the encoded quality. + /// Gets or sets the encoded quality. /// /// /// Note that jpeg image can have different quality for luminance and chrominance components. /// This property returns maximum value of luma/chroma qualities if both are present. + /// Setting the quality will update both values. /// public int Quality { @@ -67,40 +70,138 @@ public int Quality return this.LuminanceQuality.Value; } - else - { - if (this.ChrominanceQuality.HasValue) - { - return this.ChrominanceQuality.Value; - } - return Quantization.DefaultQualityFactor; - } + return this.ChrominanceQuality ?? Quantization.DefaultQualityFactor; + } + + set + { + this.LuminanceQuality = value; + this.ChrominanceQuality = value; } } /// - /// Gets the color type. + /// Gets or sets the color type. /// - public JpegEncodingColor? ColorType { get; internal set; } + public JpegColorType ColorType { get; set; } = JpegColorType.YCbCrRatio420; /// - /// Gets the component encoding mode. + /// Gets or sets a value indicating whether the component encoding mode should be interleaved. /// /// /// Interleaved encoding mode encodes all color components in a single scan. /// Non-interleaved encoding mode encodes each color component in a separate scan. /// - public bool? Interleaved { get; internal set; } + public bool Interleaved { get; set; } = true; /// - /// Gets the scan encoding mode. + /// Gets or sets a value indicating whether the scan encoding mode is progressive. /// /// /// Progressive jpeg images encode component data across multiple scans. /// - public bool? Progressive { get; internal set; } + public bool Progressive { get; set; } + + /// + /// Gets or sets collection of comments. + /// + public IList Comments { get; set; } = []; + + /// + public static JpegMetadata FromFormatConnectingMetadata(FormatConnectingMetadata metadata) + { + JpegColorType color; + PixelColorType colorType = metadata.PixelTypeInfo.ColorType; + switch (colorType) + { + case PixelColorType.Luminance: + color = JpegColorType.Luminance; + break; + case PixelColorType.CMYK: + color = JpegColorType.Cmyk; + break; + case PixelColorType.YCCK: + color = JpegColorType.Ycck; + break; + default: + if (colorType.HasFlag(PixelColorType.RGB) || colorType.HasFlag(PixelColorType.BGR)) + { + color = JpegColorType.Rgb; + } + else + { + color = metadata.Quality <= Quantization.DefaultQualityFactor + ? JpegColorType.YCbCrRatio420 + : JpegColorType.YCbCrRatio444; + } + + break; + } + + return new JpegMetadata + { + ColorType = color, + ChrominanceQuality = metadata.Quality, + LuminanceQuality = metadata.Quality, + }; + } + + /// + public PixelTypeInfo GetPixelTypeInfo() + { + int bpp; + PixelColorType colorType; + PixelComponentInfo info; + switch (this.ColorType) + { + case JpegColorType.Luminance: + bpp = 8; + colorType = PixelColorType.Luminance; + info = PixelComponentInfo.Create(1, bpp, 8); + break; + case JpegColorType.Cmyk: + bpp = 32; + colorType = PixelColorType.CMYK; + info = PixelComponentInfo.Create(4, bpp, 8, 8, 8, 8); + break; + case JpegColorType.Ycck: + bpp = 32; + colorType = PixelColorType.YCCK; + info = PixelComponentInfo.Create(4, bpp, 8, 8, 8, 8); + break; + case JpegColorType.Rgb: + bpp = 24; + colorType = PixelColorType.RGB; + info = PixelComponentInfo.Create(3, bpp, 8, 8, 8); + break; + default: + bpp = 24; + colorType = PixelColorType.YCbCr; + info = PixelComponentInfo.Create(3, bpp, 8, 8, 8); + break; + } + + return new PixelTypeInfo(bpp) + { + AlphaRepresentation = PixelAlphaRepresentation.None, + ColorType = colorType, + ComponentInfo = info, + }; + } + + /// + public FormatConnectingMetadata ToFormatConnectingMetadata() + => new() + { + EncodingType = EncodingType.Lossy, + PixelTypeInfo = this.GetPixelTypeInfo(), + Quality = this.Quality, + }; + + /// + IDeepCloneable IDeepCloneable.DeepClone() => this.DeepClone(); /// - public IDeepCloneable DeepClone() => new JpegMetadata(this); + public JpegMetadata DeepClone() => new(this); } diff --git a/src/ImageSharp/Formats/Jpeg/MetadataExtensions.cs b/src/ImageSharp/Formats/Jpeg/MetadataExtensions.cs deleted file mode 100644 index 753dfdb60e..0000000000 --- a/src/ImageSharp/Formats/Jpeg/MetadataExtensions.cs +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.Formats.Jpeg; -using SixLabors.ImageSharp.Metadata; - -namespace SixLabors.ImageSharp; - -/// -/// Extension methods for the type. -/// -public static partial class MetadataExtensions -{ - /// - /// Gets the jpeg format specific metadata for the image. - /// - /// The metadata this method extends. - /// The . - public static JpegMetadata GetJpegMetadata(this ImageMetadata metadata) => metadata.GetFormatMetadata(JpegFormat.Instance); -} diff --git a/src/ImageSharp/Formats/Pbm/IPbmEncoderOptions.cs b/src/ImageSharp/Formats/Pbm/IPbmEncoderOptions.cs deleted file mode 100644 index 7039ef2620..0000000000 --- a/src/ImageSharp/Formats/Pbm/IPbmEncoderOptions.cs +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -namespace SixLabors.ImageSharp.Formats.Pbm; - -/// -/// Configuration options for use during PBM encoding. -/// -internal interface IPbmEncoderOptions -{ - /// - /// Gets the encoding of the pixels. - /// - PbmEncoding? Encoding { get; } - - /// - /// Gets the Color type of the resulting image. - /// - PbmColorType? ColorType { get; } - - /// - /// Gets the Data Type of the pixel components. - /// - PbmComponentType? ComponentType { get; } -} diff --git a/src/ImageSharp/Formats/Pbm/MetadataExtensions.cs b/src/ImageSharp/Formats/Pbm/MetadataExtensions.cs deleted file mode 100644 index 6d44e91a50..0000000000 --- a/src/ImageSharp/Formats/Pbm/MetadataExtensions.cs +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.Formats.Pbm; -using SixLabors.ImageSharp.Metadata; - -namespace SixLabors.ImageSharp; - -/// -/// Extension methods for the type. -/// -public static partial class MetadataExtensions -{ - /// - /// Gets the pbm format specific metadata for the image. - /// - /// The metadata this method extends. - /// The . - public static PbmMetadata GetPbmMetadata(this ImageMetadata metadata) => metadata.GetFormatMetadata(PbmFormat.Instance); -} diff --git a/src/ImageSharp/Formats/Pbm/PbmDecoderCore.cs b/src/ImageSharp/Formats/Pbm/PbmDecoderCore.cs index 73a5085c98..9d3dd3ea4c 100644 --- a/src/ImageSharp/Formats/Pbm/PbmDecoderCore.cs +++ b/src/ImageSharp/Formats/Pbm/PbmDecoderCore.cs @@ -62,7 +62,7 @@ protected override Image Decode(BufferedReadStream stream, Cance { this.ProcessHeader(stream); - var image = new Image(this.configuration, this.pixelSize.Width, this.pixelSize.Height, this.metadata); + Image image = new(this.configuration, this.pixelSize.Width, this.pixelSize.Height, this.metadata); Buffer2D pixels = image.GetRootFramePixelBuffer(); @@ -79,10 +79,9 @@ protected override Image Decode(BufferedReadStream stream, Cance protected override ImageInfo Identify(BufferedReadStream stream, CancellationToken cancellationToken) { this.ProcessHeader(stream); - - // BlackAndWhite pixels are encoded into a byte. - int bitsPerPixel = this.componentType == PbmComponentType.Short ? 16 : 8; - return new ImageInfo(new PixelTypeInfo(bitsPerPixel), new(this.pixelSize.Width, this.pixelSize.Height), this.metadata); + return new ImageInfo( + new(this.pixelSize.Width, this.pixelSize.Height), + this.metadata); } /// @@ -90,6 +89,7 @@ protected override ImageInfo Identify(BufferedReadStream stream, CancellationTok /// /// The input stream. /// An EOF marker has been read before the image has been decoded. + [MemberNotNull(nameof(metadata))] private void ProcessHeader(BufferedReadStream stream) { Span buffer = stackalloc byte[2]; diff --git a/src/ImageSharp/Formats/Pbm/PbmEncoder.cs b/src/ImageSharp/Formats/Pbm/PbmEncoder.cs index 8258c91655..f7a9d79366 100644 --- a/src/ImageSharp/Formats/Pbm/PbmEncoder.cs +++ b/src/ImageSharp/Formats/Pbm/PbmEncoder.cs @@ -1,8 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.Advanced; - namespace SixLabors.ImageSharp.Formats.Pbm; /// diff --git a/src/ImageSharp/Formats/Pbm/PbmMetadata.cs b/src/ImageSharp/Formats/Pbm/PbmMetadata.cs index 938e11db16..fec4beda7c 100644 --- a/src/ImageSharp/Formats/Pbm/PbmMetadata.cs +++ b/src/ImageSharp/Formats/Pbm/PbmMetadata.cs @@ -1,12 +1,14 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. +using SixLabors.ImageSharp.PixelFormats; + namespace SixLabors.ImageSharp.Formats.Pbm; /// /// Provides PBM specific metadata information for the image. /// -public class PbmMetadata : IDeepCloneable +public class PbmMetadata : IFormatMetadata { /// /// Initializes a new instance of the class. @@ -41,5 +43,95 @@ private PbmMetadata(PbmMetadata other) public PbmComponentType ComponentType { get; set; } /// - public IDeepCloneable DeepClone() => new PbmMetadata(this); + public static PbmMetadata FromFormatConnectingMetadata(FormatConnectingMetadata metadata) + { + PbmColorType color; + PixelColorType colorType = metadata.PixelTypeInfo.ColorType; + + switch (colorType) + { + case PixelColorType.Binary: + color = PbmColorType.BlackAndWhite; + break; + case PixelColorType.Luminance: + color = PbmColorType.Grayscale; + break; + default: + if (colorType.HasFlag(PixelColorType.RGB) || colorType.HasFlag(PixelColorType.BGR)) + { + color = PbmColorType.Rgb; + } + else + { + color = PbmColorType.Grayscale; + } + + break; + } + + int bpp = metadata.PixelTypeInfo.BitsPerPixel; + PbmComponentType componentType = bpp switch + { + 1 => PbmComponentType.Bit, + <= 8 => PbmComponentType.Byte, + _ => PbmComponentType.Short + }; + + return new PbmMetadata + { + ColorType = color, + ComponentType = componentType + }; + } + + /// + public PixelTypeInfo GetPixelTypeInfo() + { + int bpp; + PixelColorType colorType; + PixelComponentInfo info; + switch (this.ColorType) + { + case PbmColorType.BlackAndWhite: + bpp = 1; + colorType = PixelColorType.Binary; + info = PixelComponentInfo.Create(1, bpp, 1); + break; + case PbmColorType.Rgb: + bpp = this.ComponentType == PbmComponentType.Short ? 48 : 24; + colorType = PixelColorType.RGB; + info = this.ComponentType == PbmComponentType.Short + ? PixelComponentInfo.Create(3, bpp, 16, 16, 16) + : PixelComponentInfo.Create(3, bpp, 8, 8, 8); + break; + case PbmColorType.Grayscale: + default: + bpp = this.ComponentType == PbmComponentType.Short ? 16 : 8; + colorType = PixelColorType.Luminance; + info = this.ComponentType == PbmComponentType.Short + ? PixelComponentInfo.Create(1, bpp, bpp) + : PixelComponentInfo.Create(1, bpp, bpp); + break; + } + + return new PixelTypeInfo(bpp) + { + AlphaRepresentation = PixelAlphaRepresentation.None, + ColorType = colorType, + ComponentInfo = info, + }; + } + + /// + public FormatConnectingMetadata ToFormatConnectingMetadata() + => new() + { + PixelTypeInfo = this.GetPixelTypeInfo(), + }; + + /// + IDeepCloneable IDeepCloneable.DeepClone() => this.DeepClone(); + + /// + public PbmMetadata DeepClone() => new(this); } diff --git a/src/ImageSharp/Formats/PixelTypeInfo.cs b/src/ImageSharp/Formats/PixelTypeInfo.cs deleted file mode 100644 index 1328c65280..0000000000 --- a/src/ImageSharp/Formats/PixelTypeInfo.cs +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.PixelFormats; - -// TODO: Review this class as it's used to represent 2 different things. -// 1.The encoded image pixel format. -// 2. The pixel format of the decoded image. -namespace SixLabors.ImageSharp.Formats; - -/// -/// Contains information about the pixels that make up an images visual data. -/// -public class PixelTypeInfo -{ - /// - /// Initializes a new instance of the class. - /// - /// Color depth, in number of bits per pixel. - public PixelTypeInfo(int bitsPerPixel) - => this.BitsPerPixel = bitsPerPixel; - - /// - /// Initializes a new instance of the class. - /// - /// Color depth, in number of bits per pixel. - /// The pixel alpha transparency behavior. - public PixelTypeInfo(int bitsPerPixel, PixelAlphaRepresentation alpha) - { - this.BitsPerPixel = bitsPerPixel; - this.AlphaRepresentation = alpha; - } - - /// - /// Gets color depth, in number of bits per pixel. - /// - public int BitsPerPixel { get; } - - /// - /// Gets the pixel alpha transparency behavior. - /// means unknown, unspecified. - /// - public PixelAlphaRepresentation? AlphaRepresentation { get; } - - internal static PixelTypeInfo Create() - where TPixel : unmanaged, IPixel - => new(Unsafe.SizeOf() * 8); - - internal static PixelTypeInfo Create(PixelAlphaRepresentation alpha) - where TPixel : unmanaged, IPixel - => new(Unsafe.SizeOf() * 8, alpha); -} diff --git a/src/ImageSharp/Formats/Png/Chunks/FrameControl.cs b/src/ImageSharp/Formats/Png/Chunks/FrameControl.cs index fb2ca473c2..91f79c8154 100644 --- a/src/ImageSharp/Formats/Png/Chunks/FrameControl.cs +++ b/src/ImageSharp/Formats/Png/Chunks/FrameControl.cs @@ -22,8 +22,8 @@ public FrameControl( uint yOffset, ushort delayNumerator, ushort delayDenominator, - PngDisposalMethod disposeOperation, - PngBlendMethod blendOperation) + FrameDisposalMode disposalMode, + FrameBlendMode blendMode) { this.SequenceNumber = sequenceNumber; this.Width = width; @@ -32,8 +32,8 @@ public FrameControl( this.YOffset = yOffset; this.DelayNumerator = delayNumerator; this.DelayDenominator = delayDenominator; - this.DisposeOperation = disposeOperation; - this.BlendOperation = blendOperation; + this.DisposalMode = disposalMode; + this.BlendMode = blendMode; } /// @@ -84,12 +84,12 @@ public FrameControl( /// /// Gets the type of frame area disposal to be done after rendering this frame /// - public PngDisposalMethod DisposeOperation { get; } + public FrameDisposalMode DisposalMode { get; } /// /// Gets the type of frame area rendering for this frame /// - public PngBlendMethod BlendOperation { get; } + public FrameBlendMode BlendMode { get; } public Rectangle Bounds => new((int)this.XOffset, (int)this.YOffset, (int)this.Width, (int)this.Height); @@ -137,8 +137,8 @@ public void WriteTo(Span buffer) BinaryPrimitives.WriteUInt16BigEndian(buffer[20..22], this.DelayNumerator); BinaryPrimitives.WriteUInt16BigEndian(buffer[22..24], this.DelayDenominator); - buffer[24] = (byte)this.DisposeOperation; - buffer[25] = (byte)this.BlendOperation; + buffer[24] = (byte)(this.DisposalMode - 1); + buffer[25] = (byte)this.BlendMode; } /// @@ -155,6 +155,6 @@ public static FrameControl Parse(ReadOnlySpan data) yOffset: BinaryPrimitives.ReadUInt32BigEndian(data[16..20]), delayNumerator: BinaryPrimitives.ReadUInt16BigEndian(data[20..22]), delayDenominator: BinaryPrimitives.ReadUInt16BigEndian(data[22..24]), - disposeOperation: (PngDisposalMethod)data[24], - blendOperation: (PngBlendMethod)data[25]); + disposalMode: (FrameDisposalMode)(data[24] + 1), + blendMode: (FrameBlendMode)data[25]); } diff --git a/src/ImageSharp/Formats/Png/MetadataExtensions.cs b/src/ImageSharp/Formats/Png/MetadataExtensions.cs deleted file mode 100644 index b6313bffe0..0000000000 --- a/src/ImageSharp/Formats/Png/MetadataExtensions.cs +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Diagnostics.CodeAnalysis; -using SixLabors.ImageSharp.Formats; -using SixLabors.ImageSharp.Formats.Png; -using SixLabors.ImageSharp.Metadata; - -namespace SixLabors.ImageSharp; - -/// -/// Extension methods for the type. -/// -public static partial class MetadataExtensions -{ - /// - /// Gets the png format specific metadata for the image. - /// - /// The metadata this method extends. - /// The . - public static PngMetadata GetPngMetadata(this ImageMetadata source) => source.GetFormatMetadata(PngFormat.Instance); - - /// - /// Gets the png format specific metadata for the image. - /// - /// The metadata this method extends. - /// The metadata. - /// - /// if the png metadata exists; otherwise, . - /// - public static bool TryGetPngMetadata(this ImageMetadata source, [NotNullWhen(true)] out PngMetadata? metadata) - => source.TryGetFormatMetadata(PngFormat.Instance, out metadata); - - /// - /// Gets the png format specific metadata for the image frame. - /// - /// The metadata this method extends. - /// The . - public static PngFrameMetadata GetPngMetadata(this ImageFrameMetadata source) => source.GetFormatMetadata(PngFormat.Instance); - - /// - /// Gets the png format specific metadata for the image frame. - /// - /// The metadata this method extends. - /// The metadata. - /// - /// if the png frame metadata exists; otherwise, . - /// - public static bool TryGetPngMetadata(this ImageFrameMetadata source, [NotNullWhen(true)] out PngFrameMetadata? metadata) - => source.TryGetFormatMetadata(PngFormat.Instance, out metadata); - - internal static AnimatedImageMetadata ToAnimatedImageMetadata(this PngMetadata source) - => new() - { - ColorTable = source.ColorTable, - ColorTableMode = FrameColorTableMode.Global, - RepeatCount = (ushort)Numerics.Clamp(source.RepeatCount, 0, ushort.MaxValue), - }; - - internal static AnimatedImageFrameMetadata ToAnimatedImageFrameMetadata(this PngFrameMetadata source) - { - double delay = source.FrameDelay.ToDouble(); - if (double.IsNaN(delay)) - { - delay = 0; - } - - return new() - { - ColorTableMode = FrameColorTableMode.Global, - Duration = TimeSpan.FromMilliseconds(delay * 1000), - DisposalMode = GetMode(source.DisposalMethod), - BlendMode = source.BlendMethod == PngBlendMethod.Source ? FrameBlendMode.Source : FrameBlendMode.Over, - }; - } - - private static FrameDisposalMode GetMode(PngDisposalMethod method) => method switch - { - PngDisposalMethod.DoNotDispose => FrameDisposalMode.DoNotDispose, - PngDisposalMethod.RestoreToBackground => FrameDisposalMode.RestoreToBackground, - PngDisposalMethod.RestoreToPrevious => FrameDisposalMode.RestoreToPrevious, - _ => FrameDisposalMode.Unspecified, - }; -} diff --git a/src/ImageSharp/Formats/Png/PngBitDepth.cs b/src/ImageSharp/Formats/Png/PngBitDepth.cs index 452839d1d4..a5cd2026b2 100644 --- a/src/ImageSharp/Formats/Png/PngBitDepth.cs +++ b/src/ImageSharp/Formats/Png/PngBitDepth.cs @@ -1,4 +1,4 @@ -// Copyright (c) Six Labors. +// Copyright (c) Six Labors. // Licensed under the Six Labors Split License. // Note the value assignment, This will allow us to add 1, 2, and 4 bit encoding when we support it. diff --git a/src/ImageSharp/Formats/Png/PngBlendMethod.cs b/src/ImageSharp/Formats/Png/PngBlendMethod.cs deleted file mode 100644 index f71dce8325..0000000000 --- a/src/ImageSharp/Formats/Png/PngBlendMethod.cs +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -namespace SixLabors.ImageSharp.Formats.Png; - -/// -/// Specifies whether the frame is to be alpha blended into the current output buffer content, -/// or whether it should completely replace its region in the output buffer. -/// -public enum PngBlendMethod -{ - /// - /// All color components of the frame, including alpha, overwrite the current contents of the frame's output buffer region. - /// - Source, - - /// - /// The frame should be composited onto the output buffer based on its alpha, using a simple OVER operation as - /// described in the "Alpha Channel Processing" section of the PNG specification [PNG-1.2]. - /// - Over -} diff --git a/src/ImageSharp/Formats/Png/PngChunk.cs b/src/ImageSharp/Formats/Png/PngChunk.cs index 6ec0df9ad6..3883986d06 100644 --- a/src/ImageSharp/Formats/Png/PngChunk.cs +++ b/src/ImageSharp/Formats/Png/PngChunk.cs @@ -41,13 +41,13 @@ public PngChunk(int length, PngChunkType type, IMemoryOwner data = null) /// /// Gets a value indicating whether the given chunk is critical to decoding /// - /// The chunk CRC handling behavior. - public bool IsCritical(PngCrcChunkHandling handling) + /// The segment handling behavior. + public bool IsCritical(SegmentIntegrityHandling handling) => handling switch { - PngCrcChunkHandling.IgnoreNone => true, - PngCrcChunkHandling.IgnoreNonCritical => this.Type is PngChunkType.Header or PngChunkType.Palette or PngChunkType.Data or PngChunkType.FrameData, - PngCrcChunkHandling.IgnoreData => this.Type is PngChunkType.Header or PngChunkType.Palette, + SegmentIntegrityHandling.IgnoreNone => true, + SegmentIntegrityHandling.IgnoreNonCritical => this.Type is PngChunkType.Header or PngChunkType.Palette or PngChunkType.Data or PngChunkType.FrameData, + SegmentIntegrityHandling.IgnoreData => this.Type is PngChunkType.Header or PngChunkType.Palette, _ => false, }; } diff --git a/src/ImageSharp/Formats/Png/PngCrcChunkHandling.cs b/src/ImageSharp/Formats/Png/PngCrcChunkHandling.cs deleted file mode 100644 index 264d737fdc..0000000000 --- a/src/ImageSharp/Formats/Png/PngCrcChunkHandling.cs +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -namespace SixLabors.ImageSharp.Formats.Png; - -/// -/// Specifies how to handle validation of any CRC (Cyclic Redundancy Check) data within the encoded PNG. -/// -public enum PngCrcChunkHandling -{ - /// - /// Do not ignore any CRC chunk errors. - /// - IgnoreNone, - - /// - /// Ignore CRC errors in non critical chunks. - /// - IgnoreNonCritical, - - /// - /// Ignore CRC errors in data chunks. - /// - IgnoreData, - - /// - /// Ignore CRC errors in all chunks. - /// - IgnoreAll -} diff --git a/src/ImageSharp/Formats/Png/PngDecoder.cs b/src/ImageSharp/Formats/Png/PngDecoder.cs index 4a7ba3f961..cfea0e6020 100644 --- a/src/ImageSharp/Formats/Png/PngDecoder.cs +++ b/src/ImageSharp/Formats/Png/PngDecoder.cs @@ -53,8 +53,8 @@ protected override Image Decode(PngDecoderOptions options, Stream stream, Cancel stream.Position = 0; PngMetadata meta = info.Metadata.GetPngMetadata(); - PngColorType color = meta.ColorType.GetValueOrDefault(); - PngBitDepth bits = meta.BitDepth.GetValueOrDefault(); + PngColorType color = meta.ColorType; + PngBitDepth bits = meta.BitDepth; switch (color) { @@ -101,5 +101,5 @@ protected override Image Decode(PngDecoderOptions options, Stream stream, Cancel } /// - protected override PngDecoderOptions CreateDefaultSpecializedOptions(DecoderOptions options) => new PngDecoderOptions() { GeneralOptions = options }; + protected override PngDecoderOptions CreateDefaultSpecializedOptions(DecoderOptions options) => new() { GeneralOptions = options }; } diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index 44e76407c5..484241d52f 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -6,6 +6,7 @@ using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.IO.Compression; +using System.IO.Hashing; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Text; @@ -118,7 +119,12 @@ internal sealed class PngDecoderCore : ImageDecoderCore /// /// How to handle CRC errors. /// - private readonly PngCrcChunkHandling pngCrcChunkHandling; + private readonly SegmentIntegrityHandling segmentIntegrityHandling; + + /// + /// A reusable Crc32 hashing instance. + /// + private readonly Crc32 crc32 = new(); /// /// The maximum memory in bytes that a zTXt, sPLT, iTXt, iCCP, or unknown chunk can occupy when decompressed. @@ -136,7 +142,7 @@ public PngDecoderCore(PngDecoderOptions options) this.maxFrames = options.GeneralOptions.MaxFrames; this.skipMetadata = options.GeneralOptions.SkipMetadata; this.memoryAllocator = this.configuration.MemoryAllocator; - this.pngCrcChunkHandling = options.PngCrcChunkHandling; + this.segmentIntegrityHandling = options.GeneralOptions.SegmentIntegrityHandling; this.maxUncompressedLength = options.MaxUncompressedAncillaryChunkSizeBytes; } @@ -148,7 +154,7 @@ internal PngDecoderCore(PngDecoderOptions options, bool colorMetadataOnly) this.skipMetadata = true; this.configuration = options.GeneralOptions.Configuration; this.memoryAllocator = this.configuration.MemoryAllocator; - this.pngCrcChunkHandling = options.PngCrcChunkHandling; + this.segmentIntegrityHandling = options.GeneralOptions.SegmentIntegrityHandling; this.maxUncompressedLength = options.MaxUncompressedAncillaryChunkSizeBytes; } @@ -228,7 +234,7 @@ protected override Image Decode(BufferedReadStream stream, Cance cancellationToken); // if current frame dispose is restore to previous, then from future frame's perspective, it never happened - if (currentFrameControl.Value.DisposeOperation != PngDisposalMethod.RestoreToPrevious) + if (currentFrameControl.Value.DisposalMode != FrameDisposalMode.RestoreToPrevious) { previousFrame = currentFrame; previousFrameControl = currentFrameControl; @@ -332,9 +338,10 @@ protected override ImageInfo Identify(BufferedReadStream stream, CancellationTok { uint frameCount = 0; ImageMetadata metadata = new(); + List framesMetadata = []; PngMetadata pngMetadata = metadata.GetPngMetadata(); this.currentStream = stream; - FrameControl? lastFrameControl = null; + FrameControl? currentFrameControl = null; Span buffer = stackalloc byte[20]; this.currentStream.Skip(8); @@ -387,7 +394,8 @@ protected override ImageInfo Identify(BufferedReadStream stream, CancellationTok break; } - lastFrameControl = this.ReadFrameControlChunk(chunk.Data.GetSpan()); + currentFrameControl = this.ReadFrameControlChunk(chunk.Data.GetSpan()); + break; case PngChunkType.FrameData: if (frameCount >= this.maxFrames) @@ -400,22 +408,35 @@ protected override ImageInfo Identify(BufferedReadStream stream, CancellationTok goto EOF; } - if (lastFrameControl is null) + if (currentFrameControl is null) { PngThrowHelper.ThrowMissingFrameControl(); } + InitializeFrameMetadata(framesMetadata, currentFrameControl.Value); + // Skip sequence number this.currentStream.Skip(4); this.SkipChunkDataAndCrc(chunk); break; case PngChunkType.Data: + // Spec says tRNS must be before IDAT so safe to exit. if (this.colorMetadataOnly) { goto EOF; } + pngMetadata.AnimateRootFrame = currentFrameControl != null; + currentFrameControl ??= new((uint)this.header.Width, (uint)this.header.Height); + if (framesMetadata.Count == 0) + { + InitializeFrameMetadata(framesMetadata, currentFrameControl.Value); + + // Both PLTE and tRNS chunks, if present, have been read at this point as per spec. + AssignColorPalette(this.palette, this.paletteAlpha, pngMetadata); + } + this.SkipChunkDataAndCrc(chunk); break; case PngChunkType.Palette: @@ -499,10 +520,7 @@ protected override ImageInfo Identify(BufferedReadStream stream, CancellationTok PngThrowHelper.ThrowInvalidHeader(); } - // Both PLTE and tRNS chunks, if present, have been read at this point as per spec. - AssignColorPalette(this.palette, this.paletteAlpha, pngMetadata); - - return new ImageInfo(new PixelTypeInfo(this.CalculateBitsPerPixel()), new(this.header.Width, this.header.Height), metadata); + return new ImageInfo(new(this.header.Width, this.header.Height), metadata, framesMetadata); } finally { @@ -646,12 +664,12 @@ private void InitializeFrame( // If the first `fcTL` chunk uses a `dispose_op` of APNG_DISPOSE_OP_PREVIOUS it should be treated as APNG_DISPOSE_OP_BACKGROUND. // So, if restoring to before first frame, clear entire area. Same if first frame (previousFrameControl null). - if (previousFrameControl == null || (previousFrame is null && previousFrameControl.Value.DisposeOperation == PngDisposalMethod.RestoreToPrevious)) + if (previousFrameControl == null || (previousFrame is null && previousFrameControl.Value.DisposalMode == FrameDisposalMode.RestoreToPrevious)) { Buffer2DRegion pixelRegion = frame.PixelBuffer.GetRegion(); pixelRegion.Clear(); } - else if (previousFrameControl.Value.DisposeOperation == PngDisposalMethod.RestoreToBackground) + else if (previousFrameControl.Value.DisposalMode == FrameDisposalMode.RestoreToBackground) { Rectangle restoreArea = previousFrameControl.Value.Bounds; Buffer2DRegion pixelRegion = frame.PixelBuffer.GetRegion(restoreArea); @@ -667,27 +685,12 @@ private void InitializeFrame( this.scanline = this.configuration.MemoryAllocator.Allocate(this.bytesPerScanline, AllocationOptions.Clean); } - /// - /// Calculates the correct number of bits per pixel for the given color type. - /// - /// The - private int CalculateBitsPerPixel() + private static void InitializeFrameMetadata(List imageFrameMetadata, FrameControl currentFrameControl) { - switch (this.pngColorType) - { - case PngColorType.Grayscale: - case PngColorType.Palette: - return this.header.BitDepth; - case PngColorType.GrayscaleWithAlpha: - return this.header.BitDepth * 2; - case PngColorType.Rgb: - return this.header.BitDepth * 3; - case PngColorType.RgbWithAlpha: - return this.header.BitDepth * 4; - default: - PngThrowHelper.ThrowNotSupportedColor(); - return -1; - } + ImageFrameMetadata meta = new(); + PngFrameMetadata frameMetadata = meta.GetPngMetadata(); + frameMetadata.FromChunk(currentFrameControl); + imageFrameMetadata.Add(meta); } /// @@ -781,8 +784,8 @@ private void DecodePixelData( int height = (int)frameControl.YMax; IMemoryOwner? blendMemory = null; - Span blendRowBuffer = Span.Empty; - if (frameControl.BlendOperation == PngBlendMethod.Over) + Span blendRowBuffer = []; + if (frameControl.BlendMode == FrameBlendMode.Over) { blendMemory = this.memoryAllocator.Allocate(imageFrame.Width, AllocationOptions.Clean); blendRowBuffer = blendMemory.Memory.Span; @@ -830,7 +833,7 @@ private void DecodePixelData( break; default: - if (this.pngCrcChunkHandling is PngCrcChunkHandling.IgnoreData or PngCrcChunkHandling.IgnoreAll) + if (this.segmentIntegrityHandling is SegmentIntegrityHandling.IgnoreData or SegmentIntegrityHandling.IgnoreAll) { goto EXIT; } @@ -874,8 +877,8 @@ private void DecodeInterlacedPixelData( Buffer2D imageBuffer = imageFrame.PixelBuffer; IMemoryOwner? blendMemory = null; - Span blendRowBuffer = Span.Empty; - if (frameControl.BlendOperation == PngBlendMethod.Over) + Span blendRowBuffer = []; + if (frameControl.BlendMode == FrameBlendMode.Over) { blendMemory = this.memoryAllocator.Allocate(imageFrame.Width, AllocationOptions.Clean); blendRowBuffer = blendMemory.Memory.Span; @@ -936,7 +939,7 @@ private void DecodeInterlacedPixelData( break; default: - if (this.pngCrcChunkHandling is PngCrcChunkHandling.IgnoreData or PngCrcChunkHandling.IgnoreAll) + if (this.segmentIntegrityHandling is SegmentIntegrityHandling.IgnoreData or SegmentIntegrityHandling.IgnoreAll) { goto EXIT; } @@ -1000,7 +1003,7 @@ private void ProcessDefilteredScanline( { Span destination = pixels.PixelBuffer.DangerousGetRowSpan(currentRow); - bool blend = frameControl.BlendOperation == PngBlendMethod.Over; + bool blend = frameControl.BlendMode == FrameBlendMode.Over; Span rowSpan = blend ? blendRowBuffer : destination; @@ -1113,7 +1116,7 @@ private void ProcessInterlacedDefilteredScanline( int increment = 1) where TPixel : unmanaged, IPixel { - bool blend = frameControl.BlendOperation == PngBlendMethod.Over; + bool blend = frameControl.BlendMode == FrameBlendMode.Over; Span rowSpan = blend ? blendRowBuffer : destination; @@ -1229,10 +1232,7 @@ private static void AssignColorPalette(ReadOnlySpan palette, ReadOnlySpan< Color[] colorTable = new Color[palette.Length / Unsafe.SizeOf()]; ReadOnlySpan rgbTable = MemoryMarshal.Cast(palette); - for (int i = 0; i < colorTable.Length; i++) - { - colorTable[i] = new Color(rgbTable[i]); - } + Color.FromPixel(rgbTable, colorTable); if (alpha.Length > 0) { @@ -1265,14 +1265,14 @@ private void AssignTransparentMarkers(ReadOnlySpan alpha, PngMetadata pngM ushort gc = BinaryPrimitives.ReadUInt16LittleEndian(alpha.Slice(2, 2)); ushort bc = BinaryPrimitives.ReadUInt16LittleEndian(alpha.Slice(4, 2)); - pngMetadata.TransparentColor = new(new Rgb48(rc, gc, bc)); + pngMetadata.TransparentColor = Color.FromPixel(new Rgb48(rc, gc, bc)); return; } byte r = ReadByteLittleEndian(alpha, 0); byte g = ReadByteLittleEndian(alpha, 2); byte b = ReadByteLittleEndian(alpha, 4); - pngMetadata.TransparentColor = new(new Rgb24(r, g, b)); + pngMetadata.TransparentColor = Color.FromPixel(new Rgb24(r, g, b)); } } else if (this.pngColorType == PngColorType.Grayscale) @@ -1451,7 +1451,20 @@ private static void ReadCicpChunk(ImageMetadata metadata, ReadOnlySpan dat byte colorPrimaries = data[0]; byte transferFunction = data[1]; byte matrixCoefficients = data[2]; - bool? fullRange = data[3] == 1 ? true : data[3] == 0 ? false : null; + bool? fullRange; + if (data[3] == 1) + { + fullRange = true; + } + else if (data[3] == 0) + { + fullRange = false; + } + else + { + fullRange = null; + } + metadata.CicpProfile = new CicpProfile(colorPrimaries, transferFunction, matrixCoefficients, fullRange); } @@ -1483,7 +1496,7 @@ private static bool TryReadLegacyExifTextChunk(ImageMetadata metadata, string da // Sequence of bytes for the exif header ("Exif" ASCII and two zero bytes). // This doesn't actually allocate. - ReadOnlySpan exifHeader = new byte[] { 0x45, 0x78, 0x69, 0x66, 0x00, 0x00 }; + ReadOnlySpan exifHeader = [0x45, 0x78, 0x69, 0x66, 0x00, 0x00]; if (dataLength < exifHeader.Length) { @@ -1594,7 +1607,7 @@ private unsafe bool TryDecompressZlibData(ReadOnlySpan compressedData, int Span destUncompressedData = destBuffer.GetSpan(); if (!inflateStream.AllocateNewBytes(compressedData.Length, false)) { - uncompressedBytesArray = Array.Empty(); + uncompressedBytesArray = []; return false; } @@ -1603,7 +1616,7 @@ private unsafe bool TryDecompressZlibData(ReadOnlySpan compressedData, int { if (memoryStreamOutput.Length > maxLength) { - uncompressedBytesArray = Array.Empty(); + uncompressedBytesArray = []; return false; } @@ -1914,15 +1927,16 @@ private bool TryReadChunk(Span buffer, out PngChunk chunk) private void ValidateChunk(in PngChunk chunk, Span buffer) { uint inputCrc = this.ReadChunkCrc(buffer); - if (chunk.IsCritical(this.pngCrcChunkHandling)) + if (chunk.IsCritical(this.segmentIntegrityHandling)) { Span chunkType = stackalloc byte[4]; BinaryPrimitives.WriteUInt32BigEndian(chunkType, (uint)chunk.Type); - uint validCrc = Crc32.Calculate(chunkType); - validCrc = Crc32.Calculate(validCrc, chunk.Data.GetSpan()); + this.crc32.Reset(); + this.crc32.Append(chunkType); + this.crc32.Append(chunk.Data.GetSpan()); - if (validCrc != inputCrc) + if (this.crc32.GetCurrentHashAsUInt32() != inputCrc) { string chunkTypeName = Encoding.ASCII.GetString(chunkType); @@ -1969,7 +1983,7 @@ private IMemoryOwner ReadChunkData(int length) { if (length == 0) { - return new BasicArrayBuffer(Array.Empty()); + return new BasicArrayBuffer([]); } // We rent the buffer here to return it afterwards in Decode() @@ -2050,8 +2064,7 @@ private static bool TryReadTextKeyword(ReadOnlySpan keywordBytes, out stri // Keywords should not be empty or have leading or trailing whitespace. name = PngConstants.Encoding.GetString(keywordBytes); return !string.IsNullOrWhiteSpace(name) - && !name.StartsWith(" ", StringComparison.Ordinal) - && !name.EndsWith(" ", StringComparison.Ordinal); + && !name.StartsWith(' ') && !name.EndsWith(' '); } private static bool IsXmpTextData(ReadOnlySpan keywordBytes) diff --git a/src/ImageSharp/Formats/Png/PngDecoderOptions.cs b/src/ImageSharp/Formats/Png/PngDecoderOptions.cs index abfa4b1da8..a73db87774 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderOptions.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderOptions.cs @@ -11,11 +11,6 @@ public sealed class PngDecoderOptions : ISpecializedDecoderOptions /// public DecoderOptions GeneralOptions { get; init; } = new DecoderOptions(); - /// - /// Gets a value indicating how to handle validation of any CRC (Cyclic Redundancy Check) data within the encoded PNG. - /// - public PngCrcChunkHandling PngCrcChunkHandling { get; init; } = PngCrcChunkHandling.IgnoreNonCritical; - /// /// Gets the maximum memory in bytes that a zTXt, sPLT, iTXt, iCCP, or unknown chunk can occupy when decompressed. /// Defaults to 8MB diff --git a/src/ImageSharp/Formats/Png/PngDisposalMethod.cs b/src/ImageSharp/Formats/Png/PngDisposalMethod.cs deleted file mode 100644 index 1537c5cedf..0000000000 --- a/src/ImageSharp/Formats/Png/PngDisposalMethod.cs +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -namespace SixLabors.ImageSharp.Formats.Png; - -/// -/// Specifies how the output buffer should be changed at the end of the delay (before rendering the next frame). -/// -public enum PngDisposalMethod -{ - /// - /// No disposal is done on this frame before rendering the next; the contents of the output buffer are left as is. - /// - DoNotDispose, - - /// - /// The frame's region of the output buffer is to be cleared to fully transparent black before rendering the next frame. - /// - RestoreToBackground, - - /// - /// The frame's region of the output buffer is to be reverted to the previous contents before rendering the next frame. - /// - RestoreToPrevious -} diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index e01b5c2a59..4bbb68358f 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -3,15 +3,14 @@ using System.Buffers; using System.Buffers.Binary; +using System.IO.Hashing; using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using SixLabors.ImageSharp.Common.Helpers; using SixLabors.ImageSharp.Compression.Zlib; -using SixLabors.ImageSharp.Formats.Gif; using SixLabors.ImageSharp.Formats.Png.Chunks; using SixLabors.ImageSharp.Formats.Png.Filters; -using SixLabors.ImageSharp.Formats.Webp; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Metadata; using SixLabors.ImageSharp.PixelFormats; @@ -124,6 +123,11 @@ internal sealed class PngEncoderCore : IDisposable /// private int derivedTransparencyIndex = -1; + /// + /// A reusable Crc32 hashing instance. + /// + private readonly Crc32 crc32 = new(); + /// /// Initializes a new instance of the class. /// @@ -154,7 +158,7 @@ public void Encode(Image image, Stream stream, CancellationToken this.height = image.Height; ImageMetadata metadata = image.Metadata; - PngMetadata pngMetadata = GetPngMetadata(image); + PngMetadata pngMetadata = metadata.ClonePngMetadata(); this.SanitizeAndSetEncoderOptions(this.encoder, pngMetadata, out this.use16Bit, out this.bytesPerPixel); stream.Write(PngConstants.HeaderBytes); @@ -205,8 +209,8 @@ public void Encode(Image image, Stream stream, CancellationToken { // Write the first animated frame. currentFrame = image.Frames[currentFrameIndex]; - PngFrameMetadata frameMetadata = GetPngFrameMetadata(currentFrame); - PngDisposalMethod previousDisposal = frameMetadata.DisposalMethod; + PngFrameMetadata frameMetadata = currentFrame.Metadata.GetPngMetadata(); + FrameDisposalMode previousDisposal = frameMetadata.DisposalMode; FrameControl frameControl = this.WriteFrameControlChunk(stream, frameMetadata, currentFrame.Bounds(), 0); uint sequenceNumber = 1; if (pngMetadata.AnimateRootFrame) @@ -231,12 +235,12 @@ public void Encode(Image image, Stream stream, CancellationToken for (; currentFrameIndex < image.Frames.Count; currentFrameIndex++) { - ImageFrame? prev = previousDisposal == PngDisposalMethod.RestoreToBackground ? null : previousFrame; + ImageFrame? prev = previousDisposal == FrameDisposalMode.RestoreToBackground ? null : previousFrame; currentFrame = image.Frames[currentFrameIndex]; ImageFrame? nextFrame = currentFrameIndex < image.Frames.Count - 1 ? image.Frames[currentFrameIndex + 1] : null; - frameMetadata = GetPngFrameMetadata(currentFrame); - bool blend = frameMetadata.BlendMethod == PngBlendMethod.Over; + frameMetadata = currentFrame.Metadata.GetPngMetadata(); + bool blend = frameMetadata.BlendMode == FrameBlendMode.Over; (bool difference, Rectangle bounds) = AnimationUtilities.DeDuplicatePixels( @@ -262,7 +266,7 @@ public void Encode(Image image, Stream stream, CancellationToken sequenceNumber += this.WriteDataChunks(frameControl, encodingFrame.PixelBuffer.GetRegion(bounds), quantized, stream, true) + 1; previousFrame = currentFrame; - previousDisposal = frameMetadata.DisposalMethod; + previousDisposal = frameMetadata.DisposalMode; } } @@ -282,54 +286,6 @@ public void Dispose() this.currentScanline?.Dispose(); } - private static PngMetadata GetPngMetadata(Image image) - where TPixel : unmanaged, IPixel - { - if (image.Metadata.TryGetPngMetadata(out PngMetadata? png)) - { - return (PngMetadata)png.DeepClone(); - } - - if (image.Metadata.TryGetGifMetadata(out GifMetadata? gif)) - { - AnimatedImageMetadata ani = gif.ToAnimatedImageMetadata(); - return PngMetadata.FromAnimatedMetadata(ani); - } - - if (image.Metadata.TryGetWebpMetadata(out WebpMetadata? webp)) - { - AnimatedImageMetadata ani = webp.ToAnimatedImageMetadata(); - return PngMetadata.FromAnimatedMetadata(ani); - } - - // Return explicit new instance so we do not mutate the original metadata. - return new(); - } - - private static PngFrameMetadata GetPngFrameMetadata(ImageFrame frame) - where TPixel : unmanaged, IPixel - { - if (frame.Metadata.TryGetPngMetadata(out PngFrameMetadata? png)) - { - return (PngFrameMetadata)png.DeepClone(); - } - - if (frame.Metadata.TryGetGifMetadata(out GifFrameMetadata? gif)) - { - AnimatedImageFrameMetadata ani = gif.ToAnimatedImageFrameMetadata(); - return PngFrameMetadata.FromAnimatedMetadata(ani); - } - - if (frame.Metadata.TryGetWebpFrameMetadata(out WebpFrameMetadata? webp)) - { - AnimatedImageFrameMetadata ani = webp.ToAnimatedImageFrameMetadata(); - return PngFrameMetadata.FromAnimatedMetadata(ani); - } - - // Return explicit new instance so we do not mutate the original metadata. - return new(); - } - /// /// Convert transparent pixels, to transparent black pixels, which can yield to better compression in some cases. /// @@ -340,18 +296,17 @@ private static void ClearTransparentPixels(ImageFrame clone) => clone.ProcessPixelRows(accessor => { // TODO: We should be able to speed this up with SIMD and masking. - Rgba32 rgba32 = default; - Rgba32 transparent = Color.Transparent; + Rgba32 transparent = Color.Transparent.ToPixel(); for (int y = 0; y < accessor.Height; y++) { Span span = accessor.GetRowSpan(y); for (int x = 0; x < accessor.Width; x++) { - span[x].ToRgba32(ref rgba32); - - if (rgba32.A is 0) + ref TPixel pixel = ref span[x]; + Rgba32 rgba = pixel.ToRgba32(); + if (rgba.A is 0) { - span[x].FromRgba32(transparent); + pixel = TPixel.FromRgba32(transparent); } } } @@ -821,7 +776,6 @@ private void WriteExifChunk(Stream stream, ImageMetadata meta) return; } - meta.SyncProfiles(); this.WriteChunk(stream, PngChunkType.Exif, meta.ExifProfile.ToByteArray()); } @@ -876,6 +830,7 @@ private void WriteXmpChunk(Stream stream, ImageMetadata meta) /// /// The containing image data. /// The image meta data. + /// CICP matrix coefficients other than Identity are not supported in PNG. private void WriteCicpChunk(Stream stream, ImageMetadata metaData) { if (metaData.CicpProfile is null) @@ -1078,7 +1033,7 @@ private void WriteTransparencyChunk(Stream stream, PngMetadata pngMetadata) else { alpha.Clear(); - Rgb24 rgb = pngMetadata.TransparentColor.Value.ToRgb24(); + Rgb24 rgb = pngMetadata.TransparentColor.Value.ToPixel(); alpha[1] = rgb.R; alpha[3] = rgb.G; alpha[5] = rgb.B; @@ -1120,8 +1075,8 @@ private FrameControl WriteFrameControlChunk(Stream stream, PngFrameMetadata fram yOffset: (uint)bounds.Top, delayNumerator: (ushort)frameMetadata.FrameDelay.Numerator, delayDenominator: (ushort)frameMetadata.FrameDelay.Denominator, - disposeOperation: frameMetadata.DisposalMethod, - blendOperation: frameMetadata.BlendMethod); + disposalMode: frameMetadata.DisposalMode, + blendMode: frameMetadata.BlendMode); fcTL.WriteTo(this.chunkDataBuffer.Span); @@ -1381,16 +1336,17 @@ private void WriteChunk(Stream stream, PngChunkType type, Span data, int o stream.Write(buffer); - uint crc = Crc32.Calculate(buffer[4..]); // Write the type buffer + this.crc32.Reset(); + this.crc32.Append(buffer[4..]); // Write the type buffer if (data.Length > 0 && length > 0) { stream.Write(data, offset, length); - crc = Crc32.Calculate(crc, data.Slice(offset, length)); + this.crc32.Append(data.Slice(offset, length)); } - BinaryPrimitives.WriteUInt32BigEndian(buffer, crc); + BinaryPrimitives.WriteUInt32BigEndian(buffer, this.crc32.GetCurrentHashAsUInt32()); stream.Write(buffer, 0, 4); // write the crc } @@ -1413,16 +1369,17 @@ private void WriteFrameDataChunk(Stream stream, uint sequenceNumber, Span stream.Write(buffer); - uint crc = Crc32.Calculate(buffer[4..]); // Write the type buffer + this.crc32.Reset(); + this.crc32.Append(buffer[4..]); // Write the type buffer if (data.Length > 0 && length > 0) { stream.Write(data, offset, length); - crc = Crc32.Calculate(crc, data.Slice(offset, length)); + this.crc32.Append(data.Slice(offset, length)); } - BinaryPrimitives.WriteUInt32BigEndian(buffer, crc); + BinaryPrimitives.WriteUInt32BigEndian(buffer, this.crc32.GetCurrentHashAsUInt32()); stream.Write(buffer, 0, 4); // write the crc } @@ -1476,7 +1433,20 @@ private void SanitizeAndSetEncoderOptions( // Use options, then check metadata, if nothing set there then we suggest // a sensible default based upon the pixel format. - this.colorType = encoder.ColorType ?? pngMetadata.ColorType ?? SuggestColorType(); + PngColorType color = encoder.ColorType ?? pngMetadata.ColorType; + byte bits = (byte)(encoder.BitDepth ?? pngMetadata.BitDepth); + + // Ensure the bit depth and color type are a supported combination. + // Bit8 is the only bit depth supported by all color types. + byte[] validBitDepths = PngConstants.ColorTypes[color]; + if (Array.IndexOf(validBitDepths, bits) == -1) + { + bits = (byte)PngBitDepth.Bit8; + } + + this.colorType = color; + this.bitDepth = bits; + if (encoder.FilterMethod.HasValue) { this.filterMethod = encoder.FilterMethod.Value; @@ -1487,20 +1457,10 @@ private void SanitizeAndSetEncoderOptions( this.filterMethod = this.colorType is PngColorType.Palette ? PngFilterMethod.None : PngFilterMethod.Paeth; } - // Ensure bit depth and color type are a supported combination. - // Bit8 is the only bit depth supported by all color types. - byte bits = (byte)(encoder.BitDepth ?? pngMetadata.BitDepth ?? SuggestBitDepth()); - byte[] validBitDepths = PngConstants.ColorTypes[this.colorType]; - if (Array.IndexOf(validBitDepths, bits) == -1) - { - bits = (byte)PngBitDepth.Bit8; - } - - this.bitDepth = bits; use16Bit = bits == (byte)PngBitDepth.Bit16; bytesPerPixel = CalculateBytesPerPixel(this.colorType, use16Bit); - this.interlaceMode = (encoder.InterlaceMethod ?? pngMetadata.InterlaceMethod)!.Value; + this.interlaceMode = encoder.InterlaceMethod ?? pngMetadata.InterlaceMethod; this.chunkFilter = encoder.SkipMetadata ? PngChunkFilter.ExcludeAll : encoder.ChunkFilter ?? PngChunkFilter.None; } @@ -1640,56 +1600,6 @@ private static int CalculateBytesPerPixel(PngColorType? pngColorType, bool use16 _ => use16Bit ? 8 : 4, }; - /// - /// Returns a suggested for the given - /// This is not exhaustive but covers many common pixel formats. - /// - /// The type of pixel format. - private static PngColorType SuggestColorType() - where TPixel : unmanaged, IPixel - => default(TPixel) switch - { - A8 => PngColorType.GrayscaleWithAlpha, - Argb32 => PngColorType.RgbWithAlpha, - Bgr24 => PngColorType.Rgb, - Bgra32 => PngColorType.RgbWithAlpha, - L8 => PngColorType.Grayscale, - L16 => PngColorType.Grayscale, - La16 => PngColorType.GrayscaleWithAlpha, - La32 => PngColorType.GrayscaleWithAlpha, - Rgb24 => PngColorType.Rgb, - Rgba32 => PngColorType.RgbWithAlpha, - Rgb48 => PngColorType.Rgb, - Rgba64 => PngColorType.RgbWithAlpha, - RgbaVector => PngColorType.RgbWithAlpha, - _ => PngColorType.RgbWithAlpha - }; - - /// - /// Returns a suggested for the given - /// This is not exhaustive but covers many common pixel formats. - /// - /// The type of pixel format. - private static PngBitDepth SuggestBitDepth() - where TPixel : unmanaged, IPixel - => default(TPixel) switch - { - A8 => PngBitDepth.Bit8, - Argb32 => PngBitDepth.Bit8, - Bgr24 => PngBitDepth.Bit8, - Bgra32 => PngBitDepth.Bit8, - L8 => PngBitDepth.Bit8, - L16 => PngBitDepth.Bit16, - La16 => PngBitDepth.Bit8, - La32 => PngBitDepth.Bit16, - Rgb24 => PngBitDepth.Bit8, - Rgba32 => PngBitDepth.Bit8, - Rgb48 => PngBitDepth.Bit16, - Rgba64 => PngBitDepth.Bit16, - RgbaVector => PngBitDepth.Bit16, - _ => PngBitDepth.Bit8 - }; - private unsafe struct ScratchBuffer { private const int Size = 26; diff --git a/src/ImageSharp/Formats/Png/PngFrameMetadata.cs b/src/ImageSharp/Formats/Png/PngFrameMetadata.cs index dbda4d73c9..c142a1c8e0 100644 --- a/src/ImageSharp/Formats/Png/PngFrameMetadata.cs +++ b/src/ImageSharp/Formats/Png/PngFrameMetadata.cs @@ -8,7 +8,7 @@ namespace SixLabors.ImageSharp.Formats.Png; /// /// Provides APng specific metadata information for the image frame. /// -public class PngFrameMetadata : IDeepCloneable +public class PngFrameMetadata : IFormatFrameMetadata { /// /// Initializes a new instance of the class. @@ -24,8 +24,8 @@ public PngFrameMetadata() private PngFrameMetadata(PngFrameMetadata other) { this.FrameDelay = other.FrameDelay; - this.DisposalMethod = other.DisposalMethod; - this.BlendMethod = other.BlendMethod; + this.DisposalMode = other.DisposalMode; + this.BlendMode = other.BlendMode; } /// @@ -39,12 +39,12 @@ private PngFrameMetadata(PngFrameMetadata other) /// /// Gets or sets the type of frame area disposal to be done after rendering this frame /// - public PngDisposalMethod DisposalMethod { get; set; } + public FrameDisposalMode DisposalMode { get; set; } /// /// Gets or sets the type of frame area rendering for this frame /// - public PngBlendMethod BlendMethod { get; set; } + public FrameBlendMode BlendMode { get; set; } /// /// Initializes a new instance of the class. @@ -53,26 +53,48 @@ private PngFrameMetadata(PngFrameMetadata other) internal void FromChunk(in FrameControl frameControl) { this.FrameDelay = new Rational(frameControl.DelayNumerator, frameControl.DelayDenominator); - this.DisposalMethod = frameControl.DisposeOperation; - this.BlendMethod = frameControl.BlendOperation; + this.DisposalMode = frameControl.DisposalMode; + this.BlendMode = frameControl.BlendMode; } /// - public IDeepCloneable DeepClone() => new PngFrameMetadata(this); - - internal static PngFrameMetadata FromAnimatedMetadata(AnimatedImageFrameMetadata metadata) + public static PngFrameMetadata FromFormatConnectingFrameMetadata(FormatConnectingFrameMetadata metadata) => new() { FrameDelay = new(metadata.Duration.TotalMilliseconds / 1000), - DisposalMethod = GetMode(metadata.DisposalMode), - BlendMethod = metadata.BlendMode == FrameBlendMode.Source ? PngBlendMethod.Source : PngBlendMethod.Over, + DisposalMode = GetMode(metadata.DisposalMode), + BlendMode = metadata.BlendMode, }; - private static PngDisposalMethod GetMode(FrameDisposalMode mode) => mode switch + /// + public FormatConnectingFrameMetadata ToFormatConnectingFrameMetadata() + { + double delay = this.FrameDelay.ToDouble(); + if (double.IsNaN(delay)) + { + delay = 0; + } + + return new() + { + ColorTableMode = FrameColorTableMode.Global, + Duration = TimeSpan.FromMilliseconds(delay * 1000), + DisposalMode = this.DisposalMode, + BlendMode = this.BlendMode, + }; + } + + /// + IDeepCloneable IDeepCloneable.DeepClone() => this.DeepClone(); + + /// + public PngFrameMetadata DeepClone() => new(this); + + private static FrameDisposalMode GetMode(FrameDisposalMode mode) => mode switch { - FrameDisposalMode.RestoreToBackground => PngDisposalMethod.RestoreToBackground, - FrameDisposalMode.RestoreToPrevious => PngDisposalMethod.RestoreToPrevious, - FrameDisposalMode.DoNotDispose => PngDisposalMethod.DoNotDispose, - _ => PngDisposalMethod.DoNotDispose, + FrameDisposalMode.RestoreToBackground => FrameDisposalMode.RestoreToBackground, + FrameDisposalMode.RestoreToPrevious => FrameDisposalMode.RestoreToPrevious, + FrameDisposalMode.DoNotDispose => FrameDisposalMode.DoNotDispose, + _ => FrameDisposalMode.DoNotDispose, }; } diff --git a/src/ImageSharp/Formats/Png/PngMetadata.cs b/src/ImageSharp/Formats/Png/PngMetadata.cs index d9028dd807..a7b3672ef5 100644 --- a/src/ImageSharp/Formats/Png/PngMetadata.cs +++ b/src/ImageSharp/Formats/Png/PngMetadata.cs @@ -2,13 +2,14 @@ // Licensed under the Six Labors Split License. using SixLabors.ImageSharp.Formats.Png.Chunks; +using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Formats.Png; /// /// Provides Png specific metadata information for the image. /// -public class PngMetadata : IDeepCloneable +public class PngMetadata : IFormatMetadata { /// /// Initializes a new instance of the class. @@ -46,17 +47,17 @@ private PngMetadata(PngMetadata other) /// Gets or sets the number of bits per sample or per palette index (not per pixel). /// Not all values are allowed for all values. /// - public PngBitDepth? BitDepth { get; set; } + public PngBitDepth BitDepth { get; set; } = PngBitDepth.Bit8; /// /// Gets or sets the color type. /// - public PngColorType? ColorType { get; set; } + public PngColorType ColorType { get; set; } = PngColorType.RgbWithAlpha; /// /// Gets or sets a value indicating whether this instance should write an Adam7 interlaced image. /// - public PngInterlaceMode? InterlaceMethod { get; set; } = PngInterlaceMode.None; + public PngInterlaceMode InterlaceMethod { get; set; } = PngInterlaceMode.None; /// /// Gets or sets the gamma value for the image. @@ -77,7 +78,7 @@ private PngMetadata(PngMetadata other) /// Gets or sets the collection of text data stored within the iTXt, tEXt, and zTXt chunks. /// Used for conveying textual information associated with the image. /// - public IList TextData { get; set; } = new List(); + public IList TextData { get; set; } = []; /// /// Gets or sets the number of times to loop this APNG. 0 indicates infinite looping. @@ -90,35 +91,165 @@ private PngMetadata(PngMetadata other) public bool AnimateRootFrame { get; set; } = true; /// - public IDeepCloneable DeepClone() => new PngMetadata(this); - - internal static PngMetadata FromAnimatedMetadata(AnimatedImageMetadata metadata) + public static PngMetadata FromFormatConnectingMetadata(FormatConnectingMetadata metadata) { // Should the conversion be from a format that uses a 24bit palette entries (gif) // we need to clone and adjust the color table to allow for transparency. - Color[]? colorTable = metadata.ColorTable.HasValue ? metadata.ColorTable.Value.ToArray() : null; + Color[]? colorTable = metadata.ColorTable?.ToArray(); if (colorTable != null) { for (int i = 0; i < colorTable.Length; i++) { ref Color c = ref colorTable[i]; - if (c == metadata.BackgroundColor) + if (c != metadata.BackgroundColor) { - // Png treats background as fully empty - c = Color.Transparent; - break; + continue; } + + // Png treats background as fully empty + c = Color.Transparent; + break; } } + PngColorType color; + PixelColorType colorType = metadata.PixelTypeInfo.ColorType; + + switch (colorType) + { + case PixelColorType.Binary: + case PixelColorType.Indexed: + color = PngColorType.Palette; + break; + case PixelColorType.Luminance: + color = PngColorType.Grayscale; + break; + case PixelColorType.RGB: + case PixelColorType.BGR: + color = PngColorType.Rgb; + break; + default: + if (colorType.HasFlag(PixelColorType.Luminance)) + { + color = PngColorType.GrayscaleWithAlpha; + break; + } + + color = PngColorType.RgbWithAlpha; + break; + } + + // PNG uses bits per component not per pixel. + int bpc = metadata.PixelTypeInfo.ComponentInfo?.GetMaximumComponentPrecision() ?? 8; + PngBitDepth bitDepth = bpc switch + { + 1 => PngBitDepth.Bit1, + 2 => PngBitDepth.Bit2, + 4 => PngBitDepth.Bit4, + _ => (bpc <= 8) ? PngBitDepth.Bit8 : PngBitDepth.Bit16, + }; return new() { - ColorType = colorTable != null ? PngColorType.Palette : null, - BitDepth = colorTable != null - ? (PngBitDepth)Numerics.Clamp(ColorNumerics.GetBitsNeededForColorDepth(colorTable.Length), 1, 8) - : null, + ColorType = color, + BitDepth = bitDepth, ColorTable = colorTable, RepeatCount = metadata.RepeatCount, }; } + + /// + public PixelTypeInfo GetPixelTypeInfo() + { + int bpp; + PixelColorType colorType; + PixelAlphaRepresentation alpha = PixelAlphaRepresentation.None; + PixelComponentInfo info; + switch (this.ColorType) + { + case PngColorType.Palette: + bpp = this.ColorTable.HasValue + ? Numerics.Clamp(ColorNumerics.GetBitsNeededForColorDepth(this.ColorTable.Value.Length), 1, 8) + : 8; + + colorType = PixelColorType.Indexed; + info = PixelComponentInfo.Create(1, bpp, bpp); + break; + + case PngColorType.Grayscale: + bpp = (int)this.BitDepth; + colorType = PixelColorType.Luminance; + info = PixelComponentInfo.Create(1, bpp, bpp); + break; + + case PngColorType.GrayscaleWithAlpha: + + alpha = PixelAlphaRepresentation.Unassociated; + if (this.BitDepth == PngBitDepth.Bit16) + { + bpp = 32; + colorType = PixelColorType.Luminance | PixelColorType.Alpha; + info = PixelComponentInfo.Create(2, bpp, 16, 16); + break; + } + + bpp = 16; + colorType = PixelColorType.Luminance | PixelColorType.Alpha; + info = PixelComponentInfo.Create(2, bpp, 8, 8); + break; + + case PngColorType.Rgb: + if (this.BitDepth == PngBitDepth.Bit16) + { + bpp = 48; + colorType = PixelColorType.RGB; + info = PixelComponentInfo.Create(3, bpp, 16, 16, 16); + break; + } + + bpp = 24; + colorType = PixelColorType.RGB; + info = PixelComponentInfo.Create(3, bpp, 8, 8, 8); + break; + + case PngColorType.RgbWithAlpha: + default: + + alpha = PixelAlphaRepresentation.Unassociated; + if (this.BitDepth == PngBitDepth.Bit16) + { + bpp = 64; + colorType = PixelColorType.RGB | PixelColorType.Alpha; + info = PixelComponentInfo.Create(4, bpp, 16, 16, 16, 16); + break; + } + + bpp = 32; + colorType = PixelColorType.RGB | PixelColorType.Alpha; + info = PixelComponentInfo.Create(4, bpp, 8, 8, 8, 8); + break; + } + + return new PixelTypeInfo(bpp) + { + AlphaRepresentation = alpha, + ColorType = colorType, + ComponentInfo = info, + }; + } + + /// + public FormatConnectingMetadata ToFormatConnectingMetadata() + => new() + { + ColorTable = this.ColorTable, + ColorTableMode = FrameColorTableMode.Global, + PixelTypeInfo = this.GetPixelTypeInfo(), + RepeatCount = (ushort)Numerics.Clamp(this.RepeatCount, 0, ushort.MaxValue), + }; + + /// + IDeepCloneable IDeepCloneable.DeepClone() => this.DeepClone(); + + /// + public PngMetadata DeepClone() => new(this); } diff --git a/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs b/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs index c653e71c62..820fc0b5cb 100644 --- a/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs +++ b/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs @@ -42,7 +42,6 @@ public static void ProcessInterlacedGrayscaleScanline( where TPixel : unmanaged, IPixel { uint offset = pixelOffset + frameControl.XOffset; - TPixel pixel = default; ref byte scanlineSpanRef = ref MemoryMarshal.GetReference(scanlineSpan); ref TPixel rowSpanRef = ref MemoryMarshal.GetReference(rowSpan); int scaleFactor = 255 / (ColorNumerics.GetColorCountForBitDepth(bitDepth) - 1); @@ -55,8 +54,7 @@ public static void ProcessInterlacedGrayscaleScanline( for (nuint x = offset; x < frameControl.XMax; x += increment, o += 2) { ushort luminance = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, 2)); - pixel.FromL16(Unsafe.As(ref luminance)); - Unsafe.Add(ref rowSpanRef, x) = pixel; + Unsafe.Add(ref rowSpanRef, x) = TPixel.FromL16(Unsafe.As(ref luminance)); } } else @@ -64,8 +62,7 @@ public static void ProcessInterlacedGrayscaleScanline( for (nuint x = offset, o = 0; x < frameControl.XMax; x += increment, o++) { byte luminance = (byte)(Unsafe.Add(ref scanlineSpanRef, o) * scaleFactor); - pixel.FromL8(Unsafe.As(ref luminance)); - Unsafe.Add(ref rowSpanRef, x) = pixel; + Unsafe.Add(ref rowSpanRef, x) = TPixel.FromL8(Unsafe.As(ref luminance)); } } @@ -75,30 +72,22 @@ public static void ProcessInterlacedGrayscaleScanline( if (bitDepth == 16) { L16 transparent = transparentColor.Value.ToPixel(); - La32 source = default; int o = 0; for (nuint x = offset; x < frameControl.XMax; x += increment, o += 2) { ushort luminance = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, 2)); - source.L = luminance; - source.A = luminance.Equals(transparent.PackedValue) ? ushort.MinValue : ushort.MaxValue; - - pixel.FromLa32(source); - Unsafe.Add(ref rowSpanRef, x) = pixel; + La32 source = new(luminance, luminance.Equals(transparent.PackedValue) ? ushort.MinValue : ushort.MaxValue); + Unsafe.Add(ref rowSpanRef, x) = TPixel.FromLa32(source); } } else { byte transparent = (byte)(transparentColor.Value.ToPixel().PackedValue * scaleFactor); - La16 source = default; for (nuint x = offset, o = 0; x < frameControl.XMax; x += increment, o++) { byte luminance = (byte)(Unsafe.Add(ref scanlineSpanRef, o) * scaleFactor); - source.L = luminance; - source.A = luminance.Equals(transparent) ? byte.MinValue : byte.MaxValue; - - pixel.FromLa16(source); - Unsafe.Add(ref rowSpanRef, x) = pixel; + La16 source = new(luminance, luminance.Equals(transparent) ? byte.MinValue : byte.MaxValue); + Unsafe.Add(ref rowSpanRef, x) = TPixel.FromLa16(source); } } } @@ -133,34 +122,28 @@ public static void ProcessInterlacedGrayscaleWithAlphaScanline( where TPixel : unmanaged, IPixel { uint offset = pixelOffset + frameControl.XOffset; - TPixel pixel = default; ref byte scanlineSpanRef = ref MemoryMarshal.GetReference(scanlineSpan); ref TPixel rowSpanRef = ref MemoryMarshal.GetReference(rowSpan); if (bitDepth == 16) { - La32 source = default; int o = 0; for (nuint x = offset; x < frameControl.XMax; x += increment, o += 4) { - source.L = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, 2)); - source.A = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + 2, 2)); + ushort l = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, 2)); + ushort a = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + 2, 2)); - pixel.FromLa32(source); - Unsafe.Add(ref rowSpanRef, (uint)x) = pixel; + Unsafe.Add(ref rowSpanRef, (uint)x) = TPixel.FromLa32(new(l, a)); } } else { - La16 source = default; nuint offset2 = 0; for (nuint x = offset; x < frameControl.XMax; x += increment) { - source.L = Unsafe.Add(ref scanlineSpanRef, offset2); - source.A = Unsafe.Add(ref scanlineSpanRef, offset2 + bytesPerSample); - - pixel.FromLa16(source); - Unsafe.Add(ref rowSpanRef, x) = pixel; + byte l = Unsafe.Add(ref scanlineSpanRef, offset2); + byte a = Unsafe.Add(ref scanlineSpanRef, offset2 + bytesPerSample); + Unsafe.Add(ref rowSpanRef, x) = TPixel.FromLa16(new(l, a)); offset2 += bytesPerPixel; } } @@ -194,7 +177,6 @@ public static void ProcessInterlacedPaletteScanline( PngThrowHelper.ThrowMissingPalette(); } - TPixel pixel = default; ref byte scanlineSpanRef = ref MemoryMarshal.GetReference(scanlineSpan); ref TPixel rowSpanRef = ref MemoryMarshal.GetReference(rowSpan); ref Color paletteBase = ref MemoryMarshal.GetReference(palette.Value.Span); @@ -204,8 +186,7 @@ public static void ProcessInterlacedPaletteScanline( for (nuint x = offset, o = 0; x < frameControl.XMax; x += increment, o++) { uint index = Unsafe.Add(ref scanlineSpanRef, o); - pixel.FromRgba32(Unsafe.Add(ref paletteBase, (int)Math.Min(index, maxIndex)).ToRgba32()); - Unsafe.Add(ref rowSpanRef, x) = pixel; + Unsafe.Add(ref rowSpanRef, x) = TPixel.FromRgba32(Unsafe.Add(ref paletteBase, (int)Math.Min(index, maxIndex)).ToPixel()); } } @@ -245,8 +226,6 @@ public static void ProcessInterlacedRgbScanline( where TPixel : unmanaged, IPixel { uint offset = pixelOffset + frameControl.XOffset; - - TPixel pixel = default; ref byte scanlineSpanRef = ref MemoryMarshal.GetReference(scanlineSpan); ref TPixel rowSpanRef = ref MemoryMarshal.GetReference(rowSpan); @@ -254,16 +233,13 @@ public static void ProcessInterlacedRgbScanline( { if (bitDepth == 16) { - Rgb48 rgb48 = default; int o = 0; for (nuint x = offset; x < frameControl.XMax; x += increment, o += bytesPerPixel) { - rgb48.R = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, bytesPerSample)); - rgb48.G = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + bytesPerSample, bytesPerSample)); - rgb48.B = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + (2 * bytesPerSample), bytesPerSample)); - - pixel.FromRgb48(rgb48); - Unsafe.Add(ref rowSpanRef, x) = pixel; + ushort r = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, bytesPerSample)); + ushort g = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + bytesPerSample, bytesPerSample)); + ushort b = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + (2 * bytesPerSample), bytesPerSample)); + Unsafe.Add(ref rowSpanRef, x) = TPixel.FromRgb48(new(r, g, b)); } } else if (pixelOffset == 0 && increment == 1) @@ -276,16 +252,13 @@ public static void ProcessInterlacedRgbScanline( } else { - Rgb24 rgb = default; int o = 0; for (nuint x = offset; x < frameControl.XMax; x += increment, o += bytesPerPixel) { - rgb.R = Unsafe.Add(ref scanlineSpanRef, (uint)o); - rgb.G = Unsafe.Add(ref scanlineSpanRef, (uint)(o + bytesPerSample)); - rgb.B = Unsafe.Add(ref scanlineSpanRef, (uint)(o + (2 * bytesPerSample))); - - pixel.FromRgb24(rgb); - Unsafe.Add(ref rowSpanRef, x) = pixel; + byte r = Unsafe.Add(ref scanlineSpanRef, (uint)o); + byte g = Unsafe.Add(ref scanlineSpanRef, (uint)(o + bytesPerSample)); + byte b = Unsafe.Add(ref scanlineSpanRef, (uint)(o + (2 * bytesPerSample))); + Unsafe.Add(ref rowSpanRef, x) = TPixel.FromRgb24(new(r, g, b)); } } @@ -295,27 +268,20 @@ public static void ProcessInterlacedRgbScanline( if (bitDepth == 16) { Rgb48 transparent = transparentColor.Value.ToPixel(); - - Rgb48 rgb48 = default; - Rgba64 rgba64 = default; + Rgba64 rgba = default; int o = 0; for (nuint x = offset; x < frameControl.XMax; x += increment, o += bytesPerPixel) { - rgb48.R = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, bytesPerSample)); - rgb48.G = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + bytesPerSample, bytesPerSample)); - rgb48.B = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + (2 * bytesPerSample), bytesPerSample)); - - rgba64.Rgb = rgb48; - rgba64.A = rgb48.Equals(transparent) ? ushort.MinValue : ushort.MaxValue; - - pixel.FromRgba64(rgba64); - Unsafe.Add(ref rowSpanRef, x) = pixel; + rgba.R = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, bytesPerSample)); + rgba.G = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + bytesPerSample, bytesPerSample)); + rgba.B = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + (2 * bytesPerSample), bytesPerSample)); + rgba.A = rgba.Rgb.Equals(transparent) ? ushort.MinValue : ushort.MaxValue; + Unsafe.Add(ref rowSpanRef, x) = TPixel.FromRgba64(rgba); } } else { Rgb24 transparent = transparentColor.Value.ToPixel(); - Rgba32 rgba = default; int o = 0; for (nuint x = offset; x < frameControl.XMax; x += increment, o += bytesPerPixel) @@ -324,9 +290,7 @@ public static void ProcessInterlacedRgbScanline( rgba.G = Unsafe.Add(ref scanlineSpanRef, (uint)(o + bytesPerSample)); rgba.B = Unsafe.Add(ref scanlineSpanRef, (uint)(o + (2 * bytesPerSample))); rgba.A = transparent.Equals(rgba.Rgb) ? byte.MinValue : byte.MaxValue; - - pixel.FromRgba32(rgba); - Unsafe.Add(ref rowSpanRef, x) = pixel; + Unsafe.Add(ref rowSpanRef, x) = TPixel.FromRgba32(rgba); } } } @@ -364,22 +328,18 @@ public static void ProcessInterlacedRgbaScanline( where TPixel : unmanaged, IPixel { uint offset = pixelOffset + frameControl.XOffset; - TPixel pixel = default; ref TPixel rowSpanRef = ref MemoryMarshal.GetReference(rowSpan); if (bitDepth == 16) { - Rgba64 rgba64 = default; int o = 0; for (nuint x = offset; x < frameControl.XMax; x += increment, o += bytesPerPixel) { - rgba64.R = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, bytesPerSample)); - rgba64.G = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + bytesPerSample, bytesPerSample)); - rgba64.B = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + (2 * bytesPerSample), bytesPerSample)); - rgba64.A = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + (3 * bytesPerSample), bytesPerSample)); - - pixel.FromRgba64(rgba64); - Unsafe.Add(ref rowSpanRef, x) = pixel; + ushort r = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, bytesPerSample)); + ushort g = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + bytesPerSample, bytesPerSample)); + ushort b = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + (2 * bytesPerSample), bytesPerSample)); + ushort a = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + (3 * bytesPerSample), bytesPerSample)); + Unsafe.Add(ref rowSpanRef, x) = TPixel.FromRgba64(new(r, g, b, a)); } } else if (pixelOffset == 0 && increment == 1) @@ -393,17 +353,14 @@ public static void ProcessInterlacedRgbaScanline( else { ref byte scanlineSpanRef = ref MemoryMarshal.GetReference(scanlineSpan); - Rgba32 rgba = default; int o = 0; for (nuint x = offset; x < frameControl.XMax; x += increment, o += bytesPerPixel) { - rgba.R = Unsafe.Add(ref scanlineSpanRef, (uint)o); - rgba.G = Unsafe.Add(ref scanlineSpanRef, (uint)(o + bytesPerSample)); - rgba.B = Unsafe.Add(ref scanlineSpanRef, (uint)(o + (2 * bytesPerSample))); - rgba.A = Unsafe.Add(ref scanlineSpanRef, (uint)(o + (3 * bytesPerSample))); - - pixel.FromRgba32(rgba); - Unsafe.Add(ref rowSpanRef, x) = pixel; + byte r = Unsafe.Add(ref scanlineSpanRef, (uint)o); + byte g = Unsafe.Add(ref scanlineSpanRef, (uint)(o + bytesPerSample)); + byte b = Unsafe.Add(ref scanlineSpanRef, (uint)(o + (2 * bytesPerSample))); + byte a = Unsafe.Add(ref scanlineSpanRef, (uint)(o + (3 * bytesPerSample))); + Unsafe.Add(ref rowSpanRef, x) = TPixel.FromRgba32(new(r, g, b, a)); } } } diff --git a/src/ImageSharp/Formats/Qoi/MetadataExtensions.cs b/src/ImageSharp/Formats/Qoi/MetadataExtensions.cs deleted file mode 100644 index 1e0fa88997..0000000000 --- a/src/ImageSharp/Formats/Qoi/MetadataExtensions.cs +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.Formats.Qoi; -using SixLabors.ImageSharp.Metadata; - -namespace SixLabors.ImageSharp; - -/// -/// Extension methods for the type. -/// -public static partial class MetadataExtensions -{ - /// - /// Gets the qoi format specific metadata for the image. - /// - /// The metadata this method extends. - /// The . - public static QoiMetadata GetQoiMetadata(this ImageMetadata metadata) => metadata.GetFormatMetadata(QoiFormat.Instance); -} diff --git a/src/ImageSharp/Formats/Qoi/QoiDecoder.cs b/src/ImageSharp/Formats/Qoi/QoiDecoder.cs index a54095dfc6..5c1bf6ad23 100644 --- a/src/ImageSharp/Formats/Qoi/QoiDecoder.cs +++ b/src/ImageSharp/Formats/Qoi/QoiDecoder.cs @@ -4,6 +4,7 @@ using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Formats.Qoi; + internal class QoiDecoder : ImageDecoder { private QoiDecoder() diff --git a/src/ImageSharp/Formats/Qoi/QoiDecoderCore.cs b/src/ImageSharp/Formats/Qoi/QoiDecoderCore.cs index 8552e164d8..85fac7ea26 100644 --- a/src/ImageSharp/Formats/Qoi/QoiDecoderCore.cs +++ b/src/ImageSharp/Formats/Qoi/QoiDecoderCore.cs @@ -44,13 +44,7 @@ protected override Image Decode(BufferedReadStream stream, Cance this.ProcessHeader(stream); // Create Image object - ImageMetadata metadata = new() - { - DecodedImageFormat = QoiFormat.Instance, - HorizontalResolution = this.header.Width, - VerticalResolution = this.header.Height, - ResolutionUnits = PixelResolutionUnit.AspectRatio - }; + ImageMetadata metadata = new(); QoiMetadata qoiMetadata = metadata.GetQoiMetadata(); qoiMetadata.Channels = this.header.Channels; qoiMetadata.ColorSpace = this.header.ColorSpace; @@ -74,7 +68,7 @@ protected override ImageInfo Identify(BufferedReadStream stream, CancellationTok qoiMetadata.Channels = this.header.Channels; qoiMetadata.ColorSpace = this.header.ColorSpace; - return new ImageInfo(pixelType, size, metadata); + return new ImageInfo(size, metadata); } /// @@ -144,7 +138,7 @@ private void ProcessPixels(BufferedReadStream stream, Buffer2D p Span previouslySeenPixels = previouslySeenPixelsBuffer.GetSpan(); Rgba32 previousPixel = new(0, 0, 0, 255); - // We save the pixel to avoid loosing the fully opaque black pixel + // We save the pixel to avoid losing the fully opaque black pixel // See https://github.com/phoboslab/qoi/issues/258 int pixelArrayPosition = GetArrayPosition(previousPixel); previouslySeenPixels[pixelArrayPosition] = previousPixel; @@ -169,7 +163,7 @@ private void ProcessPixels(BufferedReadStream stream, Buffer2D p } readPixel.A = previousPixel.A; - pixel.FromRgba32(readPixel); + pixel = TPixel.FromRgba32(readPixel); pixelArrayPosition = GetArrayPosition(readPixel); previouslySeenPixels[pixelArrayPosition] = readPixel; break; @@ -181,7 +175,7 @@ private void ProcessPixels(BufferedReadStream stream, Buffer2D p ThrowInvalidImageContentException(); } - pixel.FromRgba32(readPixel); + pixel = TPixel.FromRgba32(readPixel); pixelArrayPosition = GetArrayPosition(readPixel); previouslySeenPixels[pixelArrayPosition] = readPixel; break; @@ -192,7 +186,7 @@ private void ProcessPixels(BufferedReadStream stream, Buffer2D p // Getting one pixel from previously seen pixels case QoiChunk.QoiOpIndex: readPixel = previouslySeenPixels[operationByte]; - pixel.FromRgba32(readPixel); + pixel = TPixel.FromRgba32(readPixel); break; // Get one pixel from the difference (-2..1) of the previous pixel @@ -206,7 +200,7 @@ private void ProcessPixels(BufferedReadStream stream, Buffer2D p G = (byte)Numerics.Modulo256(previousPixel.G + (greenDifference - 2)), B = (byte)Numerics.Modulo256(previousPixel.B + (blueDifference - 2)) }; - pixel.FromRgba32(readPixel); + pixel = TPixel.FromRgba32(readPixel); pixelArrayPosition = GetArrayPosition(readPixel); previouslySeenPixels[pixelArrayPosition] = readPixel; break; @@ -222,7 +216,7 @@ private void ProcessPixels(BufferedReadStream stream, Buffer2D p int currentRed = Numerics.Modulo256(diffRedDG - 8 + (diffGreen - 32) + previousPixel.R); int currentBlue = Numerics.Modulo256(diffBlueDG - 8 + (diffGreen - 32) + previousPixel.B); readPixel = previousPixel with { R = (byte)currentRed, B = (byte)currentBlue, G = (byte)currentGreen }; - pixel.FromRgba32(readPixel); + pixel = TPixel.FromRgba32(readPixel); pixelArrayPosition = GetArrayPosition(readPixel); previouslySeenPixels[pixelArrayPosition] = readPixel; break; @@ -236,7 +230,7 @@ private void ProcessPixels(BufferedReadStream stream, Buffer2D p } readPixel = previousPixel; - pixel.FromRgba32(readPixel); + pixel = TPixel.FromRgba32(readPixel); for (int k = -1; k < repetitions; k++, j++) { if (j == row.Length) diff --git a/src/ImageSharp/Formats/Qoi/QoiMetadata.cs b/src/ImageSharp/Formats/Qoi/QoiMetadata.cs index 610c6c15b8..e2062014d7 100644 --- a/src/ImageSharp/Formats/Qoi/QoiMetadata.cs +++ b/src/ImageSharp/Formats/Qoi/QoiMetadata.cs @@ -1,12 +1,14 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. +using SixLabors.ImageSharp.PixelFormats; + namespace SixLabors.ImageSharp.Formats.Qoi; /// /// Provides Qoi specific metadata information for the image. /// -public class QoiMetadata : IDeepCloneable +public class QoiMetadata : IFormatMetadata { /// /// Initializes a new instance of the class. @@ -36,5 +38,59 @@ private QoiMetadata(QoiMetadata other) public QoiColorSpace ColorSpace { get; set; } /// - public IDeepCloneable DeepClone() => new QoiMetadata(this); + public static QoiMetadata FromFormatConnectingMetadata(FormatConnectingMetadata metadata) + { + PixelColorType color = metadata.PixelTypeInfo.ColorType; + + if (color.HasFlag(PixelColorType.Alpha)) + { + return new QoiMetadata { Channels = QoiChannels.Rgba }; + } + + return new QoiMetadata { Channels = QoiChannels.Rgb }; + } + + /// + public PixelTypeInfo GetPixelTypeInfo() + { + int bpp; + PixelColorType colorType; + PixelAlphaRepresentation alpha = PixelAlphaRepresentation.None; + PixelComponentInfo info; + + switch (this.Channels) + { + case QoiChannels.Rgb: + bpp = 24; + colorType = PixelColorType.RGB; + info = PixelComponentInfo.Create(3, bpp, 8, 8, 8); + break; + default: + bpp = 32; + colorType = PixelColorType.RGB | PixelColorType.Alpha; + info = PixelComponentInfo.Create(4, bpp, 8, 8, 8, 8); + alpha = PixelAlphaRepresentation.Unassociated; + break; + } + + return new PixelTypeInfo(bpp) + { + AlphaRepresentation = alpha, + ColorType = colorType, + ComponentInfo = info, + }; + } + + /// + public FormatConnectingMetadata ToFormatConnectingMetadata() + => new() + { + PixelTypeInfo = this.GetPixelTypeInfo() + }; + + /// + IDeepCloneable IDeepCloneable.DeepClone() => this.DeepClone(); + + /// + public QoiMetadata DeepClone() => new(this); } diff --git a/src/ImageSharp/Formats/SegmentIntegrityHandling.cs b/src/ImageSharp/Formats/SegmentIntegrityHandling.cs new file mode 100644 index 0000000000..977aee4ad5 --- /dev/null +++ b/src/ImageSharp/Formats/SegmentIntegrityHandling.cs @@ -0,0 +1,30 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +namespace SixLabors.ImageSharp.Formats; + +/// +/// Specifies how to handle validation of errors in different segments of encoded image files. +/// +public enum SegmentIntegrityHandling +{ + /// + /// Do not ignore any errors. + /// + IgnoreNone, + + /// + /// Ignore errors in non-critical segments of the encoded image. + /// + IgnoreNonCritical, + + /// + /// Ignore errors in data segments (e.g., image data, metadata). + /// + IgnoreData, + + /// + /// Ignore errors in all segments. + /// + IgnoreAll +} diff --git a/src/ImageSharp/Formats/Tga/MetadataExtensions.cs b/src/ImageSharp/Formats/Tga/MetadataExtensions.cs deleted file mode 100644 index 8d5e357641..0000000000 --- a/src/ImageSharp/Formats/Tga/MetadataExtensions.cs +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.Formats.Tga; -using SixLabors.ImageSharp.Metadata; - -namespace SixLabors.ImageSharp; - -/// -/// Extension methods for the type. -/// -public static partial class MetadataExtensions -{ - /// - /// Gets the tga format specific metadata for the image. - /// - /// The metadata this method extends. - /// The . - public static TgaMetadata GetTgaMetadata(this ImageMetadata metadata) => metadata.GetFormatMetadata(TgaFormat.Instance); -} diff --git a/src/ImageSharp/Formats/Tga/TgaBitsPerPixel.cs b/src/ImageSharp/Formats/Tga/TgaBitsPerPixel.cs index da34e62f7e..af537ddc21 100644 --- a/src/ImageSharp/Formats/Tga/TgaBitsPerPixel.cs +++ b/src/ImageSharp/Formats/Tga/TgaBitsPerPixel.cs @@ -11,20 +11,20 @@ public enum TgaBitsPerPixel : byte /// /// 8 bits per pixel. Each pixel consists of 1 byte. /// - Pixel8 = 8, + Bit8 = 8, /// /// 16 bits per pixel. Each pixel consists of 2 bytes. /// - Pixel16 = 16, + Bit16 = 16, /// /// 24 bits per pixel. Each pixel consists of 3 bytes. /// - Pixel24 = 24, + Bit24 = 24, /// /// 32 bits per pixel. Each pixel consists of 4 bytes. /// - Pixel32 = 32 + Bit32 = 32 } diff --git a/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs b/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs index e2dd919d29..dc6b33422f 100644 --- a/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs +++ b/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs @@ -215,7 +215,6 @@ protected override Image Decode(BufferedReadStream stream, Cance private void ReadPaletted(BufferedReadStream stream, int width, int height, Buffer2D pixels, Span palette, int colorMapPixelSizeInBytes, TgaImageOrigin origin) where TPixel : unmanaged, IPixel { - TPixel color = default; bool invertX = InvertX(origin); for (int y = 0; y < height; y++) @@ -230,14 +229,14 @@ private void ReadPaletted(BufferedReadStream stream, int width, int heig { for (int x = width - 1; x >= 0; x--) { - this.ReadPalettedBgra16Pixel(stream, palette, colorMapPixelSizeInBytes, x, color, pixelRow); + this.ReadPalettedBgra16Pixel(stream, palette, colorMapPixelSizeInBytes, x, pixelRow); } } else { for (int x = 0; x < width; x++) { - this.ReadPalettedBgra16Pixel(stream, palette, colorMapPixelSizeInBytes, x, color, pixelRow); + this.ReadPalettedBgra16Pixel(stream, palette, colorMapPixelSizeInBytes, x, pixelRow); } } @@ -248,14 +247,14 @@ private void ReadPaletted(BufferedReadStream stream, int width, int heig { for (int x = width - 1; x >= 0; x--) { - ReadPalettedBgr24Pixel(stream, palette, colorMapPixelSizeInBytes, x, color, pixelRow); + ReadPalettedBgr24Pixel(stream, palette, colorMapPixelSizeInBytes, x, pixelRow); } } else { for (int x = 0; x < width; x++) { - ReadPalettedBgr24Pixel(stream, palette, colorMapPixelSizeInBytes, x, color, pixelRow); + ReadPalettedBgr24Pixel(stream, palette, colorMapPixelSizeInBytes, x, pixelRow); } } @@ -266,14 +265,14 @@ private void ReadPaletted(BufferedReadStream stream, int width, int heig { for (int x = width - 1; x >= 0; x--) { - ReadPalettedBgra32Pixel(stream, palette, colorMapPixelSizeInBytes, x, color, pixelRow); + ReadPalettedBgra32Pixel(stream, palette, colorMapPixelSizeInBytes, x, pixelRow); } } else { for (int x = 0; x < width; x++) { - ReadPalettedBgra32Pixel(stream, palette, colorMapPixelSizeInBytes, x, color, pixelRow); + ReadPalettedBgra32Pixel(stream, palette, colorMapPixelSizeInBytes, x, pixelRow); } } @@ -312,16 +311,16 @@ private void ReadPalettedRle(BufferedReadStream stream, int width, int h switch (colorMapPixelSizeInBytes) { case 1: - color.FromL8(Unsafe.As(ref palette[bufferSpan[idx] * colorMapPixelSizeInBytes])); + color = TPixel.FromL8(Unsafe.As(ref palette[bufferSpan[idx] * colorMapPixelSizeInBytes])); break; case 2: - this.ReadPalettedBgra16Pixel(palette, bufferSpan[idx], colorMapPixelSizeInBytes, ref color); + color = this.ReadPalettedBgra16Pixel(palette, bufferSpan[idx], colorMapPixelSizeInBytes); break; case 3: - color.FromBgr24(Unsafe.As(ref palette[bufferSpan[idx] * colorMapPixelSizeInBytes])); + color = TPixel.FromBgr24(Unsafe.As(ref palette[bufferSpan[idx] * colorMapPixelSizeInBytes])); break; case 4: - color.FromBgra32(Unsafe.As(ref palette[bufferSpan[idx] * colorMapPixelSizeInBytes])); + color = TPixel.FromBgra32(Unsafe.As(ref palette[bufferSpan[idx] * colorMapPixelSizeInBytes])); break; } @@ -343,17 +342,15 @@ private void ReadPalettedRle(BufferedReadStream stream, int width, int h private void ReadMonoChrome(BufferedReadStream stream, int width, int height, Buffer2D pixels, TgaImageOrigin origin) where TPixel : unmanaged, IPixel { - bool invertX = InvertX(origin); - if (invertX) + if (InvertX(origin)) { - TPixel color = default; for (int y = 0; y < height; y++) { int newY = InvertY(y, height, origin); Span pixelSpan = pixels.DangerousGetRowSpan(newY); for (int x = width - 1; x >= 0; x--) { - ReadL8Pixel(stream, color, x, pixelSpan); + ReadL8Pixel(stream, x, pixelSpan); } } @@ -362,8 +359,7 @@ private void ReadMonoChrome(BufferedReadStream stream, int width, int he using IMemoryOwner row = this.memoryAllocator.AllocatePaddedPixelRowBuffer(width, 1, 0); Span rowSpan = row.GetSpan(); - bool invertY = InvertY(origin); - if (invertY) + if (InvertY(origin)) { for (int y = height - 1; y >= 0; y--) { @@ -391,7 +387,6 @@ private void ReadMonoChrome(BufferedReadStream stream, int width, int he private void ReadBgra16(BufferedReadStream stream, int width, int height, Buffer2D pixels, TgaImageOrigin origin) where TPixel : unmanaged, IPixel { - TPixel color = default; bool invertX = InvertX(origin); using IMemoryOwner row = this.memoryAllocator.AllocatePaddedPixelRowBuffer(width, 2, 0); Span rowSpan = row.GetSpan(); @@ -419,14 +414,12 @@ private void ReadBgra16(BufferedReadStream stream, int width, int height if (this.fileHeader.ImageType == TgaImageType.BlackAndWhite) { - color.FromLa16(Unsafe.As(ref MemoryMarshal.GetReference(scratchBuffer))); + pixelSpan[x] = TPixel.FromLa16(Unsafe.As(ref MemoryMarshal.GetReference(scratchBuffer))); } else { - color.FromBgra5551(Unsafe.As(ref MemoryMarshal.GetReference(scratchBuffer))); + pixelSpan[x] = TPixel.FromBgra5551(Unsafe.As(ref MemoryMarshal.GetReference(scratchBuffer))); } - - pixelSpan[x] = color; } } else @@ -470,18 +463,16 @@ private void ReadBgra16(BufferedReadStream stream, int width, int height private void ReadBgr24(BufferedReadStream stream, int width, int height, Buffer2D pixels, TgaImageOrigin origin) where TPixel : unmanaged, IPixel { - bool invertX = InvertX(origin); - if (invertX) + if (InvertX(origin)) { Span scratchBuffer = stackalloc byte[4]; - TPixel color = default; for (int y = 0; y < height; y++) { int newY = InvertY(y, height, origin); Span pixelSpan = pixels.DangerousGetRowSpan(newY); for (int x = width - 1; x >= 0; x--) { - ReadBgr24Pixel(stream, color, x, pixelSpan, scratchBuffer); + ReadBgr24Pixel(stream, x, pixelSpan, scratchBuffer); } } @@ -490,9 +481,8 @@ private void ReadBgr24(BufferedReadStream stream, int width, int height, using IMemoryOwner row = this.memoryAllocator.AllocatePaddedPixelRowBuffer(width, 3, 0); Span rowSpan = row.GetSpan(); - bool invertY = InvertY(origin); - if (invertY) + if (InvertY(origin)) { for (int y = height - 1; y >= 0; y--) { @@ -520,7 +510,6 @@ private void ReadBgr24(BufferedReadStream stream, int width, int height, private void ReadBgra32(BufferedReadStream stream, int width, int height, Buffer2D pixels, TgaImageOrigin origin) where TPixel : unmanaged, IPixel { - TPixel color = default; bool invertX = InvertX(origin); Guard.NotNull(this.tgaMetadata); @@ -558,14 +547,14 @@ private void ReadBgra32(BufferedReadStream stream, int width, int height { for (int x = width - 1; x >= 0; x--) { - this.ReadBgra32Pixel(stream, x, color, pixelRow, scratchBuffer); + this.ReadBgra32Pixel(stream, x, pixelRow, scratchBuffer); } } else { for (int x = 0; x < width; x++) { - this.ReadBgra32Pixel(stream, x, color, pixelRow, scratchBuffer); + this.ReadBgra32Pixel(stream, x, pixelRow, scratchBuffer); } } } @@ -603,7 +592,7 @@ private void ReadRle(BufferedReadStream stream, int width, int height, B switch (bytesPerPixel) { case 1: - color.FromL8(Unsafe.As(ref bufferSpan[idx])); + color = TPixel.FromL8(Unsafe.As(ref bufferSpan[idx])); break; case 2: if (!this.hasAlpha) @@ -614,26 +603,26 @@ private void ReadRle(BufferedReadStream stream, int width, int height, B if (this.fileHeader.ImageType == TgaImageType.RleBlackAndWhite) { - color.FromLa16(Unsafe.As(ref bufferSpan[idx])); + color = TPixel.FromLa16(Unsafe.As(ref bufferSpan[idx])); } else { - color.FromBgra5551(Unsafe.As(ref bufferSpan[idx])); + color = TPixel.FromBgra5551(Unsafe.As(ref bufferSpan[idx])); } break; case 3: - color.FromBgr24(Unsafe.As(ref bufferSpan[idx])); + color = TPixel.FromBgr24(Unsafe.As(ref bufferSpan[idx])); break; case 4: if (this.hasAlpha) { - color.FromBgra32(Unsafe.As(ref bufferSpan[idx])); + color = TPixel.FromBgra32(Unsafe.As(ref bufferSpan[idx])); } else { byte alpha = alphaBits == 0 ? byte.MaxValue : bufferSpan[idx + 3]; - color.FromBgra32(new Bgra32(bufferSpan[idx + 2], bufferSpan[idx + 1], bufferSpan[idx], alpha)); + color = TPixel.FromBgra32(new Bgra32(bufferSpan[idx + 2], bufferSpan[idx + 1], bufferSpan[idx], alpha)); } break; @@ -650,7 +639,6 @@ protected override ImageInfo Identify(BufferedReadStream stream, CancellationTok { this.ReadFileHeader(stream); return new ImageInfo( - new PixelTypeInfo(this.fileHeader.PixelDepth), new(this.fileHeader.Width, this.fileHeader.Height), this.metadata); } @@ -670,16 +658,15 @@ private void ReadL8Row(BufferedReadStream stream, int width, Buffer2D(BufferedReadStream stream, TPixel color, int x, Span pixelSpan) + private static void ReadL8Pixel(BufferedReadStream stream, int x, Span pixelSpan) where TPixel : unmanaged, IPixel { byte pixelValue = (byte)stream.ReadByte(); - color.FromL8(Unsafe.As(ref pixelValue)); - pixelSpan[x] = color; + pixelSpan[x] = TPixel.FromL8(Unsafe.As(ref pixelValue)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void ReadBgr24Pixel(BufferedReadStream stream, TPixel color, int x, Span pixelSpan, Span scratchBuffer) + private static void ReadBgr24Pixel(BufferedReadStream stream, int x, Span pixelSpan, Span scratchBuffer) where TPixel : unmanaged, IPixel { int bytesRead = stream.Read(scratchBuffer, 0, 3); @@ -688,8 +675,7 @@ private static void ReadBgr24Pixel(BufferedReadStream stream, TPixel col TgaThrowHelper.ThrowInvalidImageContentException("Not enough data to read a bgr pixel"); } - color.FromBgr24(Unsafe.As(ref MemoryMarshal.GetReference(scratchBuffer))); - pixelSpan[x] = color; + pixelSpan[x] = TPixel.FromBgr24(Unsafe.As(ref MemoryMarshal.GetReference(scratchBuffer))); } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -707,7 +693,7 @@ private void ReadBgr24Row(BufferedReadStream stream, int width, Buffer2D } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void ReadBgra32Pixel(BufferedReadStream stream, int x, TPixel color, Span pixelRow, Span scratchBuffer) + private void ReadBgra32Pixel(BufferedReadStream stream, int x, Span pixelRow, Span scratchBuffer) where TPixel : unmanaged, IPixel { int bytesRead = stream.Read(scratchBuffer, 0, 4); @@ -719,8 +705,7 @@ private void ReadBgra32Pixel(BufferedReadStream stream, int x, TPixel co Guard.NotNull(this.tgaMetadata); byte alpha = this.tgaMetadata.AlphaChannelBits == 0 ? byte.MaxValue : scratchBuffer[3]; - color.FromBgra32(new Bgra32(scratchBuffer[2], scratchBuffer[1], scratchBuffer[0], alpha)); - pixelRow[x] = color; + pixelRow[x] = TPixel.FromBgra32(new Bgra32(scratchBuffer[2], scratchBuffer[1], scratchBuffer[0], alpha)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -738,7 +723,7 @@ private void ReadBgra32Row(BufferedReadStream stream, int width, Buffer2 } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void ReadPalettedBgra16Pixel(BufferedReadStream stream, Span palette, int colorMapPixelSizeInBytes, int x, TPixel color, Span pixelRow) + private void ReadPalettedBgra16Pixel(BufferedReadStream stream, Span palette, int colorMapPixelSizeInBytes, int x, Span pixelRow) where TPixel : unmanaged, IPixel { int colorIndex = stream.ReadByte(); @@ -747,16 +732,14 @@ private void ReadPalettedBgra16Pixel(BufferedReadStream stream, Span(palette, colorIndex, colorMapPixelSizeInBytes); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void ReadPalettedBgra16Pixel(Span palette, int index, int colorMapPixelSizeInBytes, ref TPixel color) + private TPixel ReadPalettedBgra16Pixel(Span palette, int index, int colorMapPixelSizeInBytes) where TPixel : unmanaged, IPixel { - Bgra5551 bgra = default; - bgra.FromBgra5551(Unsafe.As(ref palette[index * colorMapPixelSizeInBytes])); + Bgra5551 bgra = Unsafe.As(ref palette[index * colorMapPixelSizeInBytes]); if (!this.hasAlpha) { @@ -764,11 +747,11 @@ private void ReadPalettedBgra16Pixel(Span palette, int index, int bgra.PackedValue = (ushort)(bgra.PackedValue | 0x8000); } - color.FromBgra5551(bgra); + return TPixel.FromBgra5551(bgra); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void ReadPalettedBgr24Pixel(BufferedReadStream stream, Span palette, int colorMapPixelSizeInBytes, int x, TPixel color, Span pixelRow) + private static void ReadPalettedBgr24Pixel(BufferedReadStream stream, Span palette, int colorMapPixelSizeInBytes, int x, Span pixelRow) where TPixel : unmanaged, IPixel { int colorIndex = stream.ReadByte(); @@ -777,12 +760,11 @@ private static void ReadPalettedBgr24Pixel(BufferedReadStream stream, Sp TgaThrowHelper.ThrowInvalidImageContentException("Not enough data to read color index"); } - color.FromBgr24(Unsafe.As(ref palette[colorIndex * colorMapPixelSizeInBytes])); - pixelRow[x] = color; + pixelRow[x] = TPixel.FromBgr24(Unsafe.As(ref palette[colorIndex * colorMapPixelSizeInBytes])); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void ReadPalettedBgra32Pixel(BufferedReadStream stream, Span palette, int colorMapPixelSizeInBytes, int x, TPixel color, Span pixelRow) + private static void ReadPalettedBgra32Pixel(BufferedReadStream stream, Span palette, int colorMapPixelSizeInBytes, int x, Span pixelRow) where TPixel : unmanaged, IPixel { int colorIndex = stream.ReadByte(); @@ -791,8 +773,7 @@ private static void ReadPalettedBgra32Pixel(BufferedReadStream stream, S TgaThrowHelper.ThrowInvalidImageContentException("Not enough data to read color index"); } - color.FromBgra32(Unsafe.As(ref palette[colorIndex * colorMapPixelSizeInBytes])); - pixelRow[x] = color; + pixelRow[x] = TPixel.FromBgra32(Unsafe.As(ref palette[colorIndex * colorMapPixelSizeInBytes])); } /// @@ -932,7 +913,9 @@ private TgaImageOrigin ReadFileHeader(BufferedReadStream stream) this.tgaMetadata = this.metadata.GetTgaMetadata(); this.tgaMetadata.BitsPerPixel = (TgaBitsPerPixel)this.fileHeader.PixelDepth; - int alphaBits = this.fileHeader.ImageDescriptor & 0xf; + // TrueColor images with 32 bits per pixel are assumed to always have 8 bit alpha channel, + // because some encoders do not set correctly the alpha bits in the image descriptor. + int alphaBits = this.IsTrueColor32BitPerPixel(this.tgaMetadata.BitsPerPixel) ? 8 : this.fileHeader.ImageDescriptor & 0xf; if (alphaBits is not 0 and not 1 and not 8) { TgaThrowHelper.ThrowInvalidImageContentException("Invalid alpha channel bits"); @@ -944,4 +927,8 @@ private TgaImageOrigin ReadFileHeader(BufferedReadStream stream) // Bits 4 and 5 describe the image origin. return (TgaImageOrigin)((this.fileHeader.ImageDescriptor & 0x30) >> 4); } + + private bool IsTrueColor32BitPerPixel(TgaBitsPerPixel bitsPerPixel) => bitsPerPixel == TgaBitsPerPixel.Bit32 && + (this.fileHeader.ImageType == TgaImageType.TrueColor || + this.fileHeader.ImageType == TgaImageType.RleTrueColor); } diff --git a/src/ImageSharp/Formats/Tga/TgaEncoderCore.cs b/src/ImageSharp/Formats/Tga/TgaEncoderCore.cs index c1c3d23b1f..1e05a9f716 100644 --- a/src/ImageSharp/Formats/Tga/TgaEncoderCore.cs +++ b/src/ImageSharp/Formats/Tga/TgaEncoderCore.cs @@ -3,8 +3,6 @@ using System.Buffers; using System.Buffers.Binary; -using System.Numerics; -using System.Runtime.CompilerServices; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Metadata; using SixLabors.ImageSharp.PixelFormats; @@ -61,7 +59,7 @@ public void Encode(Image image, Stream stream, CancellationToken this.bitsPerPixel ??= tgaMetadata.BitsPerPixel; TgaImageType imageType = this.compression is TgaCompression.RunLength ? TgaImageType.RleTrueColor : TgaImageType.TrueColor; - if (this.bitsPerPixel == TgaBitsPerPixel.Pixel8) + if (this.bitsPerPixel == TgaBitsPerPixel.Bit8) { imageType = this.compression is TgaCompression.RunLength ? TgaImageType.RleBlackAndWhite : TgaImageType.BlackAndWhite; } @@ -73,13 +71,13 @@ public void Encode(Image image, Stream stream, CancellationToken imageDescriptor |= 0x20; } - if (this.bitsPerPixel is TgaBitsPerPixel.Pixel32) + if (this.bitsPerPixel is TgaBitsPerPixel.Bit32) { // Indicate, that 8 bit are used for the alpha channel. imageDescriptor |= 0x8; } - if (this.bitsPerPixel is TgaBitsPerPixel.Pixel16) + if (this.bitsPerPixel is TgaBitsPerPixel.Bit16) { // Indicate, that 1 bit is used for the alpha channel. imageDescriptor |= 0x1; @@ -107,11 +105,11 @@ public void Encode(Image image, Stream stream, CancellationToken stream.Write(buffer, 0, TgaFileHeader.Size); if (this.compression is TgaCompression.RunLength) { - this.WriteRunLengthEncodedImage(stream, image.Frames.RootFrame); + this.WriteRunLengthEncodedImage(stream, image.Frames.RootFrame, cancellationToken); } else { - this.WriteImage(image.Configuration, stream, image.Frames.RootFrame); + this.WriteImage(image.Configuration, stream, image.Frames.RootFrame, cancellationToken); } stream.Flush(); @@ -123,29 +121,28 @@ public void Encode(Image image, Stream stream, CancellationToken /// The pixel format. /// The global configuration. /// The to write to. - /// - /// The containing pixel data. - /// - private void WriteImage(Configuration configuration, Stream stream, ImageFrame image) + /// /// The containing pixel data. + /// The token to request cancellation. + private void WriteImage(Configuration configuration, Stream stream, ImageFrame image, CancellationToken cancellationToken) where TPixel : unmanaged, IPixel { Buffer2D pixels = image.PixelBuffer; switch (this.bitsPerPixel) { - case TgaBitsPerPixel.Pixel8: - this.Write8Bit(configuration, stream, pixels); + case TgaBitsPerPixel.Bit8: + this.Write8Bit(configuration, stream, pixels, cancellationToken); break; - case TgaBitsPerPixel.Pixel16: - this.Write16Bit(configuration, stream, pixels); + case TgaBitsPerPixel.Bit16: + this.Write16Bit(configuration, stream, pixels, cancellationToken); break; - case TgaBitsPerPixel.Pixel24: - this.Write24Bit(configuration, stream, pixels); + case TgaBitsPerPixel.Bit24: + this.Write24Bit(configuration, stream, pixels, cancellationToken); break; - case TgaBitsPerPixel.Pixel32: - this.Write32Bit(configuration, stream, pixels); + case TgaBitsPerPixel.Bit32: + this.Write32Bit(configuration, stream, pixels, cancellationToken); break; } } @@ -156,25 +153,33 @@ private void WriteImage(Configuration configuration, Stream stream, Imag /// The pixel type. /// The stream to write the image to. /// The image to encode. - private void WriteRunLengthEncodedImage(Stream stream, ImageFrame image) + /// The token to request cancellation. + private void WriteRunLengthEncodedImage(Stream stream, ImageFrame image, CancellationToken cancellationToken) where TPixel : unmanaged, IPixel { - Rgba32 color = default; Buffer2D pixels = image.PixelBuffer; + + using IMemoryOwner rgbaOwner = this.memoryAllocator.Allocate(image.Width); + Span rgbaRow = rgbaOwner.GetSpan(); + for (int y = 0; y < image.Height; y++) { + cancellationToken.ThrowIfCancellationRequested(); + Span pixelRow = pixels.DangerousGetRowSpan(y); + PixelOperations.Instance.ToRgba32(image.Configuration, pixelRow, rgbaRow); + for (int x = 0; x < image.Width;) { TPixel currentPixel = pixelRow[x]; - currentPixel.ToRgba32(ref color); + Rgba32 rgba = rgbaRow[x]; byte equalPixelCount = FindEqualPixels(pixelRow, x); if (equalPixelCount > 0) { - // Write the number of equal pixels, with the high bit set, indicating ist a compressed pixel run. + // Write the number of equal pixels, with the high bit set, indicating it's a compressed pixel run. stream.WriteByte((byte)(equalPixelCount | 128)); - this.WritePixel(stream, currentPixel, color); + this.WritePixel(stream, rgba); x += equalPixelCount + 1; } else @@ -182,13 +187,13 @@ private void WriteRunLengthEncodedImage(Stream stream, ImageFrame(Stream stream, ImageFrame /// Writes a the pixel to the stream. /// - /// The type of the pixel. /// The stream to write to. - /// The current pixel. /// The color of the pixel to write. - private void WritePixel(Stream stream, TPixel currentPixel, Rgba32 color) - where TPixel : unmanaged, IPixel + private void WritePixel(Stream stream, Rgba32 color) { switch (this.bitsPerPixel) { - case TgaBitsPerPixel.Pixel8: - int luminance = GetLuminance(currentPixel); - stream.WriteByte((byte)luminance); + case TgaBitsPerPixel.Bit8: + L8 l8 = L8.FromRgba32(color); + stream.WriteByte(l8.PackedValue); break; - case TgaBitsPerPixel.Pixel16: - Bgra5551 bgra5551 = new(color.ToVector4()); + case TgaBitsPerPixel.Bit16: + Bgra5551 bgra5551 = Bgra5551.FromRgba32(color); Span buffer = stackalloc byte[2]; BinaryPrimitives.WriteInt16LittleEndian(buffer, (short)bgra5551.PackedValue); stream.WriteByte(buffer[0]); @@ -222,13 +224,13 @@ private void WritePixel(Stream stream, TPixel currentPixel, Rgba32 color break; - case TgaBitsPerPixel.Pixel24: + case TgaBitsPerPixel.Bit24: stream.WriteByte(color.B); stream.WriteByte(color.G); stream.WriteByte(color.R); break; - case TgaBitsPerPixel.Pixel32: + case TgaBitsPerPixel.Bit32: stream.WriteByte(color.B); stream.WriteByte(color.G); stream.WriteByte(color.R); @@ -313,7 +315,8 @@ private IMemoryOwner AllocateRow(int width, int bytesPerPixel) /// The global configuration. /// The to write to. /// The containing pixel data. - private void Write8Bit(Configuration configuration, Stream stream, Buffer2D pixels) + /// The token to request cancellation. + private void Write8Bit(Configuration configuration, Stream stream, Buffer2D pixels, CancellationToken cancellationToken) where TPixel : unmanaged, IPixel { using IMemoryOwner row = this.AllocateRow(pixels.Width, 1); @@ -321,6 +324,8 @@ private void Write8Bit(Configuration configuration, Stream stream, Buffe for (int y = pixels.Height - 1; y >= 0; y--) { + cancellationToken.ThrowIfCancellationRequested(); + Span pixelSpan = pixels.DangerousGetRowSpan(y); PixelOperations.Instance.ToL8Bytes( configuration, @@ -338,7 +343,8 @@ private void Write8Bit(Configuration configuration, Stream stream, Buffe /// The global configuration. /// The to write to. /// The containing pixel data. - private void Write16Bit(Configuration configuration, Stream stream, Buffer2D pixels) + /// The token to request cancellation. + private void Write16Bit(Configuration configuration, Stream stream, Buffer2D pixels, CancellationToken cancellationToken) where TPixel : unmanaged, IPixel { using IMemoryOwner row = this.AllocateRow(pixels.Width, 2); @@ -346,6 +352,8 @@ private void Write16Bit(Configuration configuration, Stream stream, Buff for (int y = pixels.Height - 1; y >= 0; y--) { + cancellationToken.ThrowIfCancellationRequested(); + Span pixelSpan = pixels.DangerousGetRowSpan(y); PixelOperations.Instance.ToBgra5551Bytes( configuration, @@ -363,7 +371,8 @@ private void Write16Bit(Configuration configuration, Stream stream, Buff /// The global configuration. /// The to write to. /// The containing pixel data. - private void Write24Bit(Configuration configuration, Stream stream, Buffer2D pixels) + /// The token to request cancellation. + private void Write24Bit(Configuration configuration, Stream stream, Buffer2D pixels, CancellationToken cancellationToken) where TPixel : unmanaged, IPixel { using IMemoryOwner row = this.AllocateRow(pixels.Width, 3); @@ -371,6 +380,8 @@ private void Write24Bit(Configuration configuration, Stream stream, Buff for (int y = pixels.Height - 1; y >= 0; y--) { + cancellationToken.ThrowIfCancellationRequested(); + Span pixelSpan = pixels.DangerousGetRowSpan(y); PixelOperations.Instance.ToBgr24Bytes( configuration, @@ -388,7 +399,8 @@ private void Write24Bit(Configuration configuration, Stream stream, Buff /// The global configuration. /// The to write to. /// The containing pixel data. - private void Write32Bit(Configuration configuration, Stream stream, Buffer2D pixels) + /// The token to request cancellation. + private void Write32Bit(Configuration configuration, Stream stream, Buffer2D pixels, CancellationToken cancellationToken) where TPixel : unmanaged, IPixel { using IMemoryOwner row = this.AllocateRow(pixels.Width, 4); @@ -396,6 +408,8 @@ private void Write32Bit(Configuration configuration, Stream stream, Buff for (int y = pixels.Height - 1; y >= 0; y--) { + cancellationToken.ThrowIfCancellationRequested(); + Span pixelSpan = pixels.DangerousGetRowSpan(y); PixelOperations.Instance.ToBgra32Bytes( configuration, @@ -405,17 +419,4 @@ private void Write32Bit(Configuration configuration, Stream stream, Buff stream.Write(rowSpan); } } - - /// - /// Convert the pixel values to grayscale using ITU-R Recommendation BT.709. - /// - /// The type of pixel format. - /// The pixel to get the luminance from. - [MethodImpl(InliningOptions.ShortMethod)] - public static int GetLuminance(TPixel sourcePixel) - where TPixel : unmanaged, IPixel - { - Vector4 vector = sourcePixel.ToVector4(); - return ColorNumerics.GetBT709Luminance(ref vector, 256); - } } diff --git a/src/ImageSharp/Formats/Tga/TgaFileHeader.cs b/src/ImageSharp/Formats/Tga/TgaFileHeader.cs index 007dc03de1..2613cd610a 100644 --- a/src/ImageSharp/Formats/Tga/TgaFileHeader.cs +++ b/src/ImageSharp/Formats/Tga/TgaFileHeader.cs @@ -131,10 +131,7 @@ public TgaFileHeader( /// public byte ImageDescriptor { get; } - public static TgaFileHeader Parse(Span data) - { - return MemoryMarshal.Cast(data)[0]; - } + public static TgaFileHeader Parse(Span data) => MemoryMarshal.Cast(data)[0]; public void WriteTo(Span buffer) { diff --git a/src/ImageSharp/Formats/Tga/TgaMetadata.cs b/src/ImageSharp/Formats/Tga/TgaMetadata.cs index 1fb3ab5c5d..58b5119523 100644 --- a/src/ImageSharp/Formats/Tga/TgaMetadata.cs +++ b/src/ImageSharp/Formats/Tga/TgaMetadata.cs @@ -1,12 +1,14 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. +using SixLabors.ImageSharp.PixelFormats; + namespace SixLabors.ImageSharp.Formats.Tga; /// /// Provides TGA specific metadata information for the image. /// -public class TgaMetadata : IDeepCloneable +public class TgaMetadata : IFormatMetadata { /// /// Initializes a new instance of the class. @@ -25,7 +27,7 @@ private TgaMetadata(TgaMetadata other) /// /// Gets or sets the number of bits per pixel. /// - public TgaBitsPerPixel BitsPerPixel { get; set; } = TgaBitsPerPixel.Pixel24; + public TgaBitsPerPixel BitsPerPixel { get; set; } = TgaBitsPerPixel.Bit24; /// /// Gets or sets the number of alpha bits per pixel. @@ -33,5 +35,68 @@ private TgaMetadata(TgaMetadata other) public byte AlphaChannelBits { get; set; } /// - public IDeepCloneable DeepClone() => new TgaMetadata(this); + public static TgaMetadata FromFormatConnectingMetadata(FormatConnectingMetadata metadata) + { + // TODO: AlphaChannelBits is not used during encoding. + int bpp = metadata.PixelTypeInfo.BitsPerPixel; + return bpp switch + { + <= 8 => new TgaMetadata { BitsPerPixel = TgaBitsPerPixel.Bit8 }, + <= 16 => new TgaMetadata { BitsPerPixel = TgaBitsPerPixel.Bit16 }, + <= 24 => new TgaMetadata { BitsPerPixel = TgaBitsPerPixel.Bit24 }, + _ => new TgaMetadata { BitsPerPixel = TgaBitsPerPixel.Bit32 } + }; + } + + /// + public PixelTypeInfo GetPixelTypeInfo() + { + int bpp = (int)this.BitsPerPixel; + PixelComponentInfo info; + PixelColorType color; + PixelAlphaRepresentation alpha; + switch (this.BitsPerPixel) + { + case TgaBitsPerPixel.Bit8: + info = PixelComponentInfo.Create(1, bpp, 8); + color = PixelColorType.Luminance; + alpha = PixelAlphaRepresentation.None; + break; + case TgaBitsPerPixel.Bit16: + info = PixelComponentInfo.Create(1, bpp, 5, 5, 5, 1); + color = PixelColorType.BGR | PixelColorType.Alpha; + alpha = PixelAlphaRepresentation.Unassociated; + break; + case TgaBitsPerPixel.Bit24: + info = PixelComponentInfo.Create(3, bpp, 8, 8, 8); + color = PixelColorType.RGB; + alpha = PixelAlphaRepresentation.None; + break; + case TgaBitsPerPixel.Bit32 or _: + info = PixelComponentInfo.Create(4, bpp, 8, 8, 8, 8); + color = PixelColorType.RGB | PixelColorType.Alpha; + alpha = PixelAlphaRepresentation.Unassociated; + break; + } + + return new PixelTypeInfo(bpp) + { + AlphaRepresentation = alpha, + ComponentInfo = info, + ColorType = color + }; + } + + /// + public FormatConnectingMetadata ToFormatConnectingMetadata() + => new() + { + PixelTypeInfo = this.GetPixelTypeInfo() + }; + + /// + IDeepCloneable IDeepCloneable.DeepClone() => this.DeepClone(); + + /// + public TgaMetadata DeepClone() => new(this); } diff --git a/src/ImageSharp/Formats/Tiff/Compression/Compressors/TiffJpegCompressor.cs b/src/ImageSharp/Formats/Tiff/Compression/Compressors/TiffJpegCompressor.cs index 9096271fe5..08faa539a8 100644 --- a/src/ImageSharp/Formats/Tiff/Compression/Compressors/TiffJpegCompressor.cs +++ b/src/ImageSharp/Formats/Tiff/Compression/Compressors/TiffJpegCompressor.cs @@ -33,7 +33,7 @@ public override void CompressStrip(Span rows, int height) var image = Image.LoadPixelData(rows, width, height); image.Save(memoryStream, new JpegEncoder() { - ColorType = JpegEncodingColor.Rgb + ColorType = JpegColorType.Rgb }); memoryStream.Position = 0; memoryStream.WriteTo(this.Output); diff --git a/src/ImageSharp/Formats/Tiff/Compression/HorizontalPredictor.cs b/src/ImageSharp/Formats/Tiff/Compression/HorizontalPredictor.cs index 1c838b0b76..30a9335286 100644 --- a/src/ImageSharp/Formats/Tiff/Compression/HorizontalPredictor.cs +++ b/src/ImageSharp/Formats/Tiff/Compression/HorizontalPredictor.cs @@ -102,8 +102,7 @@ private static void ApplyHorizontalPrediction24Bit(Span rows, int width) byte r = (byte)(rowRgb[x].R - rowRgb[x - 1].R); byte g = (byte)(rowRgb[x].G - rowRgb[x - 1].G); byte b = (byte)(rowRgb[x].B - rowRgb[x - 1].B); - var rgb = new Rgb24(r, g, b); - rowRgb[x].FromRgb24(rgb); + rowRgb[x] = new Rgb24(r, g, b); } } } @@ -128,8 +127,7 @@ private static void ApplyHorizontalPrediction16Bit(Span rows, int width) for (int x = rowL16.Length - 1; x >= 1; x--) { - ushort val = (ushort)(rowL16[x].PackedValue - rowL16[x - 1].PackedValue); - rowL16[x].PackedValue = val; + rowL16[x].PackedValue = (ushort)(rowL16[x].PackedValue - rowL16[x - 1].PackedValue); } } } @@ -181,13 +179,13 @@ private static void UndoGray16Bit(Span pixelBytes, int width, bool isBigEn { int offset = 0; Span rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount); - ushort pixelValue = TiffUtils.ConvertToUShortBigEndian(rowBytes.Slice(offset, 2)); + ushort pixelValue = TiffUtilities.ConvertToUShortBigEndian(rowBytes.Slice(offset, 2)); offset += 2; for (int x = 1; x < width; x++) { Span rowSpan = rowBytes.Slice(offset, 2); - ushort diff = TiffUtils.ConvertToUShortBigEndian(rowSpan); + ushort diff = TiffUtilities.ConvertToUShortBigEndian(rowSpan); pixelValue += diff; BinaryPrimitives.WriteUInt16BigEndian(rowSpan, pixelValue); offset += 2; @@ -200,13 +198,13 @@ private static void UndoGray16Bit(Span pixelBytes, int width, bool isBigEn { int offset = 0; Span rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount); - ushort pixelValue = TiffUtils.ConvertToUShortLittleEndian(rowBytes.Slice(offset, 2)); + ushort pixelValue = TiffUtilities.ConvertToUShortLittleEndian(rowBytes.Slice(offset, 2)); offset += 2; for (int x = 1; x < width; x++) { Span rowSpan = rowBytes.Slice(offset, 2); - ushort diff = TiffUtils.ConvertToUShortLittleEndian(rowSpan); + ushort diff = TiffUtilities.ConvertToUShortLittleEndian(rowSpan); pixelValue += diff; BinaryPrimitives.WriteUInt16LittleEndian(rowSpan, pixelValue); offset += 2; @@ -225,13 +223,13 @@ private static void UndoGray32Bit(Span pixelBytes, int width, bool isBigEn { int offset = 0; Span rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount); - uint pixelValue = TiffUtils.ConvertToUIntBigEndian(rowBytes.Slice(offset, 4)); + uint pixelValue = TiffUtilities.ConvertToUIntBigEndian(rowBytes.Slice(offset, 4)); offset += 4; for (int x = 1; x < width; x++) { Span rowSpan = rowBytes.Slice(offset, 4); - uint diff = TiffUtils.ConvertToUIntBigEndian(rowSpan); + uint diff = TiffUtilities.ConvertToUIntBigEndian(rowSpan); pixelValue += diff; BinaryPrimitives.WriteUInt32BigEndian(rowSpan, pixelValue); offset += 4; @@ -244,13 +242,13 @@ private static void UndoGray32Bit(Span pixelBytes, int width, bool isBigEn { int offset = 0; Span rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount); - uint pixelValue = TiffUtils.ConvertToUIntLittleEndian(rowBytes.Slice(offset, 4)); + uint pixelValue = TiffUtilities.ConvertToUIntLittleEndian(rowBytes.Slice(offset, 4)); offset += 4; for (int x = 1; x < width; x++) { Span rowSpan = rowBytes.Slice(offset, 4); - uint diff = TiffUtils.ConvertToUIntLittleEndian(rowSpan); + uint diff = TiffUtilities.ConvertToUIntLittleEndian(rowSpan); pixelValue += diff; BinaryPrimitives.WriteUInt32LittleEndian(rowSpan, pixelValue); offset += 4; @@ -278,8 +276,7 @@ private static void UndoRgb24Bit(Span pixelBytes, int width) r += pixel.R; g += pixel.G; b += pixel.B; - var rgb = new Rgb24(r, g, b); - pixel.FromRgb24(rgb); + pixel = new Rgb24(r, g, b); } } } @@ -305,8 +302,7 @@ private static void UndoRgba32Bit(Span pixelBytes, int width) g += pixel.G; b += pixel.B; a += pixel.A; - var rgb = new Rgba32(r, g, b, a); - pixel.FromRgba32(rgb); + pixel = new Rgba32(r, g, b, a); } } } @@ -321,29 +317,29 @@ private static void UndoRgb48Bit(Span pixelBytes, int width, bool isBigEnd { int offset = 0; Span rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount); - ushort r = TiffUtils.ConvertToUShortBigEndian(rowBytes.Slice(offset, 2)); + ushort r = TiffUtilities.ConvertToUShortBigEndian(rowBytes.Slice(offset, 2)); offset += 2; - ushort g = TiffUtils.ConvertToUShortBigEndian(rowBytes.Slice(offset, 2)); + ushort g = TiffUtilities.ConvertToUShortBigEndian(rowBytes.Slice(offset, 2)); offset += 2; - ushort b = TiffUtils.ConvertToUShortBigEndian(rowBytes.Slice(offset, 2)); + ushort b = TiffUtilities.ConvertToUShortBigEndian(rowBytes.Slice(offset, 2)); offset += 2; for (int x = 1; x < width; x++) { Span rowSpan = rowBytes.Slice(offset, 2); - ushort deltaR = TiffUtils.ConvertToUShortBigEndian(rowSpan); + ushort deltaR = TiffUtilities.ConvertToUShortBigEndian(rowSpan); r += deltaR; BinaryPrimitives.WriteUInt16BigEndian(rowSpan, r); offset += 2; rowSpan = rowBytes.Slice(offset, 2); - ushort deltaG = TiffUtils.ConvertToUShortBigEndian(rowSpan); + ushort deltaG = TiffUtilities.ConvertToUShortBigEndian(rowSpan); g += deltaG; BinaryPrimitives.WriteUInt16BigEndian(rowSpan, g); offset += 2; rowSpan = rowBytes.Slice(offset, 2); - ushort deltaB = TiffUtils.ConvertToUShortBigEndian(rowSpan); + ushort deltaB = TiffUtilities.ConvertToUShortBigEndian(rowSpan); b += deltaB; BinaryPrimitives.WriteUInt16BigEndian(rowSpan, b); offset += 2; @@ -356,29 +352,29 @@ private static void UndoRgb48Bit(Span pixelBytes, int width, bool isBigEnd { int offset = 0; Span rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount); - ushort r = TiffUtils.ConvertToUShortLittleEndian(rowBytes.Slice(offset, 2)); + ushort r = TiffUtilities.ConvertToUShortLittleEndian(rowBytes.Slice(offset, 2)); offset += 2; - ushort g = TiffUtils.ConvertToUShortLittleEndian(rowBytes.Slice(offset, 2)); + ushort g = TiffUtilities.ConvertToUShortLittleEndian(rowBytes.Slice(offset, 2)); offset += 2; - ushort b = TiffUtils.ConvertToUShortLittleEndian(rowBytes.Slice(offset, 2)); + ushort b = TiffUtilities.ConvertToUShortLittleEndian(rowBytes.Slice(offset, 2)); offset += 2; for (int x = 1; x < width; x++) { Span rowSpan = rowBytes.Slice(offset, 2); - ushort deltaR = TiffUtils.ConvertToUShortLittleEndian(rowSpan); + ushort deltaR = TiffUtilities.ConvertToUShortLittleEndian(rowSpan); r += deltaR; BinaryPrimitives.WriteUInt16LittleEndian(rowSpan, r); offset += 2; rowSpan = rowBytes.Slice(offset, 2); - ushort deltaG = TiffUtils.ConvertToUShortLittleEndian(rowSpan); + ushort deltaG = TiffUtilities.ConvertToUShortLittleEndian(rowSpan); g += deltaG; BinaryPrimitives.WriteUInt16LittleEndian(rowSpan, g); offset += 2; rowSpan = rowBytes.Slice(offset, 2); - ushort deltaB = TiffUtils.ConvertToUShortLittleEndian(rowSpan); + ushort deltaB = TiffUtilities.ConvertToUShortLittleEndian(rowSpan); b += deltaB; BinaryPrimitives.WriteUInt16LittleEndian(rowSpan, b); offset += 2; @@ -397,37 +393,37 @@ private static void UndoRgba64Bit(Span pixelBytes, int width, bool isBigEn { int offset = 0; Span rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount); - ushort r = TiffUtils.ConvertToUShortBigEndian(rowBytes.Slice(offset, 2)); + ushort r = TiffUtilities.ConvertToUShortBigEndian(rowBytes.Slice(offset, 2)); offset += 2; - ushort g = TiffUtils.ConvertToUShortBigEndian(rowBytes.Slice(offset, 2)); + ushort g = TiffUtilities.ConvertToUShortBigEndian(rowBytes.Slice(offset, 2)); offset += 2; - ushort b = TiffUtils.ConvertToUShortBigEndian(rowBytes.Slice(offset, 2)); + ushort b = TiffUtilities.ConvertToUShortBigEndian(rowBytes.Slice(offset, 2)); offset += 2; - ushort a = TiffUtils.ConvertToUShortBigEndian(rowBytes.Slice(offset, 2)); + ushort a = TiffUtilities.ConvertToUShortBigEndian(rowBytes.Slice(offset, 2)); offset += 2; for (int x = 1; x < width; x++) { Span rowSpan = rowBytes.Slice(offset, 2); - ushort deltaR = TiffUtils.ConvertToUShortBigEndian(rowSpan); + ushort deltaR = TiffUtilities.ConvertToUShortBigEndian(rowSpan); r += deltaR; BinaryPrimitives.WriteUInt16BigEndian(rowSpan, r); offset += 2; rowSpan = rowBytes.Slice(offset, 2); - ushort deltaG = TiffUtils.ConvertToUShortBigEndian(rowSpan); + ushort deltaG = TiffUtilities.ConvertToUShortBigEndian(rowSpan); g += deltaG; BinaryPrimitives.WriteUInt16BigEndian(rowSpan, g); offset += 2; rowSpan = rowBytes.Slice(offset, 2); - ushort deltaB = TiffUtils.ConvertToUShortBigEndian(rowSpan); + ushort deltaB = TiffUtilities.ConvertToUShortBigEndian(rowSpan); b += deltaB; BinaryPrimitives.WriteUInt16BigEndian(rowSpan, b); offset += 2; rowSpan = rowBytes.Slice(offset, 2); - ushort deltaA = TiffUtils.ConvertToUShortBigEndian(rowSpan); + ushort deltaA = TiffUtilities.ConvertToUShortBigEndian(rowSpan); a += deltaA; BinaryPrimitives.WriteUInt16BigEndian(rowSpan, a); offset += 2; @@ -440,37 +436,37 @@ private static void UndoRgba64Bit(Span pixelBytes, int width, bool isBigEn { int offset = 0; Span rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount); - ushort r = TiffUtils.ConvertToUShortLittleEndian(rowBytes.Slice(offset, 2)); + ushort r = TiffUtilities.ConvertToUShortLittleEndian(rowBytes.Slice(offset, 2)); offset += 2; - ushort g = TiffUtils.ConvertToUShortLittleEndian(rowBytes.Slice(offset, 2)); + ushort g = TiffUtilities.ConvertToUShortLittleEndian(rowBytes.Slice(offset, 2)); offset += 2; - ushort b = TiffUtils.ConvertToUShortLittleEndian(rowBytes.Slice(offset, 2)); + ushort b = TiffUtilities.ConvertToUShortLittleEndian(rowBytes.Slice(offset, 2)); offset += 2; - ushort a = TiffUtils.ConvertToUShortLittleEndian(rowBytes.Slice(offset, 2)); + ushort a = TiffUtilities.ConvertToUShortLittleEndian(rowBytes.Slice(offset, 2)); offset += 2; for (int x = 1; x < width; x++) { Span rowSpan = rowBytes.Slice(offset, 2); - ushort deltaR = TiffUtils.ConvertToUShortLittleEndian(rowSpan); + ushort deltaR = TiffUtilities.ConvertToUShortLittleEndian(rowSpan); r += deltaR; BinaryPrimitives.WriteUInt16LittleEndian(rowSpan, r); offset += 2; rowSpan = rowBytes.Slice(offset, 2); - ushort deltaG = TiffUtils.ConvertToUShortLittleEndian(rowSpan); + ushort deltaG = TiffUtilities.ConvertToUShortLittleEndian(rowSpan); g += deltaG; BinaryPrimitives.WriteUInt16LittleEndian(rowSpan, g); offset += 2; rowSpan = rowBytes.Slice(offset, 2); - ushort deltaB = TiffUtils.ConvertToUShortLittleEndian(rowSpan); + ushort deltaB = TiffUtilities.ConvertToUShortLittleEndian(rowSpan); b += deltaB; BinaryPrimitives.WriteUInt16LittleEndian(rowSpan, b); offset += 2; rowSpan = rowBytes.Slice(offset, 2); - ushort deltaA = TiffUtils.ConvertToUShortLittleEndian(rowSpan); + ushort deltaA = TiffUtilities.ConvertToUShortLittleEndian(rowSpan); a += deltaA; BinaryPrimitives.WriteUInt16LittleEndian(rowSpan, a); offset += 2; @@ -489,29 +485,29 @@ private static void UndoRgb96Bit(Span pixelBytes, int width, bool isBigEnd { int offset = 0; Span rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount); - uint r = TiffUtils.ConvertToUIntBigEndian(rowBytes.Slice(offset, 4)); + uint r = TiffUtilities.ConvertToUIntBigEndian(rowBytes.Slice(offset, 4)); offset += 4; - uint g = TiffUtils.ConvertToUIntBigEndian(rowBytes.Slice(offset, 4)); + uint g = TiffUtilities.ConvertToUIntBigEndian(rowBytes.Slice(offset, 4)); offset += 4; - uint b = TiffUtils.ConvertToUIntBigEndian(rowBytes.Slice(offset, 4)); + uint b = TiffUtilities.ConvertToUIntBigEndian(rowBytes.Slice(offset, 4)); offset += 4; for (int x = 1; x < width; x++) { Span rowSpan = rowBytes.Slice(offset, 4); - uint deltaR = TiffUtils.ConvertToUIntBigEndian(rowSpan); + uint deltaR = TiffUtilities.ConvertToUIntBigEndian(rowSpan); r += deltaR; BinaryPrimitives.WriteUInt32BigEndian(rowSpan, r); offset += 4; rowSpan = rowBytes.Slice(offset, 4); - uint deltaG = TiffUtils.ConvertToUIntBigEndian(rowSpan); + uint deltaG = TiffUtilities.ConvertToUIntBigEndian(rowSpan); g += deltaG; BinaryPrimitives.WriteUInt32BigEndian(rowSpan, g); offset += 4; rowSpan = rowBytes.Slice(offset, 4); - uint deltaB = TiffUtils.ConvertToUIntBigEndian(rowSpan); + uint deltaB = TiffUtilities.ConvertToUIntBigEndian(rowSpan); b += deltaB; BinaryPrimitives.WriteUInt32BigEndian(rowSpan, b); offset += 4; @@ -524,29 +520,29 @@ private static void UndoRgb96Bit(Span pixelBytes, int width, bool isBigEnd { int offset = 0; Span rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount); - uint r = TiffUtils.ConvertToUIntLittleEndian(rowBytes.Slice(offset, 4)); + uint r = TiffUtilities.ConvertToUIntLittleEndian(rowBytes.Slice(offset, 4)); offset += 4; - uint g = TiffUtils.ConvertToUIntLittleEndian(rowBytes.Slice(offset, 4)); + uint g = TiffUtilities.ConvertToUIntLittleEndian(rowBytes.Slice(offset, 4)); offset += 4; - uint b = TiffUtils.ConvertToUIntLittleEndian(rowBytes.Slice(offset, 4)); + uint b = TiffUtilities.ConvertToUIntLittleEndian(rowBytes.Slice(offset, 4)); offset += 4; for (int x = 1; x < width; x++) { Span rowSpan = rowBytes.Slice(offset, 4); - uint deltaR = TiffUtils.ConvertToUIntLittleEndian(rowSpan); + uint deltaR = TiffUtilities.ConvertToUIntLittleEndian(rowSpan); r += deltaR; BinaryPrimitives.WriteUInt32LittleEndian(rowSpan, r); offset += 4; rowSpan = rowBytes.Slice(offset, 4); - uint deltaG = TiffUtils.ConvertToUIntLittleEndian(rowSpan); + uint deltaG = TiffUtilities.ConvertToUIntLittleEndian(rowSpan); g += deltaG; BinaryPrimitives.WriteUInt32LittleEndian(rowSpan, g); offset += 4; rowSpan = rowBytes.Slice(offset, 4); - uint deltaB = TiffUtils.ConvertToUIntLittleEndian(rowSpan); + uint deltaB = TiffUtilities.ConvertToUIntLittleEndian(rowSpan); b += deltaB; BinaryPrimitives.WriteUInt32LittleEndian(rowSpan, b); offset += 4; @@ -565,37 +561,37 @@ private static void UndoRgba128Bit(Span pixelBytes, int width, bool isBigE { int offset = 0; Span rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount); - uint r = TiffUtils.ConvertToUIntBigEndian(rowBytes.Slice(offset, 4)); + uint r = TiffUtilities.ConvertToUIntBigEndian(rowBytes.Slice(offset, 4)); offset += 4; - uint g = TiffUtils.ConvertToUIntBigEndian(rowBytes.Slice(offset, 4)); + uint g = TiffUtilities.ConvertToUIntBigEndian(rowBytes.Slice(offset, 4)); offset += 4; - uint b = TiffUtils.ConvertToUIntBigEndian(rowBytes.Slice(offset, 4)); + uint b = TiffUtilities.ConvertToUIntBigEndian(rowBytes.Slice(offset, 4)); offset += 4; - uint a = TiffUtils.ConvertToUIntBigEndian(rowBytes.Slice(offset, 4)); + uint a = TiffUtilities.ConvertToUIntBigEndian(rowBytes.Slice(offset, 4)); offset += 4; for (int x = 1; x < width; x++) { Span rowSpan = rowBytes.Slice(offset, 4); - uint deltaR = TiffUtils.ConvertToUIntBigEndian(rowSpan); + uint deltaR = TiffUtilities.ConvertToUIntBigEndian(rowSpan); r += deltaR; BinaryPrimitives.WriteUInt32BigEndian(rowSpan, r); offset += 4; rowSpan = rowBytes.Slice(offset, 4); - uint deltaG = TiffUtils.ConvertToUIntBigEndian(rowSpan); + uint deltaG = TiffUtilities.ConvertToUIntBigEndian(rowSpan); g += deltaG; BinaryPrimitives.WriteUInt32BigEndian(rowSpan, g); offset += 4; rowSpan = rowBytes.Slice(offset, 4); - uint deltaB = TiffUtils.ConvertToUIntBigEndian(rowSpan); + uint deltaB = TiffUtilities.ConvertToUIntBigEndian(rowSpan); b += deltaB; BinaryPrimitives.WriteUInt32BigEndian(rowSpan, b); offset += 4; rowSpan = rowBytes.Slice(offset, 4); - uint deltaA = TiffUtils.ConvertToUIntBigEndian(rowSpan); + uint deltaA = TiffUtilities.ConvertToUIntBigEndian(rowSpan); a += deltaA; BinaryPrimitives.WriteUInt32BigEndian(rowSpan, a); offset += 4; @@ -608,37 +604,37 @@ private static void UndoRgba128Bit(Span pixelBytes, int width, bool isBigE { int offset = 0; Span rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount); - uint r = TiffUtils.ConvertToUIntLittleEndian(rowBytes.Slice(offset, 4)); + uint r = TiffUtilities.ConvertToUIntLittleEndian(rowBytes.Slice(offset, 4)); offset += 4; - uint g = TiffUtils.ConvertToUIntLittleEndian(rowBytes.Slice(offset, 4)); + uint g = TiffUtilities.ConvertToUIntLittleEndian(rowBytes.Slice(offset, 4)); offset += 4; - uint b = TiffUtils.ConvertToUIntLittleEndian(rowBytes.Slice(offset, 4)); + uint b = TiffUtilities.ConvertToUIntLittleEndian(rowBytes.Slice(offset, 4)); offset += 4; - uint a = TiffUtils.ConvertToUIntLittleEndian(rowBytes.Slice(offset, 4)); + uint a = TiffUtilities.ConvertToUIntLittleEndian(rowBytes.Slice(offset, 4)); offset += 4; for (int x = 1; x < width; x++) { Span rowSpan = rowBytes.Slice(offset, 4); - uint deltaR = TiffUtils.ConvertToUIntLittleEndian(rowSpan); + uint deltaR = TiffUtilities.ConvertToUIntLittleEndian(rowSpan); r += deltaR; BinaryPrimitives.WriteUInt32LittleEndian(rowSpan, r); offset += 4; rowSpan = rowBytes.Slice(offset, 4); - uint deltaG = TiffUtils.ConvertToUIntLittleEndian(rowSpan); + uint deltaG = TiffUtilities.ConvertToUIntLittleEndian(rowSpan); g += deltaG; BinaryPrimitives.WriteUInt32LittleEndian(rowSpan, g); offset += 4; rowSpan = rowBytes.Slice(offset, 4); - uint deltaB = TiffUtils.ConvertToUIntLittleEndian(rowSpan); + uint deltaB = TiffUtilities.ConvertToUIntLittleEndian(rowSpan); b += deltaB; BinaryPrimitives.WriteUInt32LittleEndian(rowSpan, b); offset += 4; rowSpan = rowBytes.Slice(offset, 4); - uint deltaA = TiffUtils.ConvertToUIntLittleEndian(rowSpan); + uint deltaA = TiffUtilities.ConvertToUIntLittleEndian(rowSpan); a += deltaA; BinaryPrimitives.WriteUInt32LittleEndian(rowSpan, a); offset += 4; diff --git a/src/ImageSharp/Formats/Tiff/Constants/TiffConstants.cs b/src/ImageSharp/Formats/Tiff/Constants/TiffConstants.cs index 978860910c..c24eee484b 100644 --- a/src/ImageSharp/Formats/Tiff/Constants/TiffConstants.cs +++ b/src/ImageSharp/Formats/Tiff/Constants/TiffConstants.cs @@ -39,9 +39,9 @@ internal static class TiffConstants public const ushort BigTiffHeaderMagicNumber = 43; /// - /// The big tiff bytesize of offsets value. + /// The big tiff byte size of offsets value. /// - public const ushort BigTiffBytesize = 8; + public const ushort BigTiffByteSize = 8; /// /// RowsPerStrip default value, which is effectively infinity. @@ -58,38 +58,63 @@ internal static class TiffConstants /// public const int DefaultStripSize = 8 * 1024; + /// + /// The default predictor is None. + /// + public const TiffPredictor DefaultPredictor = TiffPredictor.None; + + /// + /// The default bits per pixel is Bit24. + /// + public const TiffBitsPerPixel DefaultBitsPerPixel = TiffBitsPerPixel.Bit24; + + /// + /// The default bits per sample for color images with 8 bits for each color channel. + /// + public static readonly TiffBitsPerSample DefaultBitsPerSample = BitsPerSampleRgb8Bit; + + /// + /// The default compression is None. + /// + public const TiffCompression DefaultCompression = TiffCompression.None; + + /// + /// The default photometric interpretation is Rgb. + /// + public const TiffPhotometricInterpretation DefaultPhotometricInterpretation = TiffPhotometricInterpretation.Rgb; + /// /// The bits per sample for 1 bit bicolor images. /// - public static readonly TiffBitsPerSample BitsPerSample1Bit = new TiffBitsPerSample(1, 0, 0); + public static readonly TiffBitsPerSample BitsPerSample1Bit = new(1, 0, 0); /// /// The bits per sample for images with a 4 color palette. /// - public static readonly TiffBitsPerSample BitsPerSample4Bit = new TiffBitsPerSample(4, 0, 0); + public static readonly TiffBitsPerSample BitsPerSample4Bit = new(4, 0, 0); /// /// The bits per sample for 8 bit images. /// - public static readonly TiffBitsPerSample BitsPerSample8Bit = new TiffBitsPerSample(8, 0, 0); + public static readonly TiffBitsPerSample BitsPerSample8Bit = new(8, 0, 0); /// /// The bits per sample for 16-bit grayscale images. /// - public static readonly TiffBitsPerSample BitsPerSample16Bit = new TiffBitsPerSample(16, 0, 0); + public static readonly TiffBitsPerSample BitsPerSample16Bit = new(16, 0, 0); /// /// The bits per sample for color images with 8 bits for each color channel. /// - public static readonly TiffBitsPerSample BitsPerSampleRgb8Bit = new TiffBitsPerSample(8, 8, 8); + public static readonly TiffBitsPerSample BitsPerSampleRgb8Bit = new(8, 8, 8); /// - /// The list of mimetypes that equate to a tiff. + /// The list of mime types that equate to a tiff. /// - public static readonly IEnumerable MimeTypes = new[] { "image/tiff", "image/tiff-fx" }; + public static readonly IEnumerable MimeTypes = ["image/tiff", "image/tiff-fx"]; /// /// The list of file extensions that equate to a tiff. /// - public static readonly IEnumerable FileExtensions = new[] { "tiff", "tif" }; + public static readonly IEnumerable FileExtensions = ["tiff", "tif"]; } diff --git a/src/ImageSharp/Formats/Tiff/Ifd/DirectoryReader.cs b/src/ImageSharp/Formats/Tiff/Ifd/DirectoryReader.cs index 086eef0585..114fc12b23 100644 --- a/src/ImageSharp/Formats/Tiff/Ifd/DirectoryReader.cs +++ b/src/ImageSharp/Formats/Tiff/Ifd/DirectoryReader.cs @@ -71,7 +71,7 @@ private static ByteOrder ReadByteOrder(Stream stream) throw TiffThrowHelper.ThrowInvalidHeader(); } - private IList ReadIfds(bool isBigTiff) + private List ReadIfds(bool isBigTiff) { List readers = new(); while (this.nextIfdOffset != 0 && this.nextIfdOffset < (ulong)this.stream.Length) diff --git a/src/ImageSharp/Formats/Tiff/Ifd/EntryReader.cs b/src/ImageSharp/Formats/Tiff/Ifd/EntryReader.cs index 2673700092..4496de6fb5 100644 --- a/src/ImageSharp/Formats/Tiff/Ifd/EntryReader.cs +++ b/src/ImageSharp/Formats/Tiff/Ifd/EntryReader.cs @@ -64,7 +64,7 @@ public void ReadFileHeader() ushort bytesize = this.ReadUInt16(); ushort reserve = this.ReadUInt16(); - if (bytesize == TiffConstants.BigTiffBytesize && reserve == 0) + if (bytesize == TiffConstants.BigTiffByteSize && reserve == 0) { this.FirstIfdOffset = this.ReadUInt64(); return; diff --git a/src/ImageSharp/Formats/Tiff/MetadataExtensions.cs b/src/ImageSharp/Formats/Tiff/MetadataExtensions.cs deleted file mode 100644 index b06f5dd470..0000000000 --- a/src/ImageSharp/Formats/Tiff/MetadataExtensions.cs +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.Formats.Tiff; -using SixLabors.ImageSharp.Metadata; - -namespace SixLabors.ImageSharp; - -/// -/// Extension methods for the type. -/// -public static partial class MetadataExtensions -{ - /// - /// Gets the tiff format specific metadata for the image. - /// - /// The metadata this method extends. - /// The . - public static TiffMetadata GetTiffMetadata(this ImageMetadata metadata) => metadata.GetFormatMetadata(TiffFormat.Instance); - - /// - /// Gets the tiff format specific metadata for the image frame. - /// - /// The metadata this method extends. - /// The . - public static TiffFrameMetadata GetTiffMetadata(this ImageFrameMetadata metadata) => metadata.GetFormatMetadata(TiffFormat.Instance); -} diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero16TiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero16TiffColor{TPixel}.cs index 8763f99570..2ef261811b 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero16TiffColor{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero16TiffColor{TPixel}.cs @@ -11,6 +11,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation; /// /// Implements the 'BlackIsZero' photometric interpretation for 16-bit grayscale images. /// +/// The type of pixel format. internal class BlackIsZero16TiffColor : TiffBaseColorDecoder where TPixel : unmanaged, IPixel { @@ -32,9 +33,8 @@ public BlackIsZero16TiffColor(Configuration configuration, bool isBigEndian) /// public override void Decode(ReadOnlySpan data, Buffer2D pixels, int left, int top, int width, int height) { - L16 l16 = TiffUtils.L16Default; - var color = default(TPixel); - color.FromScaledVector4(Vector4.Zero); + L16 l16 = TiffUtilities.L16Default; + TPixel color = TPixel.FromScaledVector4(Vector4.Zero); int offset = 0; for (int y = top; y < top + height; y++) @@ -44,10 +44,10 @@ public override void Decode(ReadOnlySpan data, Buffer2D pixels, in { for (int x = 0; x < pixelRow.Length; x++) { - ushort intensity = TiffUtils.ConvertToUShortBigEndian(data.Slice(offset, 2)); + ushort intensity = TiffUtilities.ConvertToUShortBigEndian(data.Slice(offset, 2)); offset += 2; - pixelRow[x] = TiffUtils.ColorFromL16(l16, intensity, color); + pixelRow[x] = TPixel.FromL16(new(intensity)); } } else diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero1TiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero1TiffColor{TPixel}.cs index a8a70f7272..c9c0ee5810 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero1TiffColor{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero1TiffColor{TPixel}.cs @@ -19,11 +19,9 @@ internal class BlackIsZero1TiffColor : TiffBaseColorDecoder public override void Decode(ReadOnlySpan data, Buffer2D pixels, int left, int top, int width, int height) { nuint offset = 0; - TPixel colorBlack = default; - TPixel colorWhite = default; + TPixel colorBlack = TPixel.FromRgba32(Color.Black.ToPixel()); + TPixel colorWhite = TPixel.FromRgba32(Color.White.ToPixel()); - colorBlack.FromRgba32(Color.Black); - colorWhite.FromRgba32(Color.White); ref byte dataRef = ref MemoryMarshal.GetReference(data); for (nuint y = (uint)top; y < (uint)(top + height); y++) { diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero24TiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero24TiffColor{TPixel}.cs index d57130a5f5..07bf3d1bd7 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero24TiffColor{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero24TiffColor{TPixel}.cs @@ -1,7 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using System.Numerics; using SixLabors.ImageSharp.Formats.Tiff.Utils; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; @@ -11,6 +10,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation; /// /// Implements the 'BlackIsZero' photometric interpretation for 24-bit grayscale images. /// +/// The type of pixel format. internal class BlackIsZero24TiffColor : TiffBaseColorDecoder where TPixel : unmanaged, IPixel { @@ -25,8 +25,6 @@ internal class BlackIsZero24TiffColor : TiffBaseColorDecoder /// public override void Decode(ReadOnlySpan data, Buffer2D pixels, int left, int top, int width, int height) { - var color = default(TPixel); - color.FromScaledVector4(Vector4.Zero); Span buffer = stackalloc byte[4]; int bufferStartIdx = this.isBigEndian ? 1 : 0; @@ -40,10 +38,10 @@ public override void Decode(ReadOnlySpan data, Buffer2D pixels, in for (int x = 0; x < pixelRow.Length; x++) { data.Slice(offset, 3).CopyTo(bufferSpan); - ulong intensity = TiffUtils.ConvertToUIntBigEndian(buffer); + uint intensity = TiffUtilities.ConvertToUIntBigEndian(buffer); offset += 3; - pixelRow[x] = TiffUtils.ColorScaleTo24Bit(intensity, color); + pixelRow[x] = TiffUtilities.ColorScaleTo24Bit(intensity); } } else @@ -51,10 +49,10 @@ public override void Decode(ReadOnlySpan data, Buffer2D pixels, in for (int x = 0; x < pixelRow.Length; x++) { data.Slice(offset, 3).CopyTo(bufferSpan); - ulong intensity = TiffUtils.ConvertToUIntLittleEndian(buffer); + uint intensity = TiffUtilities.ConvertToUIntLittleEndian(buffer); offset += 3; - pixelRow[x] = TiffUtils.ColorScaleTo24Bit(intensity, color); + pixelRow[x] = TiffUtilities.ColorScaleTo24Bit(intensity); } } } diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero32FloatTiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero32FloatTiffColor{TPixel}.cs index df37327c35..ac316459d8 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero32FloatTiffColor{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero32FloatTiffColor{TPixel}.cs @@ -10,6 +10,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation; /// /// Implements the 'BlackIsZero' photometric interpretation for 32-bit float grayscale images. /// +/// The type of pixel format. internal class BlackIsZero32FloatTiffColor : TiffBaseColorDecoder where TPixel : unmanaged, IPixel { @@ -24,8 +25,6 @@ internal class BlackIsZero32FloatTiffColor : TiffBaseColorDecoder public override void Decode(ReadOnlySpan data, Buffer2D pixels, int left, int top, int width, int height) { - TPixel color = default; - color.FromScaledVector4(Vector4.Zero); Span buffer = stackalloc byte[4]; int offset = 0; @@ -41,9 +40,7 @@ public override void Decode(ReadOnlySpan data, Buffer2D pixels, in float intensity = BitConverter.ToSingle(buffer); offset += 4; - var colorVector = new Vector4(intensity, intensity, intensity, 1.0f); - color.FromScaledVector4(colorVector); - pixelRow[x] = color; + pixelRow[x] = TPixel.FromScaledVector4(new Vector4(intensity, intensity, intensity, 1f)); } } else @@ -53,9 +50,7 @@ public override void Decode(ReadOnlySpan data, Buffer2D pixels, in float intensity = BitConverter.ToSingle(data.Slice(offset, 4)); offset += 4; - var colorVector = new Vector4(intensity, intensity, intensity, 1.0f); - color.FromScaledVector4(colorVector); - pixelRow[x] = color; + pixelRow[x] = TPixel.FromScaledVector4(new Vector4(intensity, intensity, intensity, 1f)); } } } diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero32TiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero32TiffColor{TPixel}.cs index b5b3d8ee9e..d51a5af657 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero32TiffColor{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero32TiffColor{TPixel}.cs @@ -1,7 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using System.Numerics; using SixLabors.ImageSharp.Formats.Tiff.Utils; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; @@ -11,6 +10,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation; /// /// Implements the 'BlackIsZero' photometric interpretation for 32-bit grayscale images. /// +/// The type of pixel format. internal class BlackIsZero32TiffColor : TiffBaseColorDecoder where TPixel : unmanaged, IPixel { @@ -25,9 +25,6 @@ internal class BlackIsZero32TiffColor : TiffBaseColorDecoder /// public override void Decode(ReadOnlySpan data, Buffer2D pixels, int left, int top, int width, int height) { - var color = default(TPixel); - color.FromScaledVector4(Vector4.Zero); - int offset = 0; for (int y = top; y < top + height; y++) { @@ -36,20 +33,20 @@ public override void Decode(ReadOnlySpan data, Buffer2D pixels, in { for (int x = 0; x < pixelRow.Length; x++) { - ulong intensity = TiffUtils.ConvertToUIntBigEndian(data.Slice(offset, 4)); + uint intensity = TiffUtilities.ConvertToUIntBigEndian(data.Slice(offset, 4)); offset += 4; - pixelRow[x] = TiffUtils.ColorScaleTo32Bit(intensity, color); + pixelRow[x] = TiffUtilities.ColorScaleTo32Bit(intensity); } } else { for (int x = 0; x < pixelRow.Length; x++) { - ulong intensity = TiffUtils.ConvertToUIntLittleEndian(data.Slice(offset, 4)); + uint intensity = TiffUtilities.ConvertToUIntLittleEndian(data.Slice(offset, 4)); offset += 4; - pixelRow[x] = TiffUtils.ColorScaleTo32Bit(intensity, color); + pixelRow[x] = TiffUtilities.ColorScaleTo32Bit(intensity); } } } diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero4TiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero4TiffColor{TPixel}.cs index 16b995441c..1d33f1a248 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero4TiffColor{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero4TiffColor{TPixel}.cs @@ -9,47 +9,30 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation; /// /// Implements the 'BlackIsZero' photometric interpretation (optimized for 4-bit grayscale images). /// +/// The type of pixel format. internal class BlackIsZero4TiffColor : TiffBaseColorDecoder where TPixel : unmanaged, IPixel { /// public override void Decode(ReadOnlySpan data, Buffer2D pixels, int left, int top, int width, int height) { - var color = default(TPixel); - int offset = 0; bool isOddWidth = (width & 1) == 1; - var l8 = default(L8); for (int y = top; y < top + height; y++) { Span pixelRowSpan = pixels.DangerousGetRowSpan(y); for (int x = left; x < left + width - 1;) { byte byteData = data[offset++]; - - byte intensity1 = (byte)(((byteData & 0xF0) >> 4) * 17); - l8.PackedValue = intensity1; - color.FromL8(l8); - - pixelRowSpan[x++] = color; - - byte intensity2 = (byte)((byteData & 0x0F) * 17); - l8.PackedValue = intensity2; - color.FromL8(l8); - - pixelRowSpan[x++] = color; + pixelRowSpan[x++] = TPixel.FromL8(new((byte)(((byteData & 0xF0) >> 4) * 17))); + pixelRowSpan[x++] = TPixel.FromL8(new((byte)((byteData & 0x0F) * 17))); } if (isOddWidth) { byte byteData = data[offset++]; - - byte intensity1 = (byte)(((byteData & 0xF0) >> 4) * 17); - l8.PackedValue = intensity1; - color.FromL8(l8); - - pixelRowSpan[left + width - 1] = color; + pixelRowSpan[left + width - 1] = TPixel.FromL8(new((byte)(((byteData & 0xF0) >> 4) * 17))); } } } diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZeroTiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZeroTiffColor{TPixel}.cs index b086cb43ee..709c2bf649 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZeroTiffColor{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZeroTiffColor{TPixel}.cs @@ -1,7 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using System.Numerics; using SixLabors.ImageSharp.Formats.Tiff.Utils; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; @@ -11,25 +10,23 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation; /// /// Implements the 'BlackIsZero' photometric interpretation (for all bit depths). /// +/// The type of pixel format. internal class BlackIsZeroTiffColor : TiffBaseColorDecoder where TPixel : unmanaged, IPixel { private readonly ushort bitsPerSample0; - private readonly float factor; public BlackIsZeroTiffColor(TiffBitsPerSample bitsPerSample) { this.bitsPerSample0 = bitsPerSample.Channel0; - this.factor = (1 << this.bitsPerSample0) - 1.0f; + this.factor = (1 << this.bitsPerSample0) - 1f; } /// public override void Decode(ReadOnlySpan data, Buffer2D pixels, int left, int top, int width, int height) { - var color = default(TPixel); - - var bitReader = new BitReader(data); + BitReader bitReader = new(data); for (int y = top; y < top + height; y++) { @@ -38,9 +35,7 @@ public override void Decode(ReadOnlySpan data, Buffer2D pixels, in { int value = bitReader.ReadBits(this.bitsPerSample0); float intensity = value / this.factor; - - color.FromScaledVector4(new Vector4(intensity, intensity, intensity, 1.0f)); - pixelRow[x] = color; + pixelRow[x] = TPixel.FromScaledVector4(new(intensity, intensity, intensity, 1f)); } bitReader.NextRow(); diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/CieLabPlanarTiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/CieLabPlanarTiffColor{TPixel}.cs index 216d173309..d6fc7c4870 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/CieLabPlanarTiffColor{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/CieLabPlanarTiffColor{TPixel}.cs @@ -2,9 +2,7 @@ // Licensed under the Six Labors Split License. using System.Buffers; -using System.Numerics; -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; +using SixLabors.ImageSharp.ColorProfiles; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; @@ -13,32 +11,30 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation; /// /// Implements decoding pixel data with photometric interpretation of type 'CieLab' with the planar configuration. /// +/// The type of pixel format. internal class CieLabPlanarTiffColor : TiffBasePlanarColorDecoder where TPixel : unmanaged, IPixel { - private static readonly ColorSpaceConverter ColorSpaceConverter = new(); + private static readonly ColorProfileConverter ColorProfileConverter = new(); private const float Inv255 = 1.0f / 255.0f; /// public override void Decode(IMemoryOwner[] data, Buffer2D pixels, int left, int top, int width, int height) { - Span l = data[0].GetSpan(); - Span a = data[1].GetSpan(); Span b = data[2].GetSpan(); + Span a = data[1].GetSpan(); + Span l = data[0].GetSpan(); - var color = default(TPixel); int offset = 0; for (int y = top; y < top + height; y++) { Span pixelRow = pixels.DangerousGetRowSpan(y).Slice(left, width); for (int x = 0; x < pixelRow.Length; x++) { - var lab = new CieLab((l[offset] & 0xFF) * 100f * Inv255, (sbyte)a[offset], (sbyte)b[offset]); - var rgb = ColorSpaceConverter.ToRgb(lab); - - color.FromVector4(new Vector4(rgb.R, rgb.G, rgb.B, 1.0f)); - pixelRow[x] = color; + CieLab lab = new((l[offset] & 0xFF) * 100f * Inv255, (sbyte)a[offset], (sbyte)b[offset]); + Rgb rgb = ColorProfileConverter.Convert(in lab); + pixelRow[x] = TPixel.FromScaledVector4(new(rgb.R, rgb.G, rgb.B, 1.0f)); offset++; } diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/CieLabTiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/CieLabTiffColor{TPixel}.cs index b39a646443..b0236022b3 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/CieLabTiffColor{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/CieLabTiffColor{TPixel}.cs @@ -1,9 +1,7 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using System.Numerics; -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; +using SixLabors.ImageSharp.ColorProfiles; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; @@ -12,17 +10,16 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation; /// /// Implements decoding pixel data with photometric interpretation of type 'CieLab'. /// +/// The type of pixel format. internal class CieLabTiffColor : TiffBaseColorDecoder where TPixel : unmanaged, IPixel { - private static readonly ColorSpaceConverter ColorSpaceConverter = new(); - - private const float Inv255 = 1.0f / 255.0f; + private static readonly ColorProfileConverter ColorProfileConverter = new(); + private const float Inv255 = 1f / 255f; /// public override void Decode(ReadOnlySpan data, Buffer2D pixels, int left, int top, int width, int height) { - TPixel color = default; int offset = 0; for (int y = top; y < top + height; y++) { @@ -32,10 +29,8 @@ public override void Decode(ReadOnlySpan data, Buffer2D pixels, in { float l = (data[offset] & 0xFF) * 100f * Inv255; CieLab lab = new(l, (sbyte)data[offset + 1], (sbyte)data[offset + 2]); - Rgb rgb = ColorSpaceConverter.ToRgb(lab); - - color.FromVector4(new Vector4(rgb.R, rgb.G, rgb.B, 1.0f)); - pixelRow[x] = color; + Rgb rgb = ColorProfileConverter.Convert(in lab); + pixelRow[x] = TPixel.FromScaledVector4(new(rgb.R, rgb.G, rgb.B, 1f)); offset += 3; } diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/CmykTiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/CmykTiffColor{TPixel}.cs index c87051d527..c7fe2ed075 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/CmykTiffColor{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/CmykTiffColor{TPixel}.cs @@ -1,9 +1,7 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using System.Numerics; -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; +using SixLabors.ImageSharp.ColorProfiles; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; @@ -12,12 +10,12 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation; internal class CmykTiffColor : TiffBaseColorDecoder where TPixel : unmanaged, IPixel { - private const float Inv255 = 1 / 255.0f; + private static readonly ColorProfileConverter ColorProfileConverter = new(); + private const float Inv255 = 1f / 255f; /// public override void Decode(ReadOnlySpan data, Buffer2D pixels, int left, int top, int width, int height) { - TPixel color = default; int offset = 0; for (int y = top; y < top + height; y++) { @@ -25,10 +23,8 @@ public override void Decode(ReadOnlySpan data, Buffer2D pixels, in for (int x = 0; x < pixelRow.Length; x++) { Cmyk cmyk = new(data[offset] * Inv255, data[offset + 1] * Inv255, data[offset + 2] * Inv255, data[offset + 3] * Inv255); - Rgb rgb = ColorSpaceConverter.ToRgb(in cmyk); - - color.FromVector4(new Vector4(rgb.R, rgb.G, rgb.B, 1.0f)); - pixelRow[x] = color; + Rgb rgb = ColorProfileConverter.Convert(in cmyk); + pixelRow[x] = TPixel.FromScaledVector4(new(rgb.R, rgb.G, rgb.B, 1.0f)); offset += 4; } diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/PaletteTiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/PaletteTiffColor{TPixel}.cs index 22db1918cb..745e5846a9 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/PaletteTiffColor{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/PaletteTiffColor{TPixel}.cs @@ -1,7 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using System.Numerics; using SixLabors.ImageSharp.Formats.Tiff.Utils; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; @@ -11,6 +10,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation; /// /// Implements the 'PaletteTiffColor' photometric interpretation (for all bit depths). /// +/// The type of pixel format. internal class PaletteTiffColor : TiffBaseColorDecoder where TPixel : unmanaged, IPixel { @@ -18,8 +18,11 @@ internal class PaletteTiffColor : TiffBaseColorDecoder private readonly TPixel[] palette; - private const float InvMax = 1.0f / 65535F; + private const float InvMax = 1f / 65535f; + /// + /// Initializes a new instance of the class. + /// /// The number of bits per sample for each pixel. /// The RGB color lookup table to use for decoding the image. public PaletteTiffColor(TiffBitsPerSample bitsPerSample, ushort[] colorMap) @@ -32,7 +35,7 @@ public PaletteTiffColor(TiffBitsPerSample bitsPerSample, ushort[] colorMap) /// public override void Decode(ReadOnlySpan data, Buffer2D pixels, int left, int top, int width, int height) { - var bitReader = new BitReader(data); + BitReader bitReader = new(data); for (int y = top; y < top + height; y++) { @@ -49,7 +52,7 @@ public override void Decode(ReadOnlySpan data, Buffer2D pixels, in private static TPixel[] GeneratePalette(ushort[] colorMap, int colorCount) { - var palette = new TPixel[colorCount]; + TPixel[] palette = new TPixel[colorCount]; const int rOffset = 0; int gOffset = colorCount; @@ -60,7 +63,7 @@ private static TPixel[] GeneratePalette(ushort[] colorMap, int colorCount) float r = colorMap[rOffset + i] * InvMax; float g = colorMap[gOffset + i] * InvMax; float b = colorMap[bOffset + i] * InvMax; - palette[i].FromScaledVector4(new Vector4(r, g, b, 1.0f)); + palette[i] = TPixel.FromScaledVector4(new(r, g, b, 1f)); } return palette; diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb161616TiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb161616TiffColor{TPixel}.cs index 8ca45c9392..d8520e307e 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb161616TiffColor{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb161616TiffColor{TPixel}.cs @@ -1,7 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using System.Numerics; using SixLabors.ImageSharp.Formats.Tiff.Utils; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; @@ -11,11 +10,11 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation; /// /// Implements the 'RGB' photometric interpretation with 16 bits for each channel. /// +/// The type of pixel format. internal class Rgb161616TiffColor : TiffBaseColorDecoder where TPixel : unmanaged, IPixel { private readonly bool isBigEndian; - private readonly Configuration configuration; /// @@ -32,10 +31,6 @@ public Rgb161616TiffColor(Configuration configuration, bool isBigEndian) /// public override void Decode(ReadOnlySpan data, Buffer2D pixels, int left, int top, int width, int height) { - Rgba64 rgba = TiffUtils.Rgba64Default; - var color = default(TPixel); - color.FromScaledVector4(Vector4.Zero); - int offset = 0; for (int y = top; y < top + height; y++) @@ -46,14 +41,14 @@ public override void Decode(ReadOnlySpan data, Buffer2D pixels, in { for (int x = 0; x < pixelRow.Length; x++) { - ulong r = TiffUtils.ConvertToUShortBigEndian(data.Slice(offset, 2)); + ushort r = TiffUtilities.ConvertToUShortBigEndian(data.Slice(offset, 2)); offset += 2; - ulong g = TiffUtils.ConvertToUShortBigEndian(data.Slice(offset, 2)); + ushort g = TiffUtilities.ConvertToUShortBigEndian(data.Slice(offset, 2)); offset += 2; - ulong b = TiffUtils.ConvertToUShortBigEndian(data.Slice(offset, 2)); + ushort b = TiffUtilities.ConvertToUShortBigEndian(data.Slice(offset, 2)); offset += 2; - pixelRow[x] = TiffUtils.ColorFromRgb64(rgba, r, g, b, color); + pixelRow[x] = TPixel.FromRgb48(new(r, g, b)); } } else diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb16PlanarTiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb16PlanarTiffColor{TPixel}.cs index 08fb6d8bea..f55d7225e0 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb16PlanarTiffColor{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb16PlanarTiffColor{TPixel}.cs @@ -2,7 +2,6 @@ // Licensed under the Six Labors Split License. using System.Buffers; -using System.Numerics; using SixLabors.ImageSharp.Formats.Tiff.Utils; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; @@ -12,6 +11,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation; /// /// Implements the 'RGB' photometric interpretation with 'Planar' layout for each color channel with 16 bit. /// +/// The type of pixel format. internal class Rgb16PlanarTiffColor : TiffBasePlanarColorDecoder where TPixel : unmanaged, IPixel { @@ -26,10 +26,6 @@ internal class Rgb16PlanarTiffColor : TiffBasePlanarColorDecoder /// public override void Decode(IMemoryOwner[] data, Buffer2D pixels, int left, int top, int width, int height) { - Rgba64 rgba = TiffUtils.Rgba64Default; - var color = default(TPixel); - color.FromScaledVector4(Vector4.Zero); - Span redData = data[0].GetSpan(); Span greenData = data[1].GetSpan(); Span blueData = data[2].GetSpan(); @@ -42,26 +38,26 @@ public override void Decode(IMemoryOwner[] data, Buffer2D pixels, { for (int x = 0; x < pixelRow.Length; x++) { - ulong r = TiffUtils.ConvertToUShortBigEndian(redData.Slice(offset, 2)); - ulong g = TiffUtils.ConvertToUShortBigEndian(greenData.Slice(offset, 2)); - ulong b = TiffUtils.ConvertToUShortBigEndian(blueData.Slice(offset, 2)); + ushort r = TiffUtilities.ConvertToUShortBigEndian(redData.Slice(offset, 2)); + ushort g = TiffUtilities.ConvertToUShortBigEndian(greenData.Slice(offset, 2)); + ushort b = TiffUtilities.ConvertToUShortBigEndian(blueData.Slice(offset, 2)); offset += 2; - pixelRow[x] = TiffUtils.ColorFromRgb64(rgba, r, g, b, color); + pixelRow[x] = TPixel.FromRgb48(new(r, g, b)); } } else { for (int x = 0; x < pixelRow.Length; x++) { - ulong r = TiffUtils.ConvertToUShortLittleEndian(redData.Slice(offset, 2)); - ulong g = TiffUtils.ConvertToUShortLittleEndian(greenData.Slice(offset, 2)); - ulong b = TiffUtils.ConvertToUShortLittleEndian(blueData.Slice(offset, 2)); + ushort r = TiffUtilities.ConvertToUShortLittleEndian(redData.Slice(offset, 2)); + ushort g = TiffUtilities.ConvertToUShortLittleEndian(greenData.Slice(offset, 2)); + ushort b = TiffUtilities.ConvertToUShortLittleEndian(blueData.Slice(offset, 2)); offset += 2; - pixelRow[x] = TiffUtils.ColorFromRgb64(rgba, r, g, b, color); + pixelRow[x] = TPixel.FromRgb48(new(r, g, b)); } } } diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb242424TiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb242424TiffColor{TPixel}.cs index 027dcce3bd..074c085301 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb242424TiffColor{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb242424TiffColor{TPixel}.cs @@ -1,7 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using System.Numerics; using SixLabors.ImageSharp.Formats.Tiff.Utils; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; @@ -11,6 +10,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation; /// /// Implements the 'RGB' photometric interpretation with 24 bits for each channel. /// +/// The type of pixel format. internal class Rgb242424TiffColor : TiffBaseColorDecoder where TPixel : unmanaged, IPixel { @@ -25,8 +25,6 @@ internal class Rgb242424TiffColor : TiffBaseColorDecoder /// public override void Decode(ReadOnlySpan data, Buffer2D pixels, int left, int top, int width, int height) { - var color = default(TPixel); - color.FromScaledVector4(Vector4.Zero); int offset = 0; Span buffer = stackalloc byte[4]; int bufferStartIdx = this.isBigEndian ? 1 : 0; @@ -41,18 +39,18 @@ public override void Decode(ReadOnlySpan data, Buffer2D pixels, in for (int x = 0; x < pixelRow.Length; x++) { data.Slice(offset, 3).CopyTo(bufferSpan); - ulong r = TiffUtils.ConvertToUIntBigEndian(buffer); + uint r = TiffUtilities.ConvertToUIntBigEndian(buffer); offset += 3; data.Slice(offset, 3).CopyTo(bufferSpan); - ulong g = TiffUtils.ConvertToUIntBigEndian(buffer); + uint g = TiffUtilities.ConvertToUIntBigEndian(buffer); offset += 3; data.Slice(offset, 3).CopyTo(bufferSpan); - ulong b = TiffUtils.ConvertToUIntBigEndian(buffer); + uint b = TiffUtilities.ConvertToUIntBigEndian(buffer); offset += 3; - pixelRow[x] = TiffUtils.ColorScaleTo24Bit(r, g, b, color); + pixelRow[x] = TiffUtilities.ColorScaleTo24Bit(r, g, b); } } else @@ -60,18 +58,18 @@ public override void Decode(ReadOnlySpan data, Buffer2D pixels, in for (int x = 0; x < pixelRow.Length; x++) { data.Slice(offset, 3).CopyTo(bufferSpan); - ulong r = TiffUtils.ConvertToUIntLittleEndian(buffer); + uint r = TiffUtilities.ConvertToUIntLittleEndian(buffer); offset += 3; data.Slice(offset, 3).CopyTo(bufferSpan); - ulong g = TiffUtils.ConvertToUIntLittleEndian(buffer); + uint g = TiffUtilities.ConvertToUIntLittleEndian(buffer); offset += 3; data.Slice(offset, 3).CopyTo(bufferSpan); - ulong b = TiffUtils.ConvertToUIntLittleEndian(buffer); + uint b = TiffUtilities.ConvertToUIntLittleEndian(buffer); offset += 3; - pixelRow[x] = TiffUtils.ColorScaleTo24Bit(r, g, b, color); + pixelRow[x] = TiffUtilities.ColorScaleTo24Bit(r, g, b); } } } diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb24PlanarTiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb24PlanarTiffColor{TPixel}.cs index eba29a7f70..03ee94c27a 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb24PlanarTiffColor{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb24PlanarTiffColor{TPixel}.cs @@ -2,7 +2,6 @@ // Licensed under the Six Labors Split License. using System.Buffers; -using System.Numerics; using SixLabors.ImageSharp.Formats.Tiff.Utils; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; @@ -12,6 +11,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation; /// /// Implements the 'RGB' photometric interpretation with 'Planar' layout for each color channel with 24 bit. /// +/// The type of pixel format. internal class Rgb24PlanarTiffColor : TiffBasePlanarColorDecoder where TPixel : unmanaged, IPixel { @@ -26,8 +26,6 @@ internal class Rgb24PlanarTiffColor : TiffBasePlanarColorDecoder /// public override void Decode(IMemoryOwner[] data, Buffer2D pixels, int left, int top, int width, int height) { - var color = default(TPixel); - color.FromScaledVector4(Vector4.Zero); Span buffer = stackalloc byte[4]; int bufferStartIdx = this.isBigEndian ? 1 : 0; @@ -45,15 +43,15 @@ public override void Decode(IMemoryOwner[] data, Buffer2D pixels, for (int x = 0; x < pixelRow.Length; x++) { redData.Slice(offset, 3).CopyTo(bufferSpan); - ulong r = TiffUtils.ConvertToUIntBigEndian(buffer); + uint r = TiffUtilities.ConvertToUIntBigEndian(buffer); greenData.Slice(offset, 3).CopyTo(bufferSpan); - ulong g = TiffUtils.ConvertToUIntBigEndian(buffer); + uint g = TiffUtilities.ConvertToUIntBigEndian(buffer); blueData.Slice(offset, 3).CopyTo(bufferSpan); - ulong b = TiffUtils.ConvertToUIntBigEndian(buffer); + uint b = TiffUtilities.ConvertToUIntBigEndian(buffer); offset += 3; - pixelRow[x] = TiffUtils.ColorScaleTo24Bit(r, g, b, color); + pixelRow[x] = TiffUtilities.ColorScaleTo24Bit(r, g, b); } } else @@ -61,15 +59,15 @@ public override void Decode(IMemoryOwner[] data, Buffer2D pixels, for (int x = 0; x < pixelRow.Length; x++) { redData.Slice(offset, 3).CopyTo(bufferSpan); - ulong r = TiffUtils.ConvertToUIntLittleEndian(buffer); + uint r = TiffUtilities.ConvertToUIntLittleEndian(buffer); greenData.Slice(offset, 3).CopyTo(bufferSpan); - ulong g = TiffUtils.ConvertToUIntLittleEndian(buffer); + uint g = TiffUtilities.ConvertToUIntLittleEndian(buffer); blueData.Slice(offset, 3).CopyTo(bufferSpan); - ulong b = TiffUtils.ConvertToUIntLittleEndian(buffer); + uint b = TiffUtilities.ConvertToUIntLittleEndian(buffer); offset += 3; - pixelRow[x] = TiffUtils.ColorScaleTo24Bit(r, g, b, color); + pixelRow[x] = TiffUtilities.ColorScaleTo24Bit(r, g, b); } } } diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb323232TiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb323232TiffColor{TPixel}.cs index 79f66c1431..5f04972595 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb323232TiffColor{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb323232TiffColor{TPixel}.cs @@ -1,7 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using System.Numerics; using SixLabors.ImageSharp.Formats.Tiff.Utils; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; @@ -11,6 +10,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation; /// /// Implements the 'RGB' photometric interpretation with 32 bits for each channel. /// +/// The type of pixel format. internal class Rgb323232TiffColor : TiffBaseColorDecoder where TPixel : unmanaged, IPixel { @@ -25,8 +25,6 @@ internal class Rgb323232TiffColor : TiffBaseColorDecoder /// public override void Decode(ReadOnlySpan data, Buffer2D pixels, int left, int top, int width, int height) { - var color = default(TPixel); - color.FromScaledVector4(Vector4.Zero); int offset = 0; for (int y = top; y < top + height; y++) @@ -37,32 +35,32 @@ public override void Decode(ReadOnlySpan data, Buffer2D pixels, in { for (int x = 0; x < pixelRow.Length; x++) { - ulong r = TiffUtils.ConvertToUIntBigEndian(data.Slice(offset, 4)); + uint r = TiffUtilities.ConvertToUIntBigEndian(data.Slice(offset, 4)); offset += 4; - ulong g = TiffUtils.ConvertToUIntBigEndian(data.Slice(offset, 4)); + uint g = TiffUtilities.ConvertToUIntBigEndian(data.Slice(offset, 4)); offset += 4; - ulong b = TiffUtils.ConvertToUIntBigEndian(data.Slice(offset, 4)); + uint b = TiffUtilities.ConvertToUIntBigEndian(data.Slice(offset, 4)); offset += 4; - pixelRow[x] = TiffUtils.ColorScaleTo32Bit(r, g, b, color); + pixelRow[x] = TiffUtilities.ColorScaleTo32Bit(r, g, b); } } else { for (int x = 0; x < pixelRow.Length; x++) { - ulong r = TiffUtils.ConvertToUIntLittleEndian(data.Slice(offset, 4)); + uint r = TiffUtilities.ConvertToUIntLittleEndian(data.Slice(offset, 4)); offset += 4; - ulong g = TiffUtils.ConvertToUIntLittleEndian(data.Slice(offset, 4)); + uint g = TiffUtilities.ConvertToUIntLittleEndian(data.Slice(offset, 4)); offset += 4; - ulong b = TiffUtils.ConvertToUIntLittleEndian(data.Slice(offset, 4)); + uint b = TiffUtilities.ConvertToUIntLittleEndian(data.Slice(offset, 4)); offset += 4; - pixelRow[x] = TiffUtils.ColorScaleTo32Bit(r, g, b, color); + pixelRow[x] = TiffUtilities.ColorScaleTo32Bit(r, g, b); } } } diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb32PlanarTiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb32PlanarTiffColor{TPixel}.cs index 472697dd5e..caa6eb51d7 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb32PlanarTiffColor{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb32PlanarTiffColor{TPixel}.cs @@ -2,7 +2,6 @@ // Licensed under the Six Labors Split License. using System.Buffers; -using System.Numerics; using SixLabors.ImageSharp.Formats.Tiff.Utils; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; @@ -12,6 +11,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation; /// /// Implements the 'RGB' photometric interpretation with 'Planar' layout for each color channel with 32 bit. /// +/// The type of pixel format. internal class Rgb32PlanarTiffColor : TiffBasePlanarColorDecoder where TPixel : unmanaged, IPixel { @@ -26,9 +26,6 @@ internal class Rgb32PlanarTiffColor : TiffBasePlanarColorDecoder /// public override void Decode(IMemoryOwner[] data, Buffer2D pixels, int left, int top, int width, int height) { - var color = default(TPixel); - color.FromScaledVector4(Vector4.Zero); - Span redData = data[0].GetSpan(); Span greenData = data[1].GetSpan(); Span blueData = data[2].GetSpan(); @@ -41,26 +38,26 @@ public override void Decode(IMemoryOwner[] data, Buffer2D pixels, { for (int x = 0; x < pixelRow.Length; x++) { - ulong r = TiffUtils.ConvertToUIntBigEndian(redData.Slice(offset, 4)); - ulong g = TiffUtils.ConvertToUIntBigEndian(greenData.Slice(offset, 4)); - ulong b = TiffUtils.ConvertToUIntBigEndian(blueData.Slice(offset, 4)); + uint r = TiffUtilities.ConvertToUIntBigEndian(redData.Slice(offset, 4)); + uint g = TiffUtilities.ConvertToUIntBigEndian(greenData.Slice(offset, 4)); + uint b = TiffUtilities.ConvertToUIntBigEndian(blueData.Slice(offset, 4)); offset += 4; - pixelRow[x] = TiffUtils.ColorScaleTo32Bit(r, g, b, color); + pixelRow[x] = TiffUtilities.ColorScaleTo32Bit(r, g, b); } } else { for (int x = 0; x < pixelRow.Length; x++) { - ulong r = TiffUtils.ConvertToUIntLittleEndian(redData.Slice(offset, 4)); - ulong g = TiffUtils.ConvertToUIntLittleEndian(greenData.Slice(offset, 4)); - ulong b = TiffUtils.ConvertToUIntLittleEndian(blueData.Slice(offset, 4)); + uint r = TiffUtilities.ConvertToUIntLittleEndian(redData.Slice(offset, 4)); + uint g = TiffUtilities.ConvertToUIntLittleEndian(greenData.Slice(offset, 4)); + uint b = TiffUtilities.ConvertToUIntLittleEndian(blueData.Slice(offset, 4)); offset += 4; - pixelRow[x] = TiffUtils.ColorScaleTo32Bit(r, g, b, color); + pixelRow[x] = TiffUtilities.ColorScaleTo32Bit(r, g, b); } } } diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb444TiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb444TiffColor{TPixel}.cs index 7c6a4a0ec5..3a90e81746 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb444TiffColor{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb444TiffColor{TPixel}.cs @@ -9,17 +9,15 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation; /// /// Implements the 'RGB' photometric interpretation for 4 bits per color channel images. /// +/// The type of pixel format. internal class Rgb444TiffColor : TiffBaseColorDecoder where TPixel : unmanaged, IPixel { /// public override void Decode(ReadOnlySpan data, Buffer2D pixels, int left, int top, int width, int height) { - var color = default(TPixel); - int offset = 0; - var bgra = default(Bgra4444); for (int y = top; y < top + height; y++) { Span pixelRow = pixels.DangerousGetRowSpan(y); @@ -31,9 +29,8 @@ public override void Decode(ReadOnlySpan data, Buffer2D pixels, in offset++; byte b = (byte)((data[offset] & 0xF0) >> 4); - bgra.PackedValue = ToBgraPackedValue(b, g, r); - color.FromScaledVector4(bgra.ToScaledVector4()); - pixelRow[x] = color; + Bgra4444 bgra = new() { PackedValue = ToBgraPackedValue(b, g, r) }; + pixelRow[x] = TPixel.FromScaledVector4(bgra.ToScaledVector4()); if (x + 1 >= pixelRow.Length) { offset++; @@ -47,8 +44,7 @@ public override void Decode(ReadOnlySpan data, Buffer2D pixels, in offset++; bgra.PackedValue = ToBgraPackedValue(b, g, r); - color.FromScaledVector4(bgra.ToScaledVector4()); - pixelRow[x + 1] = color; + pixelRow[x + 1] = TPixel.FromScaledVector4(bgra.ToScaledVector4()); } } } diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbFloat323232TiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbFloat323232TiffColor{TPixel}.cs index 1c3af55621..37605ef804 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbFloat323232TiffColor{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbFloat323232TiffColor{TPixel}.cs @@ -1,7 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using System.Numerics; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; @@ -10,6 +9,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation; /// /// Implements the 'RGB' photometric interpretation with 32 bits for each channel. /// +/// The type of pixel format. internal class RgbFloat323232TiffColor : TiffBaseColorDecoder where TPixel : unmanaged, IPixel { @@ -24,8 +24,6 @@ internal class RgbFloat323232TiffColor : TiffBaseColorDecoder /// public override void Decode(ReadOnlySpan data, Buffer2D pixels, int left, int top, int width, int height) { - var color = default(TPixel); - color.FromScaledVector4(Vector4.Zero); int offset = 0; Span buffer = stackalloc byte[4]; @@ -52,9 +50,7 @@ public override void Decode(ReadOnlySpan data, Buffer2D pixels, in float b = BitConverter.ToSingle(buffer); offset += 4; - var colorVector = new Vector4(r, g, b, 1.0f); - color.FromScaledVector4(colorVector); - pixelRow[x] = color; + pixelRow[x] = TPixel.FromScaledVector4(new(r, g, b, 1f)); } } else @@ -70,9 +66,7 @@ public override void Decode(ReadOnlySpan data, Buffer2D pixels, in float b = BitConverter.ToSingle(data.Slice(offset, 4)); offset += 4; - var colorVector = new Vector4(r, g, b, 1.0f); - color.FromScaledVector4(colorVector); - pixelRow[x] = color; + pixelRow[x] = TPixel.FromScaledVector4(new(r, g, b, 1f)); } } } diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbPlanarTiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbPlanarTiffColor{TPixel}.cs index 0b822f5a0f..844b08d3c0 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbPlanarTiffColor{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbPlanarTiffColor{TPixel}.cs @@ -2,7 +2,6 @@ // Licensed under the Six Labors Split License. using System.Buffers; -using System.Numerics; using SixLabors.ImageSharp.Formats.Tiff.Utils; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; @@ -12,6 +11,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation; /// /// Implements the 'RGB' photometric interpretation with 'Planar' layout (for all bit depths). /// +/// The type of pixel format. internal class RgbPlanarTiffColor : TiffBasePlanarColorDecoder where TPixel : unmanaged, IPixel { @@ -49,11 +49,9 @@ public RgbPlanarTiffColor(TiffBitsPerSample bitsPerSample) /// The height of the image block. public override void Decode(IMemoryOwner[] data, Buffer2D pixels, int left, int top, int width, int height) { - var color = default(TPixel); - - var rBitReader = new BitReader(data[0].GetSpan()); - var gBitReader = new BitReader(data[1].GetSpan()); - var bBitReader = new BitReader(data[2].GetSpan()); + BitReader rBitReader = new(data[0].GetSpan()); + BitReader gBitReader = new(data[1].GetSpan()); + BitReader bBitReader = new(data[2].GetSpan()); for (int y = top; y < top + height; y++) { @@ -64,8 +62,7 @@ public override void Decode(IMemoryOwner[] data, Buffer2D pixels, float g = gBitReader.ReadBits(this.bitsPerSampleG) / this.gFactor; float b = bBitReader.ReadBits(this.bitsPerSampleB) / this.bFactor; - color.FromScaledVector4(new Vector4(r, g, b, 1.0f)); - pixelRow[x] = color; + pixelRow[x] = TPixel.FromScaledVector4(new(r, g, b, 1f)); } rBitReader.NextRow(); diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbTiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbTiffColor{TPixel}.cs index dcaab94a6a..3c205d1476 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbTiffColor{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbTiffColor{TPixel}.cs @@ -11,6 +11,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation; /// /// Implements the 'RGB' photometric interpretation (for all bit depths). /// +/// The type of pixel format. internal class RgbTiffColor : TiffBaseColorDecoder where TPixel : unmanaged, IPixel { @@ -40,9 +41,7 @@ public RgbTiffColor(TiffBitsPerSample bitsPerSample) /// public override void Decode(ReadOnlySpan data, Buffer2D pixels, int left, int top, int width, int height) { - var color = default(TPixel); - - var bitReader = new BitReader(data); + BitReader bitReader = new(data); for (int y = top; y < top + height; y++) { @@ -53,8 +52,7 @@ public override void Decode(ReadOnlySpan data, Buffer2D pixels, in float g = bitReader.ReadBits(this.bitsPerSampleG) / this.gFactor; float b = bitReader.ReadBits(this.bitsPerSampleB) / this.bFactor; - color.FromScaledVector4(new Vector4(r, g, b, 1.0f)); - pixelRow[x] = color; + pixelRow[x] = TPixel.FromScaledVector4(new Vector4(r, g, b, 1f)); } bitReader.NextRow(); diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba16161616TiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba16161616TiffColor{TPixel}.cs index 0467f7ad5c..e4965887d6 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba16161616TiffColor{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba16161616TiffColor{TPixel}.cs @@ -13,6 +13,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation; /// /// Implements the 'RGB' photometric interpretation with an alpha channel and with 16 bits for each channel. /// +/// The type of pixel format. internal class Rgba16161616TiffColor : TiffBaseColorDecoder where TPixel : unmanaged, IPixel { @@ -29,8 +30,8 @@ internal class Rgba16161616TiffColor : TiffBaseColorDecoder /// /// The configuration. /// The memory allocator. - /// if set to true decodes the pixel data as big endian, otherwise as little endian. /// The type of the extra samples. + /// if set to true decodes the pixel data as big endian, otherwise as little endian. public Rgba16161616TiffColor(Configuration configuration, MemoryAllocator memoryAllocator, TiffExtraSampleType? extraSamplesType, bool isBigEndian) { this.configuration = configuration; @@ -42,15 +43,11 @@ public Rgba16161616TiffColor(Configuration configuration, MemoryAllocator memory /// public override void Decode(ReadOnlySpan data, Buffer2D pixels, int left, int top, int width, int height) { - Rgba64 rgba = TiffUtils.Rgba64Default; - var color = default(TPixel); - color.FromScaledVector4(Vector4.Zero); - bool hasAssociatedAlpha = this.extraSamplesType.HasValue && this.extraSamplesType == TiffExtraSampleType.AssociatedAlphaData; int offset = 0; using IMemoryOwner vectors = hasAssociatedAlpha ? this.memoryAllocator.Allocate(width) : null; - Span vectorsSpan = hasAssociatedAlpha ? vectors.GetSpan() : Span.Empty; + Span vectorsSpan = hasAssociatedAlpha ? vectors.GetSpan() : []; for (int y = top; y < top + height; y++) { Span pixelRow = pixels.DangerousGetRowSpan(y).Slice(left, width); @@ -59,18 +56,18 @@ public override void Decode(ReadOnlySpan data, Buffer2D pixels, in { for (int x = 0; x < pixelRow.Length; x++) { - ulong r = TiffUtils.ConvertToUShortBigEndian(data.Slice(offset, 2)); + ushort r = TiffUtilities.ConvertToUShortBigEndian(data.Slice(offset, 2)); offset += 2; - ulong g = TiffUtils.ConvertToUShortBigEndian(data.Slice(offset, 2)); + ushort g = TiffUtilities.ConvertToUShortBigEndian(data.Slice(offset, 2)); offset += 2; - ulong b = TiffUtils.ConvertToUShortBigEndian(data.Slice(offset, 2)); + ushort b = TiffUtilities.ConvertToUShortBigEndian(data.Slice(offset, 2)); offset += 2; - ulong a = TiffUtils.ConvertToUShortBigEndian(data.Slice(offset, 2)); + ushort a = TiffUtilities.ConvertToUShortBigEndian(data.Slice(offset, 2)); offset += 2; - pixelRow[x] = hasAssociatedAlpha ? - TiffUtils.ColorFromRgba64Premultiplied(rgba, r, g, b, a, color) : - TiffUtils.ColorFromRgba64(rgba, r, g, b, a, color); + pixelRow[x] = hasAssociatedAlpha + ? TiffUtilities.ColorFromRgba64Premultiplied(r, g, b, a) + : TPixel.FromRgba64(new(r, g, b, a)); } } else diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba16PlanarTiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba16PlanarTiffColor{TPixel}.cs index 7426544d29..3d36db17de 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba16PlanarTiffColor{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba16PlanarTiffColor{TPixel}.cs @@ -2,7 +2,6 @@ // Licensed under the Six Labors Split License. using System.Buffers; -using System.Numerics; using SixLabors.ImageSharp.Formats.Tiff.Utils; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; @@ -12,6 +11,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation; /// /// Implements the 'RGB' photometric interpretation with an alpha channel and with 'Planar' layout for each color channel with 16 bit. /// +/// The type of pixel format. internal class Rgba16PlanarTiffColor : TiffBasePlanarColorDecoder where TPixel : unmanaged, IPixel { @@ -33,10 +33,6 @@ public Rgba16PlanarTiffColor(TiffExtraSampleType? extraSamplesType, bool isBigEn /// public override void Decode(IMemoryOwner[] data, Buffer2D pixels, int left, int top, int width, int height) { - Rgba64 rgba = TiffUtils.Rgba64Default; - var color = default(TPixel); - color.FromScaledVector4(Vector4.Zero); - Span redData = data[0].GetSpan(); Span greenData = data[1].GetSpan(); Span blueData = data[2].GetSpan(); @@ -51,32 +47,32 @@ public override void Decode(IMemoryOwner[] data, Buffer2D pixels, { for (int x = 0; x < pixelRow.Length; x++) { - ulong r = TiffUtils.ConvertToUShortBigEndian(redData.Slice(offset, 2)); - ulong g = TiffUtils.ConvertToUShortBigEndian(greenData.Slice(offset, 2)); - ulong b = TiffUtils.ConvertToUShortBigEndian(blueData.Slice(offset, 2)); - ulong a = TiffUtils.ConvertToUShortBigEndian(alphaData.Slice(offset, 2)); + ushort r = TiffUtilities.ConvertToUShortBigEndian(redData.Slice(offset, 2)); + ushort g = TiffUtilities.ConvertToUShortBigEndian(greenData.Slice(offset, 2)); + ushort b = TiffUtilities.ConvertToUShortBigEndian(blueData.Slice(offset, 2)); + ushort a = TiffUtilities.ConvertToUShortBigEndian(alphaData.Slice(offset, 2)); offset += 2; - pixelRow[x] = hasAssociatedAlpha ? - TiffUtils.ColorFromRgba64Premultiplied(rgba, r, g, b, a, color) : - TiffUtils.ColorFromRgba64(rgba, r, g, b, a, color); + pixelRow[x] = hasAssociatedAlpha + ? TiffUtilities.ColorFromRgba64Premultiplied(r, g, b, a) + : TPixel.FromRgba64(new(r, g, b, a)); } } else { for (int x = 0; x < pixelRow.Length; x++) { - ulong r = TiffUtils.ConvertToUShortLittleEndian(redData.Slice(offset, 2)); - ulong g = TiffUtils.ConvertToUShortLittleEndian(greenData.Slice(offset, 2)); - ulong b = TiffUtils.ConvertToUShortLittleEndian(blueData.Slice(offset, 2)); - ulong a = TiffUtils.ConvertToUShortLittleEndian(alphaData.Slice(offset, 2)); + ushort r = TiffUtilities.ConvertToUShortLittleEndian(redData.Slice(offset, 2)); + ushort g = TiffUtilities.ConvertToUShortLittleEndian(greenData.Slice(offset, 2)); + ushort b = TiffUtilities.ConvertToUShortLittleEndian(blueData.Slice(offset, 2)); + ushort a = TiffUtilities.ConvertToUShortLittleEndian(alphaData.Slice(offset, 2)); offset += 2; - pixelRow[x] = hasAssociatedAlpha ? - TiffUtils.ColorFromRgba64Premultiplied(rgba, r, g, b, a, color) : - TiffUtils.ColorFromRgba64(rgba, r, g, b, a, color); + pixelRow[x] = hasAssociatedAlpha + ? TiffUtilities.ColorFromRgba64Premultiplied(r, g, b, a) + : TPixel.FromRgba64(new(r, g, b, a)); } } } diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba24242424TiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba24242424TiffColor{TPixel}.cs index eba60679a2..a294693659 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba24242424TiffColor{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba24242424TiffColor{TPixel}.cs @@ -1,7 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using System.Numerics; using SixLabors.ImageSharp.Formats.Tiff.Utils; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; @@ -11,6 +10,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation; /// /// Implements the 'RGB' photometric interpretation with an alpha channel and with 24 bits for each channel. /// +/// The type of pixel format. internal class Rgba24242424TiffColor : TiffBaseColorDecoder where TPixel : unmanaged, IPixel { @@ -32,9 +32,6 @@ public Rgba24242424TiffColor(TiffExtraSampleType? extraSamplesType, bool isBigEn /// public override void Decode(ReadOnlySpan data, Buffer2D pixels, int left, int top, int width, int height) { - var color = default(TPixel); - color.FromScaledVector4(Vector4.Zero); - bool hasAssociatedAlpha = this.extraSamplesType.HasValue && this.extraSamplesType == TiffExtraSampleType.AssociatedAlphaData; int offset = 0; @@ -51,24 +48,24 @@ public override void Decode(ReadOnlySpan data, Buffer2D pixels, in for (int x = 0; x < pixelRow.Length; x++) { data.Slice(offset, 3).CopyTo(bufferSpan); - ulong r = TiffUtils.ConvertToUIntBigEndian(buffer); + uint r = TiffUtilities.ConvertToUIntBigEndian(buffer); offset += 3; data.Slice(offset, 3).CopyTo(bufferSpan); - ulong g = TiffUtils.ConvertToUIntBigEndian(buffer); + uint g = TiffUtilities.ConvertToUIntBigEndian(buffer); offset += 3; data.Slice(offset, 3).CopyTo(bufferSpan); - ulong b = TiffUtils.ConvertToUIntBigEndian(buffer); + uint b = TiffUtilities.ConvertToUIntBigEndian(buffer); offset += 3; data.Slice(offset, 3).CopyTo(bufferSpan); - ulong a = TiffUtils.ConvertToUIntBigEndian(buffer); + uint a = TiffUtilities.ConvertToUIntBigEndian(buffer); offset += 3; - pixelRow[x] = hasAssociatedAlpha ? - TiffUtils.ColorScaleTo24BitPremultiplied(r, g, b, a, color) : - TiffUtils.ColorScaleTo24Bit(r, g, b, a, color); + pixelRow[x] = hasAssociatedAlpha + ? TiffUtilities.ColorScaleTo24BitPremultiplied(r, g, b, a) + : TiffUtilities.ColorScaleTo24Bit(r, g, b, a); } } else @@ -76,24 +73,24 @@ public override void Decode(ReadOnlySpan data, Buffer2D pixels, in for (int x = 0; x < pixelRow.Length; x++) { data.Slice(offset, 3).CopyTo(bufferSpan); - ulong r = TiffUtils.ConvertToUIntLittleEndian(buffer); + uint r = TiffUtilities.ConvertToUIntLittleEndian(buffer); offset += 3; data.Slice(offset, 3).CopyTo(bufferSpan); - ulong g = TiffUtils.ConvertToUIntLittleEndian(buffer); + uint g = TiffUtilities.ConvertToUIntLittleEndian(buffer); offset += 3; data.Slice(offset, 3).CopyTo(bufferSpan); - ulong b = TiffUtils.ConvertToUIntLittleEndian(buffer); + uint b = TiffUtilities.ConvertToUIntLittleEndian(buffer); offset += 3; data.Slice(offset, 3).CopyTo(bufferSpan); - ulong a = TiffUtils.ConvertToUIntLittleEndian(buffer); + uint a = TiffUtilities.ConvertToUIntLittleEndian(buffer); offset += 3; - pixelRow[x] = hasAssociatedAlpha ? - TiffUtils.ColorScaleTo24BitPremultiplied(r, g, b, a, color) : - TiffUtils.ColorScaleTo24Bit(r, g, b, a, color); + pixelRow[x] = hasAssociatedAlpha + ? TiffUtilities.ColorScaleTo24BitPremultiplied(r, g, b, a) + : TiffUtilities.ColorScaleTo24Bit(r, g, b, a); } } } diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba24PlanarTiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba24PlanarTiffColor{TPixel}.cs index 1b842a79be..222e729867 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba24PlanarTiffColor{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba24PlanarTiffColor{TPixel}.cs @@ -2,7 +2,6 @@ // Licensed under the Six Labors Split License. using System.Buffers; -using System.Numerics; using SixLabors.ImageSharp.Formats.Tiff.Utils; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; @@ -12,6 +11,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation; /// /// Implements the 'RGB' photometric interpretation with an alpha channel and with 'Planar' layout for each color channel with 24 bit. /// +/// The type of pixel format. internal class Rgba24PlanarTiffColor : TiffBasePlanarColorDecoder where TPixel : unmanaged, IPixel { @@ -33,8 +33,6 @@ public Rgba24PlanarTiffColor(TiffExtraSampleType? extraSamplesType, bool isBigEn /// public override void Decode(IMemoryOwner[] data, Buffer2D pixels, int left, int top, int width, int height) { - var color = default(TPixel); - color.FromScaledVector4(Vector4.Zero); Span buffer = stackalloc byte[4]; int bufferStartIdx = this.isBigEndian ? 1 : 0; @@ -54,19 +52,19 @@ public override void Decode(IMemoryOwner[] data, Buffer2D pixels, for (int x = 0; x < pixelRow.Length; x++) { redData.Slice(offset, 3).CopyTo(bufferSpan); - ulong r = TiffUtils.ConvertToUIntBigEndian(buffer); + uint r = TiffUtilities.ConvertToUIntBigEndian(buffer); greenData.Slice(offset, 3).CopyTo(bufferSpan); - ulong g = TiffUtils.ConvertToUIntBigEndian(buffer); + uint g = TiffUtilities.ConvertToUIntBigEndian(buffer); blueData.Slice(offset, 3).CopyTo(bufferSpan); - ulong b = TiffUtils.ConvertToUIntBigEndian(buffer); + uint b = TiffUtilities.ConvertToUIntBigEndian(buffer); alphaData.Slice(offset, 3).CopyTo(bufferSpan); - ulong a = TiffUtils.ConvertToUIntBigEndian(buffer); + uint a = TiffUtilities.ConvertToUIntBigEndian(buffer); offset += 3; - pixelRow[x] = hasAssociatedAlpha ? - TiffUtils.ColorScaleTo24BitPremultiplied(r, g, b, a, color) : - TiffUtils.ColorScaleTo24Bit(r, g, b, a, color); + pixelRow[x] = hasAssociatedAlpha + ? TiffUtilities.ColorScaleTo24BitPremultiplied(r, g, b, a) + : TiffUtilities.ColorScaleTo24Bit(r, g, b, a); } } else @@ -74,19 +72,19 @@ public override void Decode(IMemoryOwner[] data, Buffer2D pixels, for (int x = 0; x < pixelRow.Length; x++) { redData.Slice(offset, 3).CopyTo(bufferSpan); - ulong r = TiffUtils.ConvertToUIntLittleEndian(buffer); + uint r = TiffUtilities.ConvertToUIntLittleEndian(buffer); greenData.Slice(offset, 3).CopyTo(bufferSpan); - ulong g = TiffUtils.ConvertToUIntLittleEndian(buffer); + uint g = TiffUtilities.ConvertToUIntLittleEndian(buffer); blueData.Slice(offset, 3).CopyTo(bufferSpan); - ulong b = TiffUtils.ConvertToUIntLittleEndian(buffer); + uint b = TiffUtilities.ConvertToUIntLittleEndian(buffer); alphaData.Slice(offset, 3).CopyTo(bufferSpan); - ulong a = TiffUtils.ConvertToUIntLittleEndian(buffer); + uint a = TiffUtilities.ConvertToUIntLittleEndian(buffer); offset += 3; - pixelRow[x] = hasAssociatedAlpha ? - TiffUtils.ColorScaleTo24BitPremultiplied(r, g, b, a, color) : - TiffUtils.ColorScaleTo24Bit(r, g, b, a, color); + pixelRow[x] = hasAssociatedAlpha + ? TiffUtilities.ColorScaleTo24BitPremultiplied(r, g, b, a) + : TiffUtilities.ColorScaleTo24Bit(r, g, b, a); } } } diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba32323232TiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba32323232TiffColor{TPixel}.cs index 2193f2e817..5c57221d98 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba32323232TiffColor{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba32323232TiffColor{TPixel}.cs @@ -1,7 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using System.Numerics; using SixLabors.ImageSharp.Formats.Tiff.Utils; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; @@ -11,6 +10,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation; /// /// Implements the 'RGB' photometric interpretation with an alpha channel and with 32 bits for each channel. /// +/// The type of pixel format. internal class Rgba32323232TiffColor : TiffBaseColorDecoder where TPixel : unmanaged, IPixel { @@ -32,9 +32,6 @@ public Rgba32323232TiffColor(TiffExtraSampleType? extraSamplesType, bool isBigEn /// public override void Decode(ReadOnlySpan data, Buffer2D pixels, int left, int top, int width, int height) { - var color = default(TPixel); - color.FromScaledVector4(Vector4.Zero); - bool hasAssociatedAlpha = this.extraSamplesType.HasValue && this.extraSamplesType == TiffExtraSampleType.AssociatedAlphaData; int offset = 0; @@ -46,42 +43,42 @@ public override void Decode(ReadOnlySpan data, Buffer2D pixels, in { for (int x = 0; x < pixelRow.Length; x++) { - ulong r = TiffUtils.ConvertToUIntBigEndian(data.Slice(offset, 4)); + uint r = TiffUtilities.ConvertToUIntBigEndian(data.Slice(offset, 4)); offset += 4; - ulong g = TiffUtils.ConvertToUIntBigEndian(data.Slice(offset, 4)); + uint g = TiffUtilities.ConvertToUIntBigEndian(data.Slice(offset, 4)); offset += 4; - ulong b = TiffUtils.ConvertToUIntBigEndian(data.Slice(offset, 4)); + uint b = TiffUtilities.ConvertToUIntBigEndian(data.Slice(offset, 4)); offset += 4; - ulong a = TiffUtils.ConvertToUIntBigEndian(data.Slice(offset, 4)); + uint a = TiffUtilities.ConvertToUIntBigEndian(data.Slice(offset, 4)); offset += 4; - pixelRow[x] = hasAssociatedAlpha ? - TiffUtils.ColorScaleTo32BitPremultiplied(r, g, b, a, color) : - TiffUtils.ColorScaleTo32Bit(r, g, b, a, color); + pixelRow[x] = hasAssociatedAlpha + ? TiffUtilities.ColorScaleTo32BitPremultiplied(r, g, b, a) + : TiffUtilities.ColorScaleTo32Bit(r, g, b, a); } } else { for (int x = 0; x < pixelRow.Length; x++) { - ulong r = TiffUtils.ConvertToUIntLittleEndian(data.Slice(offset, 4)); + uint r = TiffUtilities.ConvertToUIntLittleEndian(data.Slice(offset, 4)); offset += 4; - ulong g = TiffUtils.ConvertToUIntLittleEndian(data.Slice(offset, 4)); + uint g = TiffUtilities.ConvertToUIntLittleEndian(data.Slice(offset, 4)); offset += 4; - ulong b = TiffUtils.ConvertToUIntLittleEndian(data.Slice(offset, 4)); + uint b = TiffUtilities.ConvertToUIntLittleEndian(data.Slice(offset, 4)); offset += 4; - ulong a = TiffUtils.ConvertToUIntLittleEndian(data.Slice(offset, 4)); + uint a = TiffUtilities.ConvertToUIntLittleEndian(data.Slice(offset, 4)); offset += 4; - pixelRow[x] = hasAssociatedAlpha ? - TiffUtils.ColorScaleTo32BitPremultiplied(r, g, b, a, color) : - TiffUtils.ColorScaleTo32Bit(r, g, b, a, color); + pixelRow[x] = hasAssociatedAlpha + ? TiffUtilities.ColorScaleTo32BitPremultiplied(r, g, b, a) + : TiffUtilities.ColorScaleTo32Bit(r, g, b, a); } } } diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba32PlanarTiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba32PlanarTiffColor{TPixel}.cs index 7d047cf7fd..8f90907418 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba32PlanarTiffColor{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba32PlanarTiffColor{TPixel}.cs @@ -2,7 +2,6 @@ // Licensed under the Six Labors Split License. using System.Buffers; -using System.Numerics; using SixLabors.ImageSharp.Formats.Tiff.Utils; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; @@ -12,11 +11,11 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation; /// /// Implements the 'RGB' photometric interpretation with an alpha channel and a 'Planar' layout for each color channel with 32 bit. /// +/// The type of pixel format. internal class Rgba32PlanarTiffColor : TiffBasePlanarColorDecoder where TPixel : unmanaged, IPixel { private readonly bool isBigEndian; - private readonly TiffExtraSampleType? extraSamplesType; /// @@ -33,9 +32,6 @@ public Rgba32PlanarTiffColor(TiffExtraSampleType? extraSamplesType, bool isBigEn /// public override void Decode(IMemoryOwner[] data, Buffer2D pixels, int left, int top, int width, int height) { - var color = default(TPixel); - color.FromScaledVector4(Vector4.Zero); - Span redData = data[0].GetSpan(); Span greenData = data[1].GetSpan(); Span blueData = data[2].GetSpan(); @@ -50,32 +46,32 @@ public override void Decode(IMemoryOwner[] data, Buffer2D pixels, { for (int x = 0; x < pixelRow.Length; x++) { - ulong r = TiffUtils.ConvertToUIntBigEndian(redData.Slice(offset, 4)); - ulong g = TiffUtils.ConvertToUIntBigEndian(greenData.Slice(offset, 4)); - ulong b = TiffUtils.ConvertToUIntBigEndian(blueData.Slice(offset, 4)); - ulong a = TiffUtils.ConvertToUIntBigEndian(alphaData.Slice(offset, 4)); + uint r = TiffUtilities.ConvertToUIntBigEndian(redData.Slice(offset, 4)); + uint g = TiffUtilities.ConvertToUIntBigEndian(greenData.Slice(offset, 4)); + uint b = TiffUtilities.ConvertToUIntBigEndian(blueData.Slice(offset, 4)); + uint a = TiffUtilities.ConvertToUIntBigEndian(alphaData.Slice(offset, 4)); offset += 4; - pixelRow[x] = hasAssociatedAlpha ? - TiffUtils.ColorScaleTo32BitPremultiplied(r, g, b, a, color) : - TiffUtils.ColorScaleTo32Bit(r, g, b, a, color); + pixelRow[x] = hasAssociatedAlpha + ? TiffUtilities.ColorScaleTo32BitPremultiplied(r, g, b, a) + : TiffUtilities.ColorScaleTo32Bit(r, g, b, a); } } else { for (int x = 0; x < pixelRow.Length; x++) { - ulong r = TiffUtils.ConvertToUIntLittleEndian(redData.Slice(offset, 4)); - ulong g = TiffUtils.ConvertToUIntLittleEndian(greenData.Slice(offset, 4)); - ulong b = TiffUtils.ConvertToUIntLittleEndian(blueData.Slice(offset, 4)); - ulong a = TiffUtils.ConvertToUIntLittleEndian(alphaData.Slice(offset, 4)); + uint r = TiffUtilities.ConvertToUIntLittleEndian(redData.Slice(offset, 4)); + uint g = TiffUtilities.ConvertToUIntLittleEndian(greenData.Slice(offset, 4)); + uint b = TiffUtilities.ConvertToUIntLittleEndian(blueData.Slice(offset, 4)); + uint a = TiffUtilities.ConvertToUIntLittleEndian(alphaData.Slice(offset, 4)); offset += 4; - pixelRow[x] = hasAssociatedAlpha ? - TiffUtils.ColorScaleTo32BitPremultiplied(r, g, b, a, color) : - TiffUtils.ColorScaleTo32Bit(r, g, b, a, color); + pixelRow[x] = hasAssociatedAlpha + ? TiffUtilities.ColorScaleTo32BitPremultiplied(r, g, b, a) + : TiffUtilities.ColorScaleTo32Bit(r, g, b, a); } } } diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba8888TiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba8888TiffColor{TPixel}.cs index dc1fbb8717..26ffbbab9b 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba8888TiffColor{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba8888TiffColor{TPixel}.cs @@ -12,6 +12,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation; /// /// Implements the 'RGB' photometric interpretation with an alpha channel and 8 bits per channel. /// +/// The type of pixel format. internal class Rgba8888TiffColor : TiffBaseColorDecoder where TPixel : unmanaged, IPixel { @@ -34,10 +35,8 @@ public override void Decode(ReadOnlySpan data, Buffer2D pixels, in int offset = 0; bool hasAssociatedAlpha = this.extraSamplesType.HasValue && this.extraSamplesType == TiffExtraSampleType.AssociatedAlphaData; - var color = default(TPixel); - color.FromScaledVector4(Vector4.Zero); using IMemoryOwner vectors = hasAssociatedAlpha ? this.memoryAllocator.Allocate(width) : null; - Span vectorsSpan = hasAssociatedAlpha ? vectors.GetSpan() : Span.Empty; + Span vectorsSpan = hasAssociatedAlpha ? vectors.GetSpan() : []; for (int y = top; y < top + height; y++) { Span pixelRow = pixels.DangerousGetRowSpan(y).Slice(left, width); diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbaFloat32323232TiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbaFloat32323232TiffColor{TPixel}.cs index 743502d56e..12f1b75b40 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbaFloat32323232TiffColor{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbaFloat32323232TiffColor{TPixel}.cs @@ -1,7 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using System.Numerics; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; @@ -10,6 +9,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation; /// /// Implements the 'RGB' photometric interpretation with an alpha channel and with 32 bits for each channel. /// +/// The type of pixel format. internal class RgbaFloat32323232TiffColor : TiffBaseColorDecoder where TPixel : unmanaged, IPixel { @@ -24,8 +24,6 @@ internal class RgbaFloat32323232TiffColor : TiffBaseColorDecoder /// public override void Decode(ReadOnlySpan data, Buffer2D pixels, int left, int top, int width, int height) { - var color = default(TPixel); - color.FromScaledVector4(Vector4.Zero); int offset = 0; Span buffer = stackalloc byte[4]; @@ -57,9 +55,7 @@ public override void Decode(ReadOnlySpan data, Buffer2D pixels, in float a = BitConverter.ToSingle(buffer); offset += 4; - var colorVector = new Vector4(r, g, b, a); - color.FromScaledVector4(colorVector); - pixelRow[x] = color; + pixelRow[x] = TPixel.FromScaledVector4(new(r, g, b, a)); } } else @@ -78,9 +74,7 @@ public override void Decode(ReadOnlySpan data, Buffer2D pixels, in float a = BitConverter.ToSingle(data.Slice(offset, 4)); offset += 4; - var colorVector = new Vector4(r, g, b, a); - color.FromScaledVector4(colorVector); - pixelRow[x] = color; + pixelRow[x] = TPixel.FromScaledVector4(new(r, g, b, a)); } } } diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbaPlanarTiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbaPlanarTiffColor{TPixel}.cs index 63aa64d867..7a599a06a7 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbaPlanarTiffColor{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbaPlanarTiffColor{TPixel}.cs @@ -12,6 +12,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation; /// /// Implements the 'RGB' photometric interpretation with an alpha channel and with 'Planar' layout (for all bit depths). /// +/// The type of pixel format. internal class RgbaPlanarTiffColor : TiffBasePlanarColorDecoder where TPixel : unmanaged, IPixel { @@ -59,13 +60,12 @@ public RgbaPlanarTiffColor(TiffExtraSampleType? extraSampleType, TiffBitsPerSamp /// The height of the image block. public override void Decode(IMemoryOwner[] data, Buffer2D pixels, int left, int top, int width, int height) { - var color = default(TPixel); bool hasAssociatedAlpha = this.extraSampleType.HasValue && this.extraSampleType == TiffExtraSampleType.AssociatedAlphaData; - var rBitReader = new BitReader(data[0].GetSpan()); - var gBitReader = new BitReader(data[1].GetSpan()); - var bBitReader = new BitReader(data[2].GetSpan()); - var aBitReader = new BitReader(data[3].GetSpan()); + BitReader rBitReader = new(data[0].GetSpan()); + BitReader gBitReader = new(data[1].GetSpan()); + BitReader bBitReader = new(data[2].GetSpan()); + BitReader aBitReader = new(data[3].GetSpan()); for (int y = top; y < top + height; y++) { @@ -77,17 +77,15 @@ public override void Decode(IMemoryOwner[] data, Buffer2D pixels, float b = bBitReader.ReadBits(this.bitsPerSampleB) / this.bFactor; float a = aBitReader.ReadBits(this.bitsPerSampleA) / this.aFactor; - var vec = new Vector4(r, g, b, a); + Vector4 vector = new(r, g, b, a); if (hasAssociatedAlpha) { - color = TiffUtils.UnPremultiply(ref vec, color); + pixelRow[x] = TiffUtilities.UnPremultiply(ref vector); } else { - color.FromScaledVector4(vec); + pixelRow[x] = TPixel.FromScaledVector4(vector); } - - pixelRow[x] = color; } rBitReader.NextRow(); diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbaTiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbaTiffColor{TPixel}.cs index 0ea8a87fcc..68b59c95a4 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbaTiffColor{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbaTiffColor{TPixel}.cs @@ -11,6 +11,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation; /// /// Implements the 'RGB' photometric interpretation with alpha channel (for all bit depths). /// +/// The type of pixel format. internal class RgbaTiffColor : TiffBaseColorDecoder where TPixel : unmanaged, IPixel { @@ -50,9 +51,7 @@ public RgbaTiffColor(TiffExtraSampleType? extraSampleType, TiffBitsPerSample bit /// public override void Decode(ReadOnlySpan data, Buffer2D pixels, int left, int top, int width, int height) { - var color = default(TPixel); - - var bitReader = new BitReader(data); + BitReader bitReader = new(data); bool hasAssociatedAlpha = this.extraSamplesType.HasValue && this.extraSamplesType == TiffExtraSampleType.AssociatedAlphaData; @@ -66,15 +65,14 @@ public override void Decode(ReadOnlySpan data, Buffer2D pixels, in float b = bitReader.ReadBits(this.bitsPerSampleB) / this.bFactor; float a = bitReader.ReadBits(this.bitsPerSampleB) / this.aFactor; - var vec = new Vector4(r, g, b, a); + Vector4 vector = new(r, g, b, a); if (hasAssociatedAlpha) { - pixelRow[x] = TiffUtils.UnPremultiply(ref vec, color); + pixelRow[x] = TiffUtilities.UnPremultiply(ref vector); } else { - color.FromScaledVector4(vec); - pixelRow[x] = color; + pixelRow[x] = TPixel.FromScaledVector4(vector); } } diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero16TiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero16TiffColor{TPixel}.cs index f7fd55e523..6f1672e1b9 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero16TiffColor{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero16TiffColor{TPixel}.cs @@ -1,7 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using System.Numerics; using SixLabors.ImageSharp.Formats.Tiff.Utils; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; @@ -11,6 +10,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation; /// /// Implements the 'WhiteIsZero' photometric interpretation for 16-bit grayscale images. /// +/// The type of pixel format. internal class WhiteIsZero16TiffColor : TiffBaseColorDecoder where TPixel : unmanaged, IPixel { @@ -25,10 +25,6 @@ internal class WhiteIsZero16TiffColor : TiffBaseColorDecoder /// public override void Decode(ReadOnlySpan data, Buffer2D pixels, int left, int top, int width, int height) { - L16 l16 = TiffUtils.L16Default; - var color = default(TPixel); - color.FromScaledVector4(Vector4.Zero); - int offset = 0; for (int y = top; y < top + height; y++) { @@ -37,20 +33,20 @@ public override void Decode(ReadOnlySpan data, Buffer2D pixels, in { for (int x = 0; x < pixelRow.Length; x++) { - ushort intensity = (ushort)(ushort.MaxValue - TiffUtils.ConvertToUShortBigEndian(data.Slice(offset, 2))); + ushort intensity = (ushort)(ushort.MaxValue - TiffUtilities.ConvertToUShortBigEndian(data.Slice(offset, 2))); offset += 2; - pixelRow[x] = TiffUtils.ColorFromL16(l16, intensity, color); + pixelRow[x] = TPixel.FromL16(new(intensity)); } } else { for (int x = 0; x < pixelRow.Length; x++) { - ushort intensity = (ushort)(ushort.MaxValue - TiffUtils.ConvertToUShortLittleEndian(data.Slice(offset, 2))); + ushort intensity = (ushort)(ushort.MaxValue - TiffUtilities.ConvertToUShortLittleEndian(data.Slice(offset, 2))); offset += 2; - pixelRow[x] = TiffUtils.ColorFromL16(l16, intensity, color); + pixelRow[x] = TPixel.FromL16(new(intensity)); } } } diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero1TiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero1TiffColor{TPixel}.cs index c5b662979e..1de9c295bb 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero1TiffColor{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero1TiffColor{TPixel}.cs @@ -11,6 +11,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation; /// /// Implements the 'WhiteIsZero' photometric interpretation (optimized for bilevel images). /// +/// The type of pixel format. internal class WhiteIsZero1TiffColor : TiffBaseColorDecoder where TPixel : unmanaged, IPixel { @@ -18,11 +19,9 @@ internal class WhiteIsZero1TiffColor : TiffBaseColorDecoder public override void Decode(ReadOnlySpan data, Buffer2D pixels, int left, int top, int width, int height) { nuint offset = 0; - var colorBlack = default(TPixel); - var colorWhite = default(TPixel); + TPixel colorBlack = TPixel.FromRgba32(Color.Black.ToPixel()); + TPixel colorWhite = TPixel.FromRgba32(Color.White.ToPixel()); - colorBlack.FromRgba32(Color.Black); - colorWhite.FromRgba32(Color.White); ref byte dataRef = ref MemoryMarshal.GetReference(data); for (nuint y = (uint)top; y < (uint)(top + height); y++) { diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero24TiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero24TiffColor{TPixel}.cs index 59e0df87d2..94549d663d 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero24TiffColor{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero24TiffColor{TPixel}.cs @@ -1,7 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using System.Numerics; using SixLabors.ImageSharp.Formats.Tiff.Utils; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; @@ -11,6 +10,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation; /// /// Implements the 'WhiteIsZero' photometric interpretation for 24-bit grayscale images. /// +/// The type of pixel format. internal class WhiteIsZero24TiffColor : TiffBaseColorDecoder where TPixel : unmanaged, IPixel { @@ -25,8 +25,6 @@ internal class WhiteIsZero24TiffColor : TiffBaseColorDecoder /// public override void Decode(ReadOnlySpan data, Buffer2D pixels, int left, int top, int width, int height) { - var color = default(TPixel); - color.FromScaledVector4(Vector4.Zero); Span buffer = stackalloc byte[4]; int bufferStartIdx = this.isBigEndian ? 1 : 0; const uint maxValue = 0xFFFFFF; @@ -41,10 +39,10 @@ public override void Decode(ReadOnlySpan data, Buffer2D pixels, in for (int x = 0; x < pixelRow.Length; x++) { data.Slice(offset, 3).CopyTo(bufferSpan); - ulong intensity = maxValue - TiffUtils.ConvertToUIntBigEndian(buffer); + uint intensity = maxValue - TiffUtilities.ConvertToUIntBigEndian(buffer); offset += 3; - pixelRow[x] = TiffUtils.ColorScaleTo24Bit(intensity, color); + pixelRow[x] = TiffUtilities.ColorScaleTo24Bit(intensity); } } else @@ -52,10 +50,10 @@ public override void Decode(ReadOnlySpan data, Buffer2D pixels, in for (int x = 0; x < pixelRow.Length; x++) { data.Slice(offset, 3).CopyTo(bufferSpan); - ulong intensity = maxValue - TiffUtils.ConvertToUIntLittleEndian(buffer); + uint intensity = maxValue - TiffUtilities.ConvertToUIntLittleEndian(buffer); offset += 3; - pixelRow[x] = TiffUtils.ColorScaleTo24Bit(intensity, color); + pixelRow[x] = TiffUtilities.ColorScaleTo24Bit(intensity); } } } diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero32FloatTiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero32FloatTiffColor{TPixel}.cs index f3207b2f45..7d31f23abd 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero32FloatTiffColor{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero32FloatTiffColor{TPixel}.cs @@ -10,6 +10,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation; /// /// Implements the 'WhiteIsZero' photometric interpretation for 32-bit float grayscale images. /// +/// The type of pixel format. internal class WhiteIsZero32FloatTiffColor : TiffBaseColorDecoder where TPixel : unmanaged, IPixel { @@ -24,8 +25,6 @@ internal class WhiteIsZero32FloatTiffColor : TiffBaseColorDecoder public override void Decode(ReadOnlySpan data, Buffer2D pixels, int left, int top, int width, int height) { - var color = default(TPixel); - color.FromScaledVector4(Vector4.Zero); Span buffer = stackalloc byte[4]; int offset = 0; @@ -41,9 +40,7 @@ public override void Decode(ReadOnlySpan data, Buffer2D pixels, in float intensity = 1.0f - BitConverter.ToSingle(buffer); offset += 4; - var colorVector = new Vector4(intensity, intensity, intensity, 1.0f); - color.FromScaledVector4(colorVector); - pixelRow[x] = color; + pixelRow[x] = TPixel.FromScaledVector4(new(intensity, intensity, intensity, 1f)); } } else @@ -53,9 +50,7 @@ public override void Decode(ReadOnlySpan data, Buffer2D pixels, in float intensity = 1.0f - BitConverter.ToSingle(data.Slice(offset, 4)); offset += 4; - var colorVector = new Vector4(intensity, intensity, intensity, 1.0f); - color.FromScaledVector4(colorVector); - pixelRow[x] = color; + pixelRow[x] = TPixel.FromScaledVector4(new Vector4(intensity, intensity, intensity, 1.0f)); } } } diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero32TiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero32TiffColor{TPixel}.cs index 558779a147..5a9aba836c 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero32TiffColor{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero32TiffColor{TPixel}.cs @@ -1,7 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using System.Numerics; using SixLabors.ImageSharp.Formats.Tiff.Utils; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; @@ -11,6 +10,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation; /// /// Implements the 'WhiteIsZero' photometric interpretation for 32-bit grayscale images. /// +/// The type of pixel format. internal class WhiteIsZero32TiffColor : TiffBaseColorDecoder where TPixel : unmanaged, IPixel { @@ -25,8 +25,6 @@ internal class WhiteIsZero32TiffColor : TiffBaseColorDecoder /// public override void Decode(ReadOnlySpan data, Buffer2D pixels, int left, int top, int width, int height) { - var color = default(TPixel); - color.FromScaledVector4(Vector4.Zero); const uint maxValue = 0xFFFFFFFF; int offset = 0; @@ -37,20 +35,20 @@ public override void Decode(ReadOnlySpan data, Buffer2D pixels, in { for (int x = 0; x < pixelRow.Length; x++) { - ulong intensity = maxValue - TiffUtils.ConvertToUIntBigEndian(data.Slice(offset, 4)); + uint intensity = maxValue - TiffUtilities.ConvertToUIntBigEndian(data.Slice(offset, 4)); offset += 4; - pixelRow[x] = TiffUtils.ColorScaleTo32Bit(intensity, color); + pixelRow[x] = TiffUtilities.ColorScaleTo32Bit(intensity); } } else { for (int x = 0; x < pixelRow.Length; x++) { - ulong intensity = maxValue - TiffUtils.ConvertToUIntLittleEndian(data.Slice(offset, 4)); + uint intensity = maxValue - TiffUtilities.ConvertToUIntLittleEndian(data.Slice(offset, 4)); offset += 4; - pixelRow[x] = TiffUtils.ColorScaleTo32Bit(intensity, color); + pixelRow[x] = TiffUtilities.ColorScaleTo32Bit(intensity); } } } diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero4TiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero4TiffColor{TPixel}.cs index bc5e2fb645..7dcbe23c5f 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero4TiffColor{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero4TiffColor{TPixel}.cs @@ -9,47 +9,30 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation; /// /// Implements the 'WhiteIsZero' photometric interpretation (optimized for 4-bit grayscale images). /// +/// The type of pixel format. internal class WhiteIsZero4TiffColor : TiffBaseColorDecoder where TPixel : unmanaged, IPixel { /// public override void Decode(ReadOnlySpan data, Buffer2D pixels, int left, int top, int width, int height) { - var color = default(TPixel); - int offset = 0; bool isOddWidth = (width & 1) == 1; - var l8 = default(L8); for (int y = top; y < top + height; y++) { Span pixelRowSpan = pixels.DangerousGetRowSpan(y); for (int x = left; x < left + width - 1;) { byte byteData = data[offset++]; - - byte intensity1 = (byte)((15 - ((byteData & 0xF0) >> 4)) * 17); - l8.PackedValue = intensity1; - color.FromL8(l8); - - pixelRowSpan[x++] = color; - - byte intensity2 = (byte)((15 - (byteData & 0x0F)) * 17); - l8.PackedValue = intensity2; - color.FromL8(l8); - - pixelRowSpan[x++] = color; + pixelRowSpan[x++] = TPixel.FromL8(new((byte)((15 - ((byteData & 0xF0) >> 4)) * 17))); + pixelRowSpan[x++] = TPixel.FromL8(new((byte)((15 - (byteData & 0x0F)) * 17))); } if (isOddWidth) { byte byteData = data[offset++]; - - byte intensity1 = (byte)((15 - ((byteData & 0xF0) >> 4)) * 17); - l8.PackedValue = intensity1; - color.FromL8(l8); - - pixelRowSpan[left + width - 1] = color; + pixelRowSpan[left + width - 1] = TPixel.FromL8(new((byte)((15 - ((byteData & 0xF0) >> 4)) * 17))); } } } diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero8TiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero8TiffColor{TPixel}.cs index fb2653543b..5429dbd3b0 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero8TiffColor{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero8TiffColor{TPixel}.cs @@ -1,7 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.Formats.Tiff.Utils; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; @@ -10,24 +9,21 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation; /// /// Implements the 'WhiteIsZero' photometric interpretation (optimized for 8-bit grayscale images). /// +/// The type of pixel format. internal class WhiteIsZero8TiffColor : TiffBaseColorDecoder where TPixel : unmanaged, IPixel { /// public override void Decode(ReadOnlySpan data, Buffer2D pixels, int left, int top, int width, int height) { - var color = default(TPixel); - int offset = 0; - - var l8 = default(L8); for (int y = top; y < top + height; y++) { Span pixelRow = pixels.DangerousGetRowSpan(y).Slice(left, width); for (int x = 0; x < pixelRow.Length; x++) { byte intensity = (byte)(byte.MaxValue - data[offset++]); - pixelRow[x] = TiffUtils.ColorFromL8(l8, intensity, color); + pixelRow[x] = TPixel.FromL8(new(intensity)); } } } diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZeroTiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZeroTiffColor{TPixel}.cs index b38868a0e4..0cd01a6199 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZeroTiffColor{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZeroTiffColor{TPixel}.cs @@ -11,11 +11,11 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation; /// /// Implements the 'WhiteIsZero' photometric interpretation (for all bit depths). /// +/// The type of pixel format. internal class WhiteIsZeroTiffColor : TiffBaseColorDecoder where TPixel : unmanaged, IPixel { private readonly ushort bitsPerSample0; - private readonly float factor; public WhiteIsZeroTiffColor(TiffBitsPerSample bitsPerSample) @@ -27,9 +27,7 @@ public WhiteIsZeroTiffColor(TiffBitsPerSample bitsPerSample) /// public override void Decode(ReadOnlySpan data, Buffer2D pixels, int left, int top, int width, int height) { - var color = default(TPixel); - - var bitReader = new BitReader(data); + BitReader bitReader = new(data); for (int y = top; y < top + height; y++) { @@ -37,10 +35,8 @@ public override void Decode(ReadOnlySpan data, Buffer2D pixels, in for (int x = 0; x < pixelRow.Length; x++) { int value = bitReader.ReadBits(this.bitsPerSample0); - float intensity = 1.0f - (value / this.factor); - - color.FromScaledVector4(new Vector4(intensity, intensity, intensity, 1.0f)); - pixelRow[x] = color; + float intensity = 1f - (value / this.factor); + pixelRow[x] = TPixel.FromScaledVector4(new Vector4(intensity, intensity, intensity, 1f)); } bitReader.NextRow(); diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/YCbCrPlanarTiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/YCbCrPlanarTiffColor{TPixel}.cs index 791bfa438a..768177bfc0 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/YCbCrPlanarTiffColor{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/YCbCrPlanarTiffColor{TPixel}.cs @@ -11,11 +11,11 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation; /// /// Implements decoding pixel data with photometric interpretation of type 'YCbCr' with the planar configuration. /// +/// The type of pixel format. internal class YCbCrPlanarTiffColor : TiffBasePlanarColorDecoder where TPixel : unmanaged, IPixel { private readonly YCbCrConverter converter; - private readonly ushort[] ycbcrSubSampling; public YCbCrPlanarTiffColor(Rational[] referenceBlackAndWhite, Rational[] coefficients, ushort[] ycbcrSubSampling) @@ -36,13 +36,12 @@ public override void Decode(IMemoryOwner[] data, Buffer2D pixels, ReverseChromaSubSampling(width, height, this.ycbcrSubSampling[0], this.ycbcrSubSampling[1], cbData, crData); } - var color = default(TPixel); int offset = 0; int widthPadding = 0; if (this.ycbcrSubSampling != null) { // Round to the next integer multiple of horizontalSubSampling. - widthPadding = TiffUtils.PaddingToNextInteger(width, this.ycbcrSubSampling[0]); + widthPadding = TiffUtilities.PaddingToNextInteger(width, this.ycbcrSubSampling[0]); } for (int y = top; y < top + height; y++) @@ -51,8 +50,7 @@ public override void Decode(IMemoryOwner[] data, Buffer2D pixels, for (int x = 0; x < pixelRow.Length; x++) { Rgba32 rgba = this.converter.ConvertToRgba32(yData[offset], cbData[offset], crData[offset]); - color.FromRgba32(rgba); - pixelRow[x] = color; + pixelRow[x] = TPixel.FromRgba32(rgba); offset++; } @@ -64,8 +62,8 @@ private static void ReverseChromaSubSampling(int width, int height, int horizont { // If width and height are not multiples of ChromaSubsampleHoriz and ChromaSubsampleVert respectively, // then the source data will be padded. - width += TiffUtils.PaddingToNextInteger(width, horizontalSubSampling); - height += TiffUtils.PaddingToNextInteger(height, verticalSubSampling); + width += TiffUtilities.PaddingToNextInteger(width, horizontalSubSampling); + height += TiffUtilities.PaddingToNextInteger(height, verticalSubSampling); for (int row = height - 1; row >= 0; row--) { diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/YCbCrTiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/YCbCrTiffColor{TPixel}.cs index 2e47698a67..5a13890356 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/YCbCrTiffColor{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/YCbCrTiffColor{TPixel}.cs @@ -11,6 +11,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation; /// /// Implements decoding pixel data with photometric interpretation of type 'YCbCr'. /// +/// The type of pixel format. internal class YCbCrTiffColor : TiffBaseColorDecoder where TPixel : unmanaged, IPixel { @@ -50,13 +51,12 @@ public override void Decode(ReadOnlySpan data, Buffer2D pixels, in private void DecodeYCbCrData(Buffer2D pixels, int left, int top, int width, int height, ReadOnlySpan ycbcrData) { - var color = default(TPixel); int offset = 0; int widthPadding = 0; if (this.ycbcrSubSampling != null) { // Round to the next integer multiple of horizontalSubSampling. - widthPadding = TiffUtils.PaddingToNextInteger(width, this.ycbcrSubSampling[0]); + widthPadding = TiffUtilities.PaddingToNextInteger(width, this.ycbcrSubSampling[0]); } for (int y = top; y < top + height; y++) @@ -65,8 +65,7 @@ private void DecodeYCbCrData(Buffer2D pixels, int left, int top, int wid for (int x = 0; x < pixelRow.Length; x++) { Rgba32 rgba = this.converter.ConvertToRgba32(ycbcrData[offset], ycbcrData[offset + 1], ycbcrData[offset + 2]); - color.FromRgba32(rgba); - pixelRow[x] = color; + pixelRow[x] = TPixel.FromRgba32(rgba); offset += 3; } @@ -78,8 +77,8 @@ private static void ReverseChromaSubSampling(int width, int height, int horizont { // If width and height are not multiples of ChromaSubsampleHoriz and ChromaSubsampleVert respectively, // then the source data will be padded. - width += TiffUtils.PaddingToNextInteger(width, horizontalSubSampling); - height += TiffUtils.PaddingToNextInteger(height, verticalSubSampling); + width += TiffUtilities.PaddingToNextInteger(width, horizontalSubSampling); + height += TiffUtilities.PaddingToNextInteger(height, verticalSubSampling); int blockWidth = width / horizontalSubSampling; int blockHeight = height / verticalSubSampling; int cbCrOffsetInBlock = horizontalSubSampling * verticalSubSampling; diff --git a/src/ImageSharp/Formats/Tiff/TiffBitsPerSample.cs b/src/ImageSharp/Formats/Tiff/TiffBitsPerSample.cs index 382faa3874..2bfd9a626f 100644 --- a/src/ImageSharp/Formats/Tiff/TiffBitsPerSample.cs +++ b/src/ImageSharp/Formats/Tiff/TiffBitsPerSample.cs @@ -147,20 +147,20 @@ public ushort[] ToArray() { if (this.Channel1 == 0) { - return new[] { this.Channel0 }; + return [this.Channel0]; } if (this.Channel2 == 0) { - return new[] { this.Channel0, this.Channel1 }; + return [this.Channel0, this.Channel1]; } if (this.Channel3 == 0) { - return new[] { this.Channel0, this.Channel1, this.Channel2 }; + return [this.Channel0, this.Channel1, this.Channel2]; } - return new[] { this.Channel0, this.Channel1, this.Channel2, this.Channel3 }; + return [this.Channel0, this.Channel1, this.Channel2, this.Channel3]; } /// diff --git a/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs b/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs index 96e6d2a89d..2356d45e47 100644 --- a/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs +++ b/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs @@ -156,8 +156,8 @@ public TiffDecoderCore(DecoderOptions options) /// protected override Image Decode(BufferedReadStream stream, CancellationToken cancellationToken) { - List> frames = new(); - List framesMetadata = new(); + List> frames = []; + List framesMetadata = []; try { this.inputStream = stream; @@ -214,7 +214,7 @@ protected override ImageInfo Identify(BufferedReadStream stream, CancellationTok DirectoryReader reader = new(stream, this.configuration.MemoryAllocator); IList directories = reader.Read(); - List framesMetadata = new(); + List framesMetadata = []; foreach (ExifProfile dir in directories) { framesMetadata.Add(this.CreateFrameMetadata(dir)); @@ -227,7 +227,7 @@ protected override ImageInfo Identify(BufferedReadStream stream, CancellationTok int width = GetImageWidth(rootFrameExifProfile); int height = GetImageHeight(rootFrameExifProfile); - return new ImageInfo(new PixelTypeInfo((int)framesMetadata[0].GetTiffMetadata().BitsPerPixel), new(width, height), metadata, framesMetadata); + return new ImageInfo(new(width, height), metadata, framesMetadata); } /// diff --git a/src/ImageSharp/Formats/Tiff/TiffDecoderMetadataCreator.cs b/src/ImageSharp/Formats/Tiff/TiffDecoderMetadataCreator.cs index 1ef2478e3d..28565cac47 100644 --- a/src/ImageSharp/Formats/Tiff/TiffDecoderMetadataCreator.cs +++ b/src/ImageSharp/Formats/Tiff/TiffDecoderMetadataCreator.cs @@ -23,7 +23,7 @@ public static ImageMetadata Create(List frames, bool ignoreM TiffThrowHelper.ThrowImageFormatException("Expected at least one frame."); } - ImageMetadata imageMetaData = Create(byteOrder, isBigTiff, frames[0].ExifProfile); + ImageMetadata imageMetaData = Create(byteOrder, isBigTiff, frames[0]); if (!ignoreMetadata) { @@ -50,14 +50,22 @@ public static ImageMetadata Create(List frames, bool ignoreM return imageMetaData; } - private static ImageMetadata Create(ByteOrder byteOrder, bool isBigTiff, ExifProfile exifProfile) + private static ImageMetadata Create(ByteOrder byteOrder, bool isBigTiff, ImageFrameMetadata rootFrameMetadata) { ImageMetadata imageMetaData = new(); - SetResolution(imageMetaData, exifProfile); + SetResolution(imageMetaData, rootFrameMetadata.ExifProfile); TiffMetadata tiffMetadata = imageMetaData.GetTiffMetadata(); tiffMetadata.ByteOrder = byteOrder; tiffMetadata.FormatType = isBigTiff ? TiffFormatType.BigTIFF : TiffFormatType.Default; + + TiffFrameMetadata tiffFrameMetadata = rootFrameMetadata.GetTiffMetadata(); + tiffMetadata.BitsPerPixel = tiffFrameMetadata.BitsPerPixel; + tiffMetadata.BitsPerSample = tiffFrameMetadata.BitsPerSample; + tiffMetadata.Compression = tiffFrameMetadata.Compression; + tiffMetadata.PhotometricInterpretation = tiffFrameMetadata.PhotometricInterpretation; + tiffMetadata.Predictor = tiffFrameMetadata.Predictor; + return imageMetaData; } @@ -109,7 +117,7 @@ private static bool TryGetIptc(IReadOnlyList exifValues, out byte[] return false; } - // Probably wrong endianess, swap byte order. + // Probably wrong endianness, swap byte order. Span iptcBytesSpan = iptcBytes.AsSpan(); Span buffer = stackalloc byte[4]; for (int i = 0; i < iptcBytes.Length; i += 4) diff --git a/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs b/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs index 5a5c2b3e51..ed91755468 100644 --- a/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs +++ b/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs @@ -63,7 +63,7 @@ public static bool VerifyAndParse(this TiffDecoderCore options, ExifProfile exif } TiffSampleFormat? sampleFormat = null; - if (exifProfile.TryGetValue(ExifTag.SampleFormat, out var formatValue)) + if (exifProfile.TryGetValue(ExifTag.SampleFormat, out IExifValue formatValue)) { TiffSampleFormat[] sampleFormats = formatValue.Value.Select(a => (TiffSampleFormat)a).ToArray(); sampleFormat = sampleFormats[0]; @@ -106,11 +106,11 @@ public static bool VerifyAndParse(this TiffDecoderCore options, ExifProfile exif options.PlanarConfiguration = DefaultPlanarConfiguration; } - options.Predictor = frameMetadata.Predictor ?? TiffPredictor.None; - options.PhotometricInterpretation = frameMetadata.PhotometricInterpretation ?? TiffPhotometricInterpretation.Rgb; + options.Predictor = frameMetadata.Predictor; + options.PhotometricInterpretation = frameMetadata.PhotometricInterpretation; options.SampleFormat = sampleFormat ?? TiffSampleFormat.UnsignedInteger; - options.BitsPerPixel = frameMetadata.BitsPerPixel != null ? (int)frameMetadata.BitsPerPixel.Value : (int)TiffBitsPerPixel.Bit24; - options.BitsPerSample = frameMetadata.BitsPerSample ?? new TiffBitsPerSample(0, 0, 0); + options.BitsPerPixel = (int)frameMetadata.BitsPerPixel; + options.BitsPerSample = frameMetadata.BitsPerSample; if (exifProfile.TryGetValue(ExifTag.ReferenceBlackWhite, out IExifValue blackWhiteValue)) { @@ -142,9 +142,7 @@ public static bool VerifyAndParse(this TiffDecoderCore options, ExifProfile exif options.ParseCompression(frameMetadata.Compression, exifProfile); options.ParseColorType(exifProfile); - bool isTiled = VerifyRequiredFieldsArePresent(exifProfile, frameMetadata, options.PlanarConfiguration); - - return isTiled; + return VerifyRequiredFieldsArePresent(exifProfile, frameMetadata, options.PlanarConfiguration); } /// @@ -194,13 +192,6 @@ private static bool VerifyRequiredFieldsArePresent(ExifProfile exifProfile, Tiff } } - // For BiColor compressed images, the BitsPerPixel value will be set explicitly to 1, so we don't throw in those cases. - // See: https://github.com/SixLabors/ImageSharp/issues/2587 - if (frameMetadata.BitsPerPixel == null && !IsBiColorCompression(frameMetadata.Compression)) - { - TiffThrowHelper.ThrowNotSupported("The TIFF BitsPerSample entry is missing which is required to decode the image!"); - } - return isTiled; } @@ -224,7 +215,6 @@ private static void ParseColorType(this TiffDecoderCore options, ExifProfile exi switch (bitsPerChannel) { case 32: - { if (options.SampleFormat == TiffSampleFormat.Float) { options.ColorType = TiffColorType.WhiteIsZero32Float; @@ -233,43 +223,30 @@ private static void ParseColorType(this TiffDecoderCore options, ExifProfile exi options.ColorType = TiffColorType.WhiteIsZero32; break; - } case 24: - { options.ColorType = TiffColorType.WhiteIsZero24; break; - } case 16: - { options.ColorType = TiffColorType.WhiteIsZero16; break; - } case 8: - { options.ColorType = TiffColorType.WhiteIsZero8; break; - } case 4: - { options.ColorType = TiffColorType.WhiteIsZero4; break; - } case 1: - { options.ColorType = TiffColorType.WhiteIsZero1; break; - } default: - { options.ColorType = TiffColorType.WhiteIsZero; break; - } } break; @@ -291,7 +268,6 @@ private static void ParseColorType(this TiffDecoderCore options, ExifProfile exi switch (bitsPerChannel) { case 32: - { if (options.SampleFormat == TiffSampleFormat.Float) { options.ColorType = TiffColorType.BlackIsZero32Float; @@ -300,43 +276,30 @@ private static void ParseColorType(this TiffDecoderCore options, ExifProfile exi options.ColorType = TiffColorType.BlackIsZero32; break; - } case 24: - { options.ColorType = TiffColorType.BlackIsZero24; break; - } case 16: - { options.ColorType = TiffColorType.BlackIsZero16; break; - } case 8: - { options.ColorType = TiffColorType.BlackIsZero8; break; - } case 4: - { options.ColorType = TiffColorType.BlackIsZero4; break; - } case 1: - { options.ColorType = TiffColorType.BlackIsZero1; break; - } default: - { options.ColorType = TiffColorType.BlackIsZero; break; - } } break; @@ -535,29 +498,21 @@ private static void ParseCompression(this TiffDecoderCore options, TiffCompressi switch (compression ?? TiffCompression.None) { case TiffCompression.None: - { options.CompressionType = TiffDecoderCompressionType.None; break; - } case TiffCompression.PackBits: - { options.CompressionType = TiffDecoderCompressionType.PackBits; break; - } case TiffCompression.Deflate: case TiffCompression.OldDeflate: - { options.CompressionType = TiffDecoderCompressionType.Deflate; break; - } case TiffCompression.Lzw: - { options.CompressionType = TiffDecoderCompressionType.Lzw; break; - } case TiffCompression.CcittGroup3Fax: { @@ -599,16 +554,13 @@ private static void ParseCompression(this TiffDecoderCore options, TiffCompressi } case TiffCompression.Ccitt1D: - { options.CompressionType = TiffDecoderCompressionType.HuffmanRle; options.BitsPerSample = new TiffBitsPerSample(1, 0, 0); options.BitsPerPixel = 1; break; - } case TiffCompression.OldJpeg: - { if (!options.OldJpegCompressionStartOfImageMarker.HasValue) { TiffThrowHelper.ThrowNotSupported("Missing SOI marker offset for tiff with old jpeg compression"); @@ -620,7 +572,6 @@ private static void ParseCompression(this TiffDecoderCore options, TiffCompressi } options.CompressionType = TiffDecoderCompressionType.OldJpeg; - if (options.PhotometricInterpretation is TiffPhotometricInterpretation.YCbCr) { // Note: Setting PhotometricInterpretation and color type to RGB here, since the jpeg decoder will handle the conversion of the pixel data. @@ -629,12 +580,18 @@ private static void ParseCompression(this TiffDecoderCore options, TiffCompressi } break; - } case TiffCompression.Jpeg: - { options.CompressionType = TiffDecoderCompressionType.Jpeg; + // Some tiff encoder set this to values different from [1, 1]. The jpeg decoder already handles this, + // so we set this always to [1, 1], see: https://github.com/SixLabors/ImageSharp/issues/2679 + if (options.PhotometricInterpretation is TiffPhotometricInterpretation.YCbCr && options.YcbcrSubSampling != null) + { + options.YcbcrSubSampling[0] = 1; + options.YcbcrSubSampling[1] = 1; + } + if (options.PhotometricInterpretation is TiffPhotometricInterpretation.YCbCr && options.JpegTables is null) { // Note: Setting PhotometricInterpretation and color type to RGB here, since the jpeg decoder will handle the conversion of the pixel data. @@ -643,30 +600,14 @@ private static void ParseCompression(this TiffDecoderCore options, TiffCompressi } break; - } case TiffCompression.Webp: - { options.CompressionType = TiffDecoderCompressionType.Webp; break; - } default: - { TiffThrowHelper.ThrowNotSupported($"The specified TIFF compression format '{compression}' is not supported"); break; - } } } - - private static bool IsBiColorCompression(TiffCompression? compression) - { - if (compression is TiffCompression.Ccitt1D or TiffCompression.CcittGroup3Fax or - TiffCompression.CcittGroup4Fax) - { - return true; - } - - return false; - } } diff --git a/src/ImageSharp/Formats/Tiff/TiffEncoder.cs b/src/ImageSharp/Formats/Tiff/TiffEncoder.cs index ea64e82899..a068613bf4 100644 --- a/src/ImageSharp/Formats/Tiff/TiffEncoder.cs +++ b/src/ImageSharp/Formats/Tiff/TiffEncoder.cs @@ -47,7 +47,7 @@ public class TiffEncoder : QuantizingImageEncoder /// protected override void Encode(Image image, Stream stream, CancellationToken cancellationToken) { - TiffEncoderCore encode = new(this, image.Configuration.MemoryAllocator); + TiffEncoderCore encode = new(this, image.Configuration); encode.Encode(image, stream, cancellationToken); } } diff --git a/src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs b/src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs index 59b4eac0bc..5f91fd7393 100644 --- a/src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs +++ b/src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs @@ -1,7 +1,7 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -#nullable disable +using System.Diagnostics.CodeAnalysis; using SixLabors.ImageSharp.Compression.Zlib; using SixLabors.ImageSharp.Formats.Tiff.Compression; using SixLabors.ImageSharp.Formats.Tiff.Constants; @@ -49,41 +49,22 @@ internal sealed class TiffEncoderCore /// private readonly DeflateCompressionLevel compressionLevel; - /// - /// The default predictor is None. - /// - private const TiffPredictor DefaultPredictor = TiffPredictor.None; - - /// - /// The default bits per pixel is Bit24. - /// - private const TiffBitsPerPixel DefaultBitsPerPixel = TiffBitsPerPixel.Bit24; - - /// - /// The default compression is None. - /// - private const TiffCompression DefaultCompression = TiffCompression.None; - - /// - /// The default photometric interpretation is Rgb. - /// - private const TiffPhotometricInterpretation DefaultPhotometricInterpretation = TiffPhotometricInterpretation.Rgb; - /// /// Whether to skip metadata during encoding. /// private readonly bool skipMetadata; - private readonly List<(long, uint)> frameMarkers = new(); + private readonly List<(long, uint)> frameMarkers = []; /// /// Initializes a new instance of the class. /// /// The options for the encoder. - /// The memory allocator. - public TiffEncoderCore(TiffEncoder options, MemoryAllocator memoryAllocator) + /// The global configuration. + public TiffEncoderCore(TiffEncoder options, Configuration configuration) { - this.memoryAllocator = memoryAllocator; + this.configuration = configuration; + this.memoryAllocator = configuration.MemoryAllocator; this.PhotometricInterpretation = options.PhotometricInterpretation; this.quantizer = options.Quantizer ?? KnownQuantizers.Octree; this.pixelSamplingStrategy = options.PixelSamplingStrategy; @@ -134,35 +115,29 @@ public void Encode(Image image, Stream stream, CancellationToken // Determine the correct values to encode with. // EncoderOptions > Metadata > Default. - TiffBitsPerPixel? bitsPerPixel = this.BitsPerPixel ?? rootFrameTiffMetaData.BitsPerPixel; + TiffBitsPerPixel bitsPerPixel = this.BitsPerPixel ?? rootFrameTiffMetaData.BitsPerPixel; - TiffPhotometricInterpretation? photometricInterpretation = this.PhotometricInterpretation ?? rootFrameTiffMetaData.PhotometricInterpretation; + TiffPhotometricInterpretation photometricInterpretation = this.PhotometricInterpretation ?? rootFrameTiffMetaData.PhotometricInterpretation; - TiffPredictor predictor = - this.HorizontalPredictor - ?? rootFrameTiffMetaData.Predictor - ?? DefaultPredictor; + TiffPredictor predictor = this.HorizontalPredictor ?? rootFrameTiffMetaData.Predictor; - TiffCompression compression = - this.CompressionType - ?? rootFrameTiffMetaData.Compression - ?? DefaultCompression; + TiffCompression compression = this.CompressionType ?? rootFrameTiffMetaData.Compression; - // Make sure, the Encoder options makes sense in combination with each other. - this.SanitizeAndSetEncoderOptions(bitsPerPixel, image.PixelType.BitsPerPixel, photometricInterpretation, compression, predictor); + // Make sure the Encoder options makes sense in combination with each other. + this.SanitizeAndSetEncoderOptions(bitsPerPixel, photometricInterpretation, compression, predictor); using TiffStreamWriter writer = new(stream); Span buffer = stackalloc byte[4]; long ifdMarker = WriteHeader(writer, buffer); - Image metadataImage = image; + Image? metadataImage = image; foreach (ImageFrame frame in image.Frames) { cancellationToken.ThrowIfCancellationRequested(); - ifdMarker = this.WriteFrame(writer, frame, image.Metadata, metadataImage, ifdMarker); + ifdMarker = this.WriteFrame(writer, frame, image.Metadata, metadataImage, this.BitsPerPixel.Value, this.CompressionType.Value, ifdMarker); metadataImage = null; } @@ -198,6 +173,8 @@ public static long WriteHeader(TiffStreamWriter writer, Span buffer) /// The tiff frame. /// The image metadata (resolution values for each frame). /// The image (common metadata for root frame). + /// The bits per pixel. + /// The compression type. /// The marker to write this IFD offset. /// /// The next IFD offset value. @@ -206,16 +183,18 @@ private long WriteFrame( TiffStreamWriter writer, ImageFrame frame, ImageMetadata imageMetadata, - Image image, + Image? image, + TiffBitsPerPixel bitsPerPixel, + TiffCompression compression, long ifdOffset) where TPixel : unmanaged, IPixel { using TiffBaseCompressor compressor = TiffCompressorFactory.Create( - this.CompressionType ?? TiffCompression.None, + compression, writer.BaseStream, this.memoryAllocator, frame.Width, - (int)this.BitsPerPixel, + (int)bitsPerPixel, this.compressionLevel, this.HorizontalPredictor == TiffPredictor.Horizontal ? this.HorizontalPredictor.Value : TiffPredictor.None); @@ -228,7 +207,7 @@ private long WriteFrame( this.memoryAllocator, this.configuration, entriesCollector, - (int)this.BitsPerPixel); + (int)bitsPerPixel); int rowsPerStrip = CalcRowsPerStrip(frame.Height, colorWriter.BytesPerRow, this.CompressionType); @@ -306,7 +285,7 @@ private long WriteIfd(TiffStreamWriter writer, List entries) } uint dataOffset = (uint)writer.Position + (uint)(6 + (entries.Count * 12)); - List largeDataBlocks = new(); + List largeDataBlocks = []; entries.Sort((a, b) => (ushort)a.Tag - (ushort)b.Tag); @@ -353,135 +332,87 @@ private long WriteIfd(TiffStreamWriter writer, List entries) return nextIfdMarker; } + [MemberNotNull(nameof(BitsPerPixel), nameof(PhotometricInterpretation), nameof(CompressionType), nameof(HorizontalPredictor))] private void SanitizeAndSetEncoderOptions( - TiffBitsPerPixel? bitsPerPixel, - int inputBitsPerPixel, - TiffPhotometricInterpretation? photometricInterpretation, + TiffBitsPerPixel bitsPerPixel, + TiffPhotometricInterpretation photometricInterpretation, TiffCompression compression, TiffPredictor predictor) { - // BitsPerPixel should be the primary source of truth for the encoder options. - if (bitsPerPixel.HasValue) + // Ensure 1 Bit compression is only used with 1 bit pixel type. + // Choose a sensible default based on the bits per pixel. + if (IsOneBitCompression(compression) && bitsPerPixel != TiffBitsPerPixel.Bit1) { - switch (bitsPerPixel) + compression = bitsPerPixel switch { - case TiffBitsPerPixel.Bit1: - if (IsOneBitCompression(compression)) - { - // The “normal” PhotometricInterpretation for bilevel CCITT compressed data is WhiteIsZero. - this.SetEncoderOptions(bitsPerPixel, TiffPhotometricInterpretation.WhiteIsZero, compression, TiffPredictor.None); - break; - } - - this.SetEncoderOptions(bitsPerPixel, TiffPhotometricInterpretation.BlackIsZero, compression, TiffPredictor.None); - break; - case TiffBitsPerPixel.Bit4: - this.SetEncoderOptions(bitsPerPixel, TiffPhotometricInterpretation.PaletteColor, compression, TiffPredictor.None); - break; - case TiffBitsPerPixel.Bit8: - this.SetEncoderOptions(bitsPerPixel, photometricInterpretation ?? TiffPhotometricInterpretation.BlackIsZero, compression, predictor); - break; - case TiffBitsPerPixel.Bit16: - // Assume desire to encode as L16 grayscale - this.SetEncoderOptions(bitsPerPixel, TiffPhotometricInterpretation.BlackIsZero, compression, predictor); - break; - case TiffBitsPerPixel.Bit6: - case TiffBitsPerPixel.Bit10: - case TiffBitsPerPixel.Bit12: - case TiffBitsPerPixel.Bit14: - case TiffBitsPerPixel.Bit30: - case TiffBitsPerPixel.Bit36: - case TiffBitsPerPixel.Bit42: - case TiffBitsPerPixel.Bit48: - // Encoding not yet supported bits per pixel will default to 24 bits. - this.SetEncoderOptions(TiffBitsPerPixel.Bit24, TiffPhotometricInterpretation.Rgb, compression, TiffPredictor.None); - break; - case TiffBitsPerPixel.Bit64: - // Encoding not yet supported bits per pixel will default to 32 bits. - this.SetEncoderOptions(TiffBitsPerPixel.Bit32, TiffPhotometricInterpretation.Rgb, compression, TiffPredictor.None); - break; - default: - this.SetEncoderOptions(bitsPerPixel, TiffPhotometricInterpretation.Rgb, compression, predictor); - break; - } - - // Make sure 1 Bit compression is only used with 1 bit pixel type. - if (IsOneBitCompression(this.CompressionType) && this.BitsPerPixel != TiffBitsPerPixel.Bit1) - { - // Invalid compression / bits per pixel combination, fallback to no compression. - this.CompressionType = DefaultCompression; - } - - return; + < TiffBitsPerPixel.Bit8 => TiffCompression.None, + _ => TiffCompression.Deflate, + }; } - // If no photometric interpretation was chosen, the input image bit per pixel should be preserved. - if (!photometricInterpretation.HasValue) - { - if (IsOneBitCompression(this.CompressionType)) - { - // We need to make sure bits per pixel is set to Bit1 now. WhiteIsZero is set because its the default for bilevel compressed data. - this.SetEncoderOptions(TiffBitsPerPixel.Bit1, TiffPhotometricInterpretation.WhiteIsZero, compression, TiffPredictor.None); - return; - } + // Ensure predictor is only used with compression that supports it. + predictor = HasPredictor(compression) ? predictor : TiffPredictor.None; - // At the moment only 8, 16 and 32 bits per pixel can be preserved by the tiff encoder. - if (inputBitsPerPixel == 8) - { - this.SetEncoderOptions(TiffBitsPerPixel.Bit8, TiffPhotometricInterpretation.BlackIsZero, compression, predictor); - return; - } - - if (inputBitsPerPixel == 16) - { - // Assume desire to encode as L16 grayscale - this.SetEncoderOptions(TiffBitsPerPixel.Bit16, TiffPhotometricInterpretation.BlackIsZero, compression, predictor); - return; - } - - this.SetEncoderOptions(TiffBitsPerPixel.Bit24, TiffPhotometricInterpretation.Rgb, compression, predictor); - return; - } - - switch (photometricInterpretation) + // BitsPerPixel should be the primary source of truth for the encoder options. + switch (bitsPerPixel) { - case TiffPhotometricInterpretation.BlackIsZero: - case TiffPhotometricInterpretation.WhiteIsZero: - if (IsOneBitCompression(this.CompressionType)) + case TiffBitsPerPixel.Bit1: + if (IsOneBitCompression(compression)) { - this.SetEncoderOptions(TiffBitsPerPixel.Bit1, photometricInterpretation, compression, TiffPredictor.None); - return; - } - - if (inputBitsPerPixel == 16) - { - this.SetEncoderOptions(TiffBitsPerPixel.Bit16, photometricInterpretation, compression, predictor); - return; + // The “normal” PhotometricInterpretation for bilevel CCITT compressed data is WhiteIsZero. + this.SetEncoderOptions(bitsPerPixel, TiffPhotometricInterpretation.WhiteIsZero, compression, predictor); + break; } - this.SetEncoderOptions(TiffBitsPerPixel.Bit8, photometricInterpretation, compression, predictor); - return; - - case TiffPhotometricInterpretation.PaletteColor: - this.SetEncoderOptions(TiffBitsPerPixel.Bit8, photometricInterpretation, compression, predictor); - return; - - case TiffPhotometricInterpretation.Rgb: - // Make sure 1 Bit compression is only used with 1 bit pixel type. - if (IsOneBitCompression(this.CompressionType)) + this.SetEncoderOptions(bitsPerPixel, TiffPhotometricInterpretation.BlackIsZero, compression, predictor); + break; + case TiffBitsPerPixel.Bit4: + this.SetEncoderOptions(bitsPerPixel, TiffPhotometricInterpretation.PaletteColor, compression, predictor); + break; + case TiffBitsPerPixel.Bit8: + + // Allow any combination of the below for 8 bit images. + if (photometricInterpretation is TiffPhotometricInterpretation.BlackIsZero + or TiffPhotometricInterpretation.WhiteIsZero + or TiffPhotometricInterpretation.PaletteColor) { - // Invalid compression / bits per pixel combination, fallback to no compression. - compression = DefaultCompression; + this.SetEncoderOptions(bitsPerPixel, photometricInterpretation, compression, predictor); + break; } - this.SetEncoderOptions(TiffBitsPerPixel.Bit24, photometricInterpretation, compression, predictor); - return; + this.SetEncoderOptions(bitsPerPixel, TiffPhotometricInterpretation.PaletteColor, compression, predictor); + break; + case TiffBitsPerPixel.Bit16: + // Assume desire to encode as L16 grayscale + this.SetEncoderOptions(bitsPerPixel, TiffPhotometricInterpretation.BlackIsZero, compression, predictor); + break; + case TiffBitsPerPixel.Bit6: + case TiffBitsPerPixel.Bit10: + case TiffBitsPerPixel.Bit12: + case TiffBitsPerPixel.Bit14: + case TiffBitsPerPixel.Bit30: + case TiffBitsPerPixel.Bit36: + case TiffBitsPerPixel.Bit42: + case TiffBitsPerPixel.Bit48: + // Encoding not yet supported bits per pixel will default to 24 bits. + this.SetEncoderOptions(TiffBitsPerPixel.Bit24, TiffPhotometricInterpretation.Rgb, compression, predictor); + break; + case TiffBitsPerPixel.Bit64: + // Encoding not yet supported bits per pixel will default to 32 bits. + this.SetEncoderOptions(TiffBitsPerPixel.Bit32, TiffPhotometricInterpretation.Rgb, compression, predictor); + break; + default: + this.SetEncoderOptions(bitsPerPixel, TiffPhotometricInterpretation.Rgb, compression, predictor); + break; } - - this.SetEncoderOptions(DefaultBitsPerPixel, DefaultPhotometricInterpretation, compression, predictor); } - private void SetEncoderOptions(TiffBitsPerPixel? bitsPerPixel, TiffPhotometricInterpretation? photometricInterpretation, TiffCompression compression, TiffPredictor predictor) + [MemberNotNull(nameof(BitsPerPixel), nameof(PhotometricInterpretation), nameof(CompressionType), nameof(HorizontalPredictor))] + private void SetEncoderOptions( + TiffBitsPerPixel bitsPerPixel, + TiffPhotometricInterpretation photometricInterpretation, + TiffCompression compression, + TiffPredictor predictor) { this.BitsPerPixel = bitsPerPixel; this.PhotometricInterpretation = photometricInterpretation; @@ -491,4 +422,7 @@ private void SetEncoderOptions(TiffBitsPerPixel? bitsPerPixel, TiffPhotometricIn public static bool IsOneBitCompression(TiffCompression? compression) => compression is TiffCompression.Ccitt1D or TiffCompression.CcittGroup3Fax or TiffCompression.CcittGroup4Fax; + + public static bool HasPredictor(TiffCompression? compression) + => compression is TiffCompression.Deflate or TiffCompression.Lzw; } diff --git a/src/ImageSharp/Formats/Tiff/TiffFrameMetadata.cs b/src/ImageSharp/Formats/Tiff/TiffFrameMetadata.cs index e309830984..bb5da37411 100644 --- a/src/ImageSharp/Formats/Tiff/TiffFrameMetadata.cs +++ b/src/ImageSharp/Formats/Tiff/TiffFrameMetadata.cs @@ -9,7 +9,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff; /// /// Provides Tiff specific metadata information for the frame. /// -public class TiffFrameMetadata : IDeepCloneable +public class TiffFrameMetadata : IFormatFrameMetadata { /// /// Initializes a new instance of the class. @@ -34,33 +34,47 @@ private TiffFrameMetadata(TiffFrameMetadata other) /// /// Gets or sets the bits per pixel. /// - public TiffBitsPerPixel? BitsPerPixel { get; set; } + public TiffBitsPerPixel BitsPerPixel { get; set; } = TiffConstants.DefaultBitsPerPixel; /// /// Gets or sets number of bits per component. /// - public TiffBitsPerSample? BitsPerSample { get; set; } + public TiffBitsPerSample BitsPerSample { get; set; } = TiffConstants.DefaultBitsPerSample; /// /// Gets or sets the compression scheme used on the image data. /// - public TiffCompression? Compression { get; set; } + public TiffCompression Compression { get; set; } = TiffConstants.DefaultCompression; /// /// Gets or sets the color space of the image data. /// - public TiffPhotometricInterpretation? PhotometricInterpretation { get; set; } + public TiffPhotometricInterpretation PhotometricInterpretation { get; set; } = TiffConstants.DefaultPhotometricInterpretation; /// /// Gets or sets a mathematical operator that is applied to the image data before an encoding scheme is applied. /// - public TiffPredictor? Predictor { get; set; } + public TiffPredictor Predictor { get; set; } = TiffConstants.DefaultPredictor; /// /// Gets or sets the set of inks used in a separated () image. /// public TiffInkSet? InkSet { get; set; } + /// + public static TiffFrameMetadata FromFormatConnectingFrameMetadata(FormatConnectingFrameMetadata metadata) + => new(); + + /// + public FormatConnectingFrameMetadata ToFormatConnectingFrameMetadata() + => new(); + + /// + IDeepCloneable IDeepCloneable.DeepClone() => this.DeepClone(); + + /// + public TiffFrameMetadata DeepClone() => new(this); + /// /// Returns a new instance parsed from the given Exif profile. /// @@ -89,7 +103,7 @@ internal static void Parse(TiffFrameMetadata meta, ExifProfile profile) meta.BitsPerSample = bitsPerSample; } - meta.BitsPerPixel = meta.BitsPerSample?.BitsPerPixel(); + meta.BitsPerPixel = meta.BitsPerSample.BitsPerPixel(); if (profile.TryGetValue(ExifTag.Compression, out IExifValue? compressionValue)) { @@ -111,13 +125,11 @@ internal static void Parse(TiffFrameMetadata meta, ExifProfile profile) meta.InkSet = (TiffInkSet)inkSetValue.Value; } + // TODO: Why do we remove this? Encoding should overwrite. profile.RemoveValue(ExifTag.BitsPerSample); profile.RemoveValue(ExifTag.Compression); profile.RemoveValue(ExifTag.PhotometricInterpretation); profile.RemoveValue(ExifTag.Predictor); } } - - /// - public IDeepCloneable DeepClone() => new TiffFrameMetadata(this); } diff --git a/src/ImageSharp/Formats/Tiff/TiffMetadata.cs b/src/ImageSharp/Formats/Tiff/TiffMetadata.cs index 2759d0130c..cc70941d51 100644 --- a/src/ImageSharp/Formats/Tiff/TiffMetadata.cs +++ b/src/ImageSharp/Formats/Tiff/TiffMetadata.cs @@ -1,12 +1,15 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. +using SixLabors.ImageSharp.Formats.Tiff.Constants; +using SixLabors.ImageSharp.PixelFormats; + namespace SixLabors.ImageSharp.Formats.Tiff; /// /// Provides Tiff specific metadata information for the image. /// -public class TiffMetadata : IDeepCloneable +public class TiffMetadata : IFormatMetadata { /// /// Initializes a new instance of the class. @@ -23,6 +26,11 @@ private TiffMetadata(TiffMetadata other) { this.ByteOrder = other.ByteOrder; this.FormatType = other.FormatType; + this.BitsPerPixel = other.BitsPerPixel; + this.BitsPerSample = other.BitsPerSample; + this.Compression = other.Compression; + this.PhotometricInterpretation = other.PhotometricInterpretation; + this.Predictor = other.Predictor; } /// @@ -35,6 +43,146 @@ private TiffMetadata(TiffMetadata other) /// public TiffFormatType FormatType { get; set; } + /// + /// Gets or sets the bits per pixel. Derived from the root frame. + /// + public TiffBitsPerPixel BitsPerPixel { get; set; } = TiffConstants.DefaultBitsPerPixel; + + /// + /// Gets or sets number of bits per component. Derived from the root frame. + /// + public TiffBitsPerSample BitsPerSample { get; set; } = TiffConstants.DefaultBitsPerSample; + + /// + /// Gets or sets the compression scheme used on the image data. Derived from the root frame. + /// + public TiffCompression Compression { get; set; } = TiffConstants.DefaultCompression; + + /// + /// Gets or sets the color space of the image data. Derived from the root frame. + /// + public TiffPhotometricInterpretation PhotometricInterpretation { get; set; } = TiffConstants.DefaultPhotometricInterpretation; + + /// + /// Gets or sets a mathematical operator that is applied to the image data before an encoding scheme is applied. + /// Derived from the root frame. + /// + public TiffPredictor Predictor { get; set; } = TiffConstants.DefaultPredictor; + + /// + public static TiffMetadata FromFormatConnectingMetadata(FormatConnectingMetadata metadata) + { + int bpp = metadata.PixelTypeInfo.BitsPerPixel; + return bpp switch + { + 1 => new TiffMetadata + { + BitsPerPixel = TiffBitsPerPixel.Bit1, + BitsPerSample = TiffConstants.BitsPerSample1Bit, + PhotometricInterpretation = TiffPhotometricInterpretation.WhiteIsZero, + Compression = TiffCompression.CcittGroup4Fax, + Predictor = TiffPredictor.None + }, + <= 4 => new TiffMetadata + { + BitsPerPixel = TiffBitsPerPixel.Bit4, + BitsPerSample = TiffConstants.BitsPerSample4Bit, + PhotometricInterpretation = TiffPhotometricInterpretation.PaletteColor, + Compression = TiffCompression.Deflate, + Predictor = TiffPredictor.None // Best match for low bit depth + }, + 8 => new TiffMetadata + { + BitsPerPixel = TiffBitsPerPixel.Bit8, + BitsPerSample = TiffConstants.BitsPerSample8Bit, + PhotometricInterpretation = TiffPhotometricInterpretation.PaletteColor, + Compression = TiffCompression.Deflate, + Predictor = TiffPredictor.Horizontal + }, + 16 => new TiffMetadata + { + BitsPerPixel = TiffBitsPerPixel.Bit16, + BitsPerSample = TiffConstants.BitsPerSample16Bit, + PhotometricInterpretation = TiffPhotometricInterpretation.BlackIsZero, + Compression = TiffCompression.Deflate, + Predictor = TiffPredictor.Horizontal + }, + 32 or 64 => new TiffMetadata + { + BitsPerPixel = TiffBitsPerPixel.Bit32, + BitsPerSample = TiffConstants.BitsPerSampleRgb8Bit, + PhotometricInterpretation = TiffPhotometricInterpretation.Rgb, + Compression = TiffCompression.Deflate, + Predictor = TiffPredictor.Horizontal + }, + _ => new TiffMetadata + { + BitsPerPixel = TiffBitsPerPixel.Bit24, + BitsPerSample = TiffConstants.BitsPerSampleRgb8Bit, + PhotometricInterpretation = TiffPhotometricInterpretation.Rgb, + Compression = TiffCompression.Deflate, + Predictor = TiffPredictor.Horizontal + } + }; + } + + /// + public PixelTypeInfo GetPixelTypeInfo() + { + int bpp = (int)this.BitsPerPixel; + + TiffBitsPerSample samples = this.BitsPerSample; + PixelComponentInfo info = samples.Channels switch + { + 1 => PixelComponentInfo.Create(1, bpp, bpp), + 2 => PixelComponentInfo.Create(2, bpp, bpp, samples.Channel0, samples.Channel1), + 3 => PixelComponentInfo.Create(3, bpp, samples.Channel0, samples.Channel1, samples.Channel2), + _ => PixelComponentInfo.Create(4, bpp, samples.Channel0, samples.Channel1, samples.Channel2, samples.Channel3) + }; + + PixelColorType colorType; + PixelAlphaRepresentation alpha = PixelAlphaRepresentation.None; + switch (this.BitsPerPixel) + { + case TiffBitsPerPixel.Bit1: + colorType = PixelColorType.Binary; + break; + case TiffBitsPerPixel.Bit4: + case TiffBitsPerPixel.Bit6: + case TiffBitsPerPixel.Bit8: + colorType = PixelColorType.Indexed; + break; + case TiffBitsPerPixel.Bit16: + colorType = PixelColorType.Luminance; + break; + case TiffBitsPerPixel.Bit32: + case TiffBitsPerPixel.Bit64: + colorType = PixelColorType.RGB | PixelColorType.Alpha; + alpha = PixelAlphaRepresentation.Unassociated; + break; + default: + colorType = PixelColorType.RGB; + break; + } + + return new PixelTypeInfo(bpp) + { + ColorType = colorType, + ComponentInfo = info, + AlphaRepresentation = alpha + }; + } + + /// + public FormatConnectingMetadata ToFormatConnectingMetadata() + => new() + { + PixelTypeInfo = this.GetPixelTypeInfo() + }; + + /// + IDeepCloneable IDeepCloneable.DeepClone() => this.DeepClone(); + /// - public IDeepCloneable DeepClone() => new TiffMetadata(this); + public TiffMetadata DeepClone() => new(this); } diff --git a/src/ImageSharp/Formats/Tiff/Utils/TiffUtilities.cs b/src/ImageSharp/Formats/Tiff/Utils/TiffUtilities.cs new file mode 100644 index 0000000000..8b5e04f276 --- /dev/null +++ b/src/ImageSharp/Formats/Tiff/Utils/TiffUtilities.cs @@ -0,0 +1,120 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Buffers.Binary; +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.Intrinsics; +using SixLabors.ImageSharp.PixelFormats; + +namespace SixLabors.ImageSharp.Formats.Tiff.Utils; + +/// +/// Helper methods for TIFF decoding. +/// +internal static class TiffUtilities +{ + private const float Scale24Bit = 1f / 0xFFFFFF; + private static readonly Vector4 Scale24BitVector = Vector128.Create(Scale24Bit, Scale24Bit, Scale24Bit, 1f).AsVector4(); + + private const float Scale32Bit = 1f / 0xFFFFFFFF; + private static readonly Vector4 Scale32BitVector = Vector128.Create(Scale32Bit, Scale32Bit, Scale32Bit, 1f).AsVector4(); + + public static Rgba64 Rgba64Default { get; } = new(0, 0, 0, 0); + + public static L16 L16Default { get; } = new(0); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ushort ConvertToUShortBigEndian(ReadOnlySpan buffer) => BinaryPrimitives.ReadUInt16BigEndian(buffer); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ushort ConvertToUShortLittleEndian(ReadOnlySpan buffer) => BinaryPrimitives.ReadUInt16LittleEndian(buffer); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static uint ConvertToUIntBigEndian(ReadOnlySpan buffer) => BinaryPrimitives.ReadUInt32BigEndian(buffer); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static uint ConvertToUIntLittleEndian(ReadOnlySpan buffer) => BinaryPrimitives.ReadUInt32LittleEndian(buffer); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel ColorFromRgba64Premultiplied(ushort r, ushort g, ushort b, ushort a) + where TPixel : unmanaged, IPixel + { + if (a == 0) + { + return TPixel.FromRgba64(default); + } + + return TPixel.FromRgba64(new((ushort)(r / a), (ushort)(g / a), (ushort)(b / a), a)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel ColorScaleTo24Bit(uint r, uint g, uint b) + where TPixel : unmanaged, IPixel + => TPixel.FromScaledVector4(new Vector4(r, g, b, 1f) * Scale24BitVector); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel ColorScaleTo24Bit(uint r, uint g, uint b, uint a) + where TPixel : unmanaged, IPixel + => TPixel.FromScaledVector4(new Vector4(r, g, b, a) * Scale24Bit); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel ColorScaleTo24BitPremultiplied(uint r, uint g, uint b, uint a) + where TPixel : unmanaged, IPixel + { + Vector4 colorVector = new Vector4(r, g, b, a) * Scale24Bit; + return UnPremultiply(ref colorVector); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel ColorScaleTo32Bit(uint r, uint g, uint b) + where TPixel : unmanaged, IPixel + => TPixel.FromScaledVector4(new Vector4(r, g, b, 1f) * Scale32BitVector); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel ColorScaleTo32Bit(uint r, uint g, uint b, uint a) + where TPixel : unmanaged, IPixel + => TPixel.FromScaledVector4(new Vector4(r, g, b, a) * Scale32Bit); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel ColorScaleTo32BitPremultiplied(uint r, uint g, uint b, uint a) + where TPixel : unmanaged, IPixel + { + Vector4 vector = new Vector4(r, g, b, a) * Scale32Bit; + return UnPremultiply(ref vector); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel ColorScaleTo24Bit(uint intensity) + where TPixel : unmanaged, IPixel + => TPixel.FromScaledVector4(new Vector4(intensity, intensity, intensity, 1f) * Scale24BitVector); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel ColorScaleTo32Bit(uint intensity) + where TPixel : unmanaged, IPixel + => TPixel.FromScaledVector4(new Vector4(intensity, intensity, intensity, 1f) * Scale32BitVector); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel UnPremultiply(ref Vector4 vector) + where TPixel : unmanaged, IPixel + { + Numerics.UnPremultiply(ref vector); + return TPixel.FromScaledVector4(vector); + } + + /// + /// Finds the padding needed to round 'valueToRoundUp' to the next integer multiple of subSampling value. + /// + /// The width or height to round up. + /// The sub sampling. + /// The padding. + public static int PaddingToNextInteger(int valueToRoundUp, int subSampling) + { + if (valueToRoundUp % subSampling == 0) + { + return 0; + } + + return subSampling - (valueToRoundUp % subSampling); + } +} diff --git a/src/ImageSharp/Formats/Tiff/Utils/TiffUtils.cs b/src/ImageSharp/Formats/Tiff/Utils/TiffUtils.cs deleted file mode 100644 index 7e0251af6d..0000000000 --- a/src/ImageSharp/Formats/Tiff/Utils/TiffUtils.cs +++ /dev/null @@ -1,176 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Buffers.Binary; -using System.Numerics; -using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.PixelFormats; - -namespace SixLabors.ImageSharp.Formats.Tiff.Utils; - -/// -/// Helper methods for TIFF decoding. -/// -internal static class TiffUtils -{ - private const float Scale24Bit = 1.0f / 0xFFFFFF; - - private const float Scale32Bit = 1.0f / 0xFFFFFFFF; - - public static Rgba64 Rgba64Default { get; } = new(0, 0, 0, 0); - - public static L16 L16Default { get; } = new(0); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ushort ConvertToUShortBigEndian(ReadOnlySpan buffer) => BinaryPrimitives.ReadUInt16BigEndian(buffer); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ushort ConvertToUShortLittleEndian(ReadOnlySpan buffer) => BinaryPrimitives.ReadUInt16LittleEndian(buffer); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static uint ConvertToUIntBigEndian(ReadOnlySpan buffer) => BinaryPrimitives.ReadUInt32BigEndian(buffer); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static uint ConvertToUIntLittleEndian(ReadOnlySpan buffer) => BinaryPrimitives.ReadUInt32LittleEndian(buffer); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static TPixel ColorFromL8(L8 l8, byte intensity, TPixel color) - where TPixel : unmanaged, IPixel - { - l8.PackedValue = intensity; - color.FromL8(l8); - return color; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static TPixel ColorFromRgb64(Rgba64 rgba, ulong r, ulong g, ulong b, TPixel color) - where TPixel : unmanaged, IPixel - { - rgba.PackedValue = r | (g << 16) | (b << 32) | (0xfffful << 48); - color.FromRgba64(rgba); - return color; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static TPixel ColorFromRgba64(Rgba64 rgba, ulong r, ulong g, ulong b, ulong a, TPixel color) - where TPixel : unmanaged, IPixel - { - rgba.PackedValue = r | (g << 16) | (b << 32) | (a << 48); - color.FromRgba64(rgba); - return color; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static TPixel ColorFromRgba64Premultiplied(Rgba64 rgba, ulong r, ulong g, ulong b, ulong a, TPixel color) - where TPixel : unmanaged, IPixel - { - rgba.PackedValue = r | (g << 16) | (b << 32) | (a << 48); - var vec = rgba.ToVector4(); - return UnPremultiply(ref vec, color); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static TPixel ColorScaleTo24Bit(ulong r, ulong g, ulong b, TPixel color) - where TPixel : unmanaged, IPixel - { - var colorVector = new Vector4(r * Scale24Bit, g * Scale24Bit, b * Scale24Bit, 1.0f); - color.FromScaledVector4(colorVector); - return color; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static TPixel ColorScaleTo24Bit(ulong r, ulong g, ulong b, ulong a, TPixel color) - where TPixel : unmanaged, IPixel - { - Vector4 colorVector = new Vector4(r, g, b, a) * Scale24Bit; - color.FromScaledVector4(colorVector); - return color; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static TPixel ColorScaleTo24BitPremultiplied(ulong r, ulong g, ulong b, ulong a, TPixel color) - where TPixel : unmanaged, IPixel - { - Vector4 colorVector = new Vector4(r, g, b, a) * Scale24Bit; - return UnPremultiply(ref colorVector, color); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static TPixel ColorScaleTo32Bit(ulong r, ulong g, ulong b, TPixel color) - where TPixel : unmanaged, IPixel - { - var colorVector = new Vector4(r * Scale32Bit, g * Scale32Bit, b * Scale32Bit, 1.0f); - color.FromScaledVector4(colorVector); - return color; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static TPixel ColorScaleTo32Bit(ulong r, ulong g, ulong b, ulong a, TPixel color) - where TPixel : unmanaged, IPixel - { - Vector4 colorVector = new Vector4(r, g, b, a) * Scale32Bit; - color.FromScaledVector4(colorVector); - return color; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static TPixel ColorScaleTo32BitPremultiplied(ulong r, ulong g, ulong b, ulong a, TPixel color) - where TPixel : unmanaged, IPixel - { - Vector4 colorVector = new Vector4(r, g, b, a) * Scale32Bit; - return UnPremultiply(ref colorVector, color); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static TPixel ColorFromL16(L16 l16, ushort intensity, TPixel color) - where TPixel : unmanaged, IPixel - { - l16.PackedValue = intensity; - color.FromL16(l16); - return color; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static TPixel ColorScaleTo24Bit(ulong intensity, TPixel color) - where TPixel : unmanaged, IPixel - { - var colorVector = new Vector4(intensity * Scale24Bit, intensity * Scale24Bit, intensity * Scale24Bit, 1.0f); - color.FromScaledVector4(colorVector); - return color; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static TPixel ColorScaleTo32Bit(ulong intensity, TPixel color) - where TPixel : unmanaged, IPixel - { - var colorVector = new Vector4(intensity * Scale32Bit, intensity * Scale32Bit, intensity * Scale32Bit, 1.0f); - color.FromScaledVector4(colorVector); - return color; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static TPixel UnPremultiply(ref Vector4 vector, TPixel color) - where TPixel : unmanaged, IPixel - { - Numerics.UnPremultiply(ref vector); - color.FromScaledVector4(vector); - - return color; - } - - /// - /// Finds the padding needed to round 'valueToRoundUp' to the next integer multiple of subSampling value. - /// - /// The width or height to round up. - /// The sub sampling. - /// The padding. - public static int PaddingToNextInteger(int valueToRoundUp, int subSampling) - { - if (valueToRoundUp % subSampling == 0) - { - return 0; - } - - return subSampling - (valueToRoundUp % subSampling); - } -} diff --git a/src/ImageSharp/Formats/Webp/AlphaDecoder.cs b/src/ImageSharp/Formats/Webp/AlphaDecoder.cs index 63571617fb..eccd9ede8e 100644 --- a/src/ImageSharp/Formats/Webp/AlphaDecoder.cs +++ b/src/ImageSharp/Formats/Webp/AlphaDecoder.cs @@ -6,7 +6,9 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; using System.Runtime.Intrinsics.X86; +using SixLabors.ImageSharp.Common.Helpers; using SixLabors.ImageSharp.Formats.Webp.BitReader; using SixLabors.ImageSharp.Formats.Webp.Lossless; using SixLabors.ImageSharp.Memory; @@ -311,8 +313,7 @@ private static void ColorIndexInverseTransformAlpha( private static void HorizontalUnfilter(Span prev, Span input, Span dst, int width) { - // TODO: Investigate AdvSimd support for this method. - if (Sse2.IsSupported && width >= 9) + if ((Sse2.IsSupported || AdvSimd.IsSupported) && width >= 9) { dst[0] = (byte)(input[0] + (prev.IsEmpty ? 0 : prev[0])); nuint i; @@ -323,17 +324,17 @@ private static void HorizontalUnfilter(Span prev, Span input, Span a0 = Vector128.Create(Unsafe.As(ref Unsafe.Add(ref srcRef, i)), 0); - Vector128 a1 = Sse2.Add(a0.AsByte(), last.AsByte()); - Vector128 a2 = Sse2.ShiftLeftLogical128BitLane(a1, 1); - Vector128 a3 = Sse2.Add(a1, a2); - Vector128 a4 = Sse2.ShiftLeftLogical128BitLane(a3, 2); - Vector128 a5 = Sse2.Add(a3, a4); - Vector128 a6 = Sse2.ShiftLeftLogical128BitLane(a5, 4); - Vector128 a7 = Sse2.Add(a5, a6); + Vector128 a1 = a0.AsByte() + last.AsByte(); + Vector128 a2 = Vector128Utilities.ShiftLeftBytesInVector(a1, 1); + Vector128 a3 = a1 + a2; + Vector128 a4 = Vector128Utilities.ShiftLeftBytesInVector(a3, 2); + Vector128 a5 = a3 + a4; + Vector128 a6 = Vector128Utilities.ShiftLeftBytesInVector(a5, 4); + Vector128 a7 = a5 + a6; ref byte outputRef = ref Unsafe.Add(ref dstRef, i); Unsafe.As>(ref outputRef) = a7.GetLower(); - last = Sse2.ShiftRightLogical(a7.AsInt64(), 56).AsInt32(); + last = Vector128.ShiftRightLogical(a7.AsInt64(), 56).AsInt32(); } for (; i < (uint)width; ++i) diff --git a/src/ImageSharp/Formats/Webp/BitWriter/BitWriterBase.cs b/src/ImageSharp/Formats/Webp/BitWriter/BitWriterBase.cs index 651e68011f..39c4beb618 100644 --- a/src/ImageSharp/Formats/Webp/BitWriter/BitWriterBase.cs +++ b/src/ImageSharp/Formats/Webp/BitWriter/BitWriterBase.cs @@ -1,11 +1,11 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.Common.Helpers; using SixLabors.ImageSharp.Formats.Webp.Chunks; using SixLabors.ImageSharp.Metadata.Profiles.Exif; using SixLabors.ImageSharp.Metadata.Profiles.Icc; using SixLabors.ImageSharp.Metadata.Profiles.Xmp; +using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Formats.Webp.BitWriter; @@ -167,7 +167,7 @@ public static void WriteTrunksAfterData( /// The number of times to loop the animation. If it is 0, this means infinitely. public static void WriteAnimationParameter(Stream stream, Color background, ushort loopCount) { - WebpAnimationParameter chunk = new(background.ToBgra32().PackedValue, loopCount); + WebpAnimationParameter chunk = new(background.ToPixel().PackedValue, loopCount); chunk.WriteTo(stream); } diff --git a/src/ImageSharp/Formats/Webp/Chunks/WebpAnimationParameter.cs b/src/ImageSharp/Formats/Webp/Chunks/WebpAnimationParameter.cs index 3855a293c1..cff9f47afa 100644 --- a/src/ImageSharp/Formats/Webp/Chunks/WebpAnimationParameter.cs +++ b/src/ImageSharp/Formats/Webp/Chunks/WebpAnimationParameter.cs @@ -2,7 +2,6 @@ // Licensed under the Six Labors Split License. using System.Buffers.Binary; -using SixLabors.ImageSharp.Common.Helpers; namespace SixLabors.ImageSharp.Formats.Webp.Chunks; diff --git a/src/ImageSharp/Formats/Webp/Chunks/WebpFrameData.cs b/src/ImageSharp/Formats/Webp/Chunks/WebpFrameData.cs index 5ed7aab1ea..66662569c3 100644 --- a/src/ImageSharp/Formats/Webp/Chunks/WebpFrameData.cs +++ b/src/ImageSharp/Formats/Webp/Chunks/WebpFrameData.cs @@ -1,8 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.Common.Helpers; - namespace SixLabors.ImageSharp.Formats.Webp.Chunks; internal readonly struct WebpFrameData @@ -12,7 +10,7 @@ internal readonly struct WebpFrameData /// public const uint HeaderSize = 16; - public WebpFrameData(uint dataSize, uint x, uint y, uint width, uint height, uint duration, WebpBlendMethod blendingMethod, WebpDisposalMethod disposalMethod) + public WebpFrameData(uint dataSize, uint x, uint y, uint width, uint height, uint duration, FrameBlendMode blendingMethod, FrameDisposalMode disposalMethod) { this.DataSize = dataSize; this.X = x; @@ -32,12 +30,12 @@ public WebpFrameData(uint dataSize, uint x, uint y, uint width, uint height, uin width, height, duration, - (flags & 2) == 0 ? WebpBlendMethod.Over : WebpBlendMethod.Source, - (flags & 1) == 1 ? WebpDisposalMethod.RestoreToBackground : WebpDisposalMethod.DoNotDispose) + (flags & 2) == 0 ? FrameBlendMode.Over : FrameBlendMode.Source, + (flags & 1) == 1 ? FrameDisposalMode.RestoreToBackground : FrameDisposalMode.DoNotDispose) { } - public WebpFrameData(uint x, uint y, uint width, uint height, uint duration, WebpBlendMethod blendingMethod, WebpDisposalMethod disposalMethod) + public WebpFrameData(uint x, uint y, uint width, uint height, uint duration, FrameBlendMode blendingMethod, FrameDisposalMode disposalMethod) : this(0, x, y, width, height, duration, blendingMethod, disposalMethod) { } @@ -76,12 +74,12 @@ public WebpFrameData(uint x, uint y, uint width, uint height, uint duration, Web /// /// Gets how transparent pixels of the current frame are to be blended with corresponding pixels of the previous canvas. /// - public WebpBlendMethod BlendingMethod { get; } + public FrameBlendMode BlendingMethod { get; } /// /// Gets how the current frame is to be treated after it has been displayed (before rendering the next frame) on the canvas. /// - public WebpDisposalMethod DisposalMethod { get; } + public FrameDisposalMode DisposalMethod { get; } public Rectangle Bounds => new((int)this.X, (int)this.Y, (int)this.Width, (int)this.Height); @@ -93,13 +91,13 @@ public long WriteHeaderTo(Stream stream) { byte flags = 0; - if (this.BlendingMethod is WebpBlendMethod.Source) + if (this.BlendingMethod is FrameBlendMode.Source) { // Set blending flag. flags |= 2; } - if (this.DisposalMethod is WebpDisposalMethod.RestoreToBackground) + if (this.DisposalMethod is FrameDisposalMode.RestoreToBackground) { // Set disposal flag. flags |= 1; @@ -126,7 +124,7 @@ public static WebpFrameData Parse(Stream stream) { Span buffer = stackalloc byte[4]; - WebpFrameData data = new( + return new( dataSize: WebpChunkParsingUtils.ReadChunkSize(stream, buffer), x: WebpChunkParsingUtils.ReadUInt24LittleEndian(stream, buffer) * 2, y: WebpChunkParsingUtils.ReadUInt24LittleEndian(stream, buffer) * 2, @@ -134,7 +132,5 @@ public static WebpFrameData Parse(Stream stream) height: WebpChunkParsingUtils.ReadUInt24LittleEndian(stream, buffer) + 1, duration: WebpChunkParsingUtils.ReadUInt24LittleEndian(stream, buffer), flags: stream.ReadByte()); - - return data; } } diff --git a/src/ImageSharp/Formats/Webp/Chunks/WebpVp8X.cs b/src/ImageSharp/Formats/Webp/Chunks/WebpVp8X.cs index fc88f8faad..491f716500 100644 --- a/src/ImageSharp/Formats/Webp/Chunks/WebpVp8X.cs +++ b/src/ImageSharp/Formats/Webp/Chunks/WebpVp8X.cs @@ -1,8 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.Common.Helpers; - namespace SixLabors.ImageSharp.Formats.Webp.Chunks; internal readonly struct WebpVp8X : IEquatable diff --git a/src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs b/src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs index 40009f525b..244691e77e 100644 --- a/src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs +++ b/src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs @@ -6,7 +6,6 @@ using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using SixLabors.ImageSharp.Common.Helpers; using SixLabors.ImageSharp.Formats.Webp.BitWriter; using SixLabors.ImageSharp.Formats.Webp.Chunks; using SixLabors.ImageSharp.Memory; @@ -242,8 +241,6 @@ public WebpVp8X EncodeHeader(Image image, Stream stream, bool ha { // Write bytes from the bit-writer buffer to the stream. ImageMetadata metadata = image.Metadata; - metadata.SyncProfiles(); - ExifProfile exifProfile = this.skipMetadata ? null : metadata.ExifProfile; XmpProfile xmpProfile = this.skipMetadata ? null : metadata.XmpProfile; @@ -260,7 +257,7 @@ public WebpVp8X EncodeHeader(Image image, Stream stream, bool ha if (hasAnimation) { - WebpMetadata webpMetadata = WebpCommonUtils.GetWebpMetadata(image); + WebpMetadata webpMetadata = image.Metadata.GetWebpMetadata(); BitWriterBase.WriteAnimationParameter(stream, webpMetadata.BackgroundColor, webpMetadata.RepeatCount); } diff --git a/src/ImageSharp/Formats/Webp/Lossy/LossyUtils.cs b/src/ImageSharp/Formats/Webp/Lossy/LossyUtils.cs index de3f1586af..aae4181ce0 100644 --- a/src/ImageSharp/Formats/Webp/Lossy/LossyUtils.cs +++ b/src/ImageSharp/Formats/Webp/Lossy/LossyUtils.cs @@ -230,11 +230,7 @@ private static unsafe int Vp8_Sse16x16_Neon(Span a, Span b) } } -#if NET7_0_OR_GREATER return (int)Vector128.Sum(sum); -#else - return Numerics.ReduceSumArm(sum); -#endif } [MethodImpl(InliningOptions.ShortMethod)] @@ -252,11 +248,7 @@ private static unsafe int Vp8_Sse16x8_Neon(Span a, Span b) } } -#if NET7_0_OR_GREATER return (int)Vector128.Sum(sum); -#else - return Numerics.ReduceSumArm(sum); -#endif } [MethodImpl(InliningOptions.ShortMethod)] @@ -275,11 +267,8 @@ private static int Vp8_Sse4x4_Neon(Span a, Span b) Vector128 sum2 = AdvSimd.AddPairwiseWidening(prod2); Vector128 sum = AdvSimd.Add(sum1, sum2); -#if NET7_0_OR_GREATER + return (int)Vector128.Sum(sum); -#else - return Numerics.ReduceSumArm(sum); -#endif } // Load all 4x4 pixels into a single Vector128 diff --git a/src/ImageSharp/Formats/Webp/Lossy/Vp8Encoder.cs b/src/ImageSharp/Formats/Webp/Lossy/Vp8Encoder.cs index 7317527f72..3ad72f7d00 100644 --- a/src/ImageSharp/Formats/Webp/Lossy/Vp8Encoder.cs +++ b/src/ImageSharp/Formats/Webp/Lossy/Vp8Encoder.cs @@ -4,7 +4,6 @@ using System.Buffers; using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.Common.Helpers; using SixLabors.ImageSharp.Formats.Webp.BitWriter; using SixLabors.ImageSharp.Formats.Webp.Chunks; using SixLabors.ImageSharp.Memory; @@ -316,8 +315,6 @@ public WebpVp8X EncodeHeader(Image image, Stream stream, bool ha { // Write bytes from the bitwriter buffer to the stream. ImageMetadata metadata = image.Metadata; - metadata.SyncProfiles(); - ExifProfile exifProfile = this.skipMetadata ? null : metadata.ExifProfile; XmpProfile xmpProfile = this.skipMetadata ? null : metadata.XmpProfile; @@ -333,7 +330,7 @@ public WebpVp8X EncodeHeader(Image image, Stream stream, bool ha if (hasAnimation) { - WebpMetadata webpMetadata = WebpCommonUtils.GetWebpMetadata(image); + WebpMetadata webpMetadata = image.Metadata.GetWebpMetadata(); BitWriterBase.WriteAnimationParameter(stream, webpMetadata.BackgroundColor, webpMetadata.RepeatCount); } @@ -377,7 +374,7 @@ public void EncodeStatic(Stream stream, Image image) where TPixel : unmanaged, IPixel { ImageFrame frame = image.Frames.RootFrame; - this.Encode(stream, frame, image.Bounds, WebpCommonUtils.GetWebpFrameMetadata(frame), false, image); + this.Encode(stream, frame, image.Bounds, frame.Metadata.GetWebpMetadata(), false, image); } /// @@ -463,7 +460,7 @@ private bool Encode(Stream stream, ImageFrame frame, Rectangle b // Extract and encode alpha channel data, if present. int alphaDataSize = 0; bool alphaCompressionSucceeded = false; - Span alphaData = Span.Empty; + Span alphaData = []; IMemoryOwner encodedAlphaData = null; try { diff --git a/src/ImageSharp/Formats/Webp/Lossy/WebpLossyDecoder.cs b/src/ImageSharp/Formats/Webp/Lossy/WebpLossyDecoder.cs index 3eb03b1724..65d5b65e88 100644 --- a/src/ImageSharp/Formats/Webp/Lossy/WebpLossyDecoder.cs +++ b/src/ImageSharp/Formats/Webp/Lossy/WebpLossyDecoder.cs @@ -140,7 +140,6 @@ private void DecodePixelValues(int width, int height, Span pixelDa private static void DecodePixelValues(int width, int height, Span pixelData, Buffer2D decodedPixels, IMemoryOwner alpha) where TPixel : unmanaged, IPixel { - TPixel color = default; Span alphaSpan = alpha.Memory.Span; Span pixelsBgr = MemoryMarshal.Cast(pixelData); for (int y = 0; y < height; y++) @@ -151,8 +150,7 @@ private static void DecodePixelValues(int width, int height, Span { int offset = yMulWidth + x; Bgr24 bgr = pixelsBgr[offset]; - color.FromBgra32(new Bgra32(bgr.R, bgr.G, bgr.B, alphaSpan[offset])); - decodedPixelRow[x] = color; + decodedPixelRow[x] = TPixel.FromBgra32(new(bgr.R, bgr.G, bgr.B, alphaSpan[offset])); } } } diff --git a/src/ImageSharp/Formats/Webp/MetadataExtensions.cs b/src/ImageSharp/Formats/Webp/MetadataExtensions.cs deleted file mode 100644 index 731d3f1ff2..0000000000 --- a/src/ImageSharp/Formats/Webp/MetadataExtensions.cs +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Diagnostics.CodeAnalysis; -using SixLabors.ImageSharp.Formats; -using SixLabors.ImageSharp.Formats.Webp; -using SixLabors.ImageSharp.Metadata; - -namespace SixLabors.ImageSharp; - -/// -/// Extension methods for the type. -/// -public static partial class MetadataExtensions -{ - /// - /// Gets the webp format specific metadata for the image. - /// - /// The metadata this method extends. - /// The . - public static WebpMetadata GetWebpMetadata(this ImageMetadata metadata) => metadata.GetFormatMetadata(WebpFormat.Instance); - - /// - /// Gets the webp format specific metadata for the image. - /// - /// The metadata this method extends. - /// The metadata. - /// - /// if the webp metadata exists; otherwise, . - /// - public static bool TryGetWebpMetadata(this ImageMetadata source, [NotNullWhen(true)] out WebpMetadata? metadata) - => source.TryGetFormatMetadata(WebpFormat.Instance, out metadata); - - /// - /// Gets the webp format specific metadata for the image frame. - /// - /// The metadata this method extends. - /// The . - public static WebpFrameMetadata GetWebpMetadata(this ImageFrameMetadata metadata) => metadata.GetFormatMetadata(WebpFormat.Instance); - - /// - /// Gets the webp format specific metadata for the image frame. - /// - /// The metadata this method extends. - /// The metadata. - /// - /// if the webp frame metadata exists; otherwise, . - /// - public static bool TryGetWebpFrameMetadata(this ImageFrameMetadata source, [NotNullWhen(true)] out WebpFrameMetadata? metadata) - => source.TryGetFormatMetadata(WebpFormat.Instance, out metadata); - - internal static AnimatedImageMetadata ToAnimatedImageMetadata(this WebpMetadata source) - => new() - { - ColorTableMode = FrameColorTableMode.Global, - RepeatCount = source.RepeatCount, - BackgroundColor = source.BackgroundColor - }; - - internal static AnimatedImageFrameMetadata ToAnimatedImageFrameMetadata(this WebpFrameMetadata source) - => new() - { - ColorTableMode = FrameColorTableMode.Global, - Duration = TimeSpan.FromMilliseconds(source.FrameDelay), - DisposalMode = GetMode(source.DisposalMethod), - BlendMode = source.BlendMethod == WebpBlendMethod.Over ? FrameBlendMode.Over : FrameBlendMode.Source, - }; - - private static FrameDisposalMode GetMode(WebpDisposalMethod method) => method switch - { - WebpDisposalMethod.RestoreToBackground => FrameDisposalMode.RestoreToBackground, - WebpDisposalMethod.DoNotDispose => FrameDisposalMode.DoNotDispose, - _ => FrameDisposalMode.DoNotDispose, - }; -} diff --git a/src/ImageSharp/Common/Helpers/RiffHelper.cs b/src/ImageSharp/Formats/Webp/RiffHelper.cs similarity index 98% rename from src/ImageSharp/Common/Helpers/RiffHelper.cs rename to src/ImageSharp/Formats/Webp/RiffHelper.cs index 667a47fc94..b6318c7486 100644 --- a/src/ImageSharp/Common/Helpers/RiffHelper.cs +++ b/src/ImageSharp/Formats/Webp/RiffHelper.cs @@ -5,7 +5,7 @@ using System.Text; using SixLabors.ImageSharp.Formats.Webp.Chunks; -namespace SixLabors.ImageSharp.Common.Helpers; +namespace SixLabors.ImageSharp.Formats.Webp; internal static class RiffHelper { diff --git a/src/ImageSharp/Formats/Webp/WebpAnimationDecoder.cs b/src/ImageSharp/Formats/Webp/WebpAnimationDecoder.cs index 65f1a4da46..72405e480e 100644 --- a/src/ImageSharp/Formats/Webp/WebpAnimationDecoder.cs +++ b/src/ImageSharp/Formats/Webp/WebpAnimationDecoder.cs @@ -102,7 +102,7 @@ public Image Decode(BufferedReadStream stream, WebpFeatures feat { case WebpChunkType.FrameData: Color backgroundColor = this.backgroundColorHandling == BackgroundColorHandling.Ignore - ? new Color(new Bgra32(0, 0, 0, 0)) + ? Color.FromPixel(new Bgra32(0, 0, 0, 0)) : features.AnimationBackgroundColor!.Value; uint dataSize = this.ReadFrame(stream, ref image, ref previousFrame, width, height, backgroundColor); remainingBytes -= (int)dataSize; @@ -195,14 +195,14 @@ private uint ReadFrame(BufferedReadStream stream, ref Image? ima Rectangle regionRectangle = frameData.Bounds; - if (frameData.DisposalMethod is WebpDisposalMethod.RestoreToBackground) + if (frameData.DisposalMethod is FrameDisposalMode.RestoreToBackground) { this.RestoreToBackground(imageFrame, backgroundColor); } using Buffer2D decodedImageFrame = this.DecodeImageFrameData(frameData, webpInfo); - bool blend = previousFrame != null && frameData.BlendingMethod == WebpBlendMethod.Over; + bool blend = previousFrame != null && frameData.BlendingMethod == FrameBlendMode.Over; DrawDecodedImageFrameOnCanvas(decodedImageFrame, imageFrame, regionRectangle, blend); previousFrame = currentFrame ?? image.Frames.RootFrame; diff --git a/src/ImageSharp/Formats/Webp/WebpBitsPerPixel.cs b/src/ImageSharp/Formats/Webp/WebpBitsPerPixel.cs index 529c4bafb9..03717d852a 100644 --- a/src/ImageSharp/Formats/Webp/WebpBitsPerPixel.cs +++ b/src/ImageSharp/Formats/Webp/WebpBitsPerPixel.cs @@ -11,10 +11,10 @@ public enum WebpBitsPerPixel : short /// /// 24 bits per pixel. Each pixel consists of 3 bytes. /// - Pixel24 = 24, + Bit24 = 24, /// /// 32 bits per pixel. Each pixel consists of 4 bytes (an alpha channel is present). /// - Pixel32 = 32 + Bit32 = 32 } diff --git a/src/ImageSharp/Formats/Webp/WebpBlendMethod.cs b/src/ImageSharp/Formats/Webp/WebpBlendMethod.cs deleted file mode 100644 index f16f7650c7..0000000000 --- a/src/ImageSharp/Formats/Webp/WebpBlendMethod.cs +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -namespace SixLabors.ImageSharp.Formats.Webp; - -/// -/// Indicates how transparent pixels of the current frame are to be blended with corresponding pixels of the previous canvas. -/// -public enum WebpBlendMethod -{ - /// - /// Do not blend. After disposing of the previous frame, - /// render the current frame on the canvas by overwriting the rectangle covered by the current frame. - /// - Source = 0, - - /// - /// Use alpha blending. After disposing of the previous frame, render the current frame on the canvas using alpha-blending. - /// If the current frame does not have an alpha channel, assume alpha value of 255, effectively replacing the rectangle. - /// - Over = 1, -} diff --git a/src/ImageSharp/Formats/Webp/WebpChunkParsingUtils.cs b/src/ImageSharp/Formats/Webp/WebpChunkParsingUtils.cs index 839798b4d7..4ccaf65031 100644 --- a/src/ImageSharp/Formats/Webp/WebpChunkParsingUtils.cs +++ b/src/ImageSharp/Formats/Webp/WebpChunkParsingUtils.cs @@ -17,6 +17,10 @@ internal static class WebpChunkParsingUtils /// /// Reads the header of a lossy webp image. /// + /// The memory allocator. + /// The buffered read stream. + /// The scratch buffer to use while reading. + /// The webp features to parse. /// Information about this webp image. public static WebpImageInfo ReadVp8Header(MemoryAllocator memoryAllocator, BufferedReadStream stream, Span buffer, WebpFeatures features) { @@ -114,13 +118,15 @@ public static WebpImageInfo ReadVp8Header(MemoryAllocator memoryAllocator, Buffe Vp8BitReader bitReader = new(stream, remaining, memoryAllocator, partitionLength) { Remaining = remaining }; - return new WebpImageInfo + return new() { Width = width, Height = height, XScale = xScale, YScale = yScale, - BitsPerPixel = features?.Alpha == true ? WebpBitsPerPixel.Pixel32 : WebpBitsPerPixel.Pixel24, + + // Vp8 header can be parsed during the processing of the Vp8X header. + BitsPerPixel = features?.Alpha == true ? WebpBitsPerPixel.Bit32 : WebpBitsPerPixel.Bit24, IsLossless = false, Features = features, Vp8Profile = (sbyte)version, @@ -132,7 +138,10 @@ public static WebpImageInfo ReadVp8Header(MemoryAllocator memoryAllocator, Buffe /// /// Reads the header of a lossless webp image. /// - /// Information about this image. + /// The memory allocator. + /// The buffered read stream. + /// The scratch buffer to use while reading. + /// The webp features to parse. public static WebpImageInfo ReadVp8LHeader(MemoryAllocator memoryAllocator, BufferedReadStream stream, Span buffer, WebpFeatures features) { // VP8 data size. @@ -156,8 +165,8 @@ public static WebpImageInfo ReadVp8LHeader(MemoryAllocator memoryAllocator, Buff } // The alphaIsUsed flag should be set to 0 when all alpha values are 255 in the picture, and 1 otherwise. - // TODO: this flag value is not used yet - bool alphaIsUsed = bitReader.ReadBit(); + // Alpha may have already been set by the VP8X chunk. + features.Alpha |= bitReader.ReadBit(); // The next 3 bits are the version. The version number is a 3 bit code that must be set to 0. // Any other value should be treated as an error. @@ -167,11 +176,11 @@ public static WebpImageInfo ReadVp8LHeader(MemoryAllocator memoryAllocator, Buff WebpThrowHelper.ThrowNotSupportedException($"Unexpected version number {version} found in VP8L header"); } - return new WebpImageInfo + return new() { Width = width, Height = height, - BitsPerPixel = WebpBitsPerPixel.Pixel32, + BitsPerPixel = features.Alpha ? WebpBitsPerPixel.Bit32 : WebpBitsPerPixel.Bit24, IsLossless = true, Features = features, Vp8LBitReader = bitReader @@ -187,6 +196,9 @@ public static WebpImageInfo ReadVp8LHeader(MemoryAllocator memoryAllocator, Buff /// - An optional 'ALPH' chunk with alpha channel data. /// After the image header, image data will follow. After that optional image metadata chunks (EXIF and XMP) can follow. /// + /// The buffered read stream. + /// The scratch buffer to use while reading. + /// The webp features to parse. /// Information about this webp image. public static WebpImageInfo ReadVp8XHeader(BufferedReadStream stream, Span buffer, WebpFeatures features) { @@ -217,6 +229,7 @@ public static WebpImageInfo ReadVp8XHeader(BufferedReadStream stream, Span features.Animation = (imageFeatures & (1 << 1)) != 0; // 3 reserved bytes should follow which are supposed to be zero. + // No other decoder actually checks this though. stream.Read(buffer, 0, 3); // 3 bytes for the width. @@ -226,14 +239,14 @@ public static WebpImageInfo ReadVp8XHeader(BufferedReadStream stream, Span uint height = ReadUInt24LittleEndian(stream, buffer) + 1; // Read all the chunks in the order they occur. - WebpImageInfo info = new() + return new() { Width = width, Height = height, Features = features - }; - return info; + // Additional properties are set during the parsing of the VP8 or VP8L headers. + }; } /// diff --git a/src/ImageSharp/Formats/Webp/WebpColorType.cs b/src/ImageSharp/Formats/Webp/WebpColorType.cs new file mode 100644 index 0000000000..64d9143b1f --- /dev/null +++ b/src/ImageSharp/Formats/Webp/WebpColorType.cs @@ -0,0 +1,25 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +namespace SixLabors.ImageSharp.Formats.Webp; + +/// +/// Provides enumeration of the various webp color types. +/// +public enum WebpColorType +{ + /// + /// Yuv (luminance, blue chroma, red chroma) as defined in the ITU-R Rec. BT.709 specification. + /// + Yuv, + + /// + /// Rgb color space. + /// + Rgb, + + /// + /// Rgba color space. + /// + Rgba +} diff --git a/src/ImageSharp/Formats/Webp/WebpCommonUtils.cs b/src/ImageSharp/Formats/Webp/WebpCommonUtils.cs index 49482260bb..a1e9821c09 100644 --- a/src/ImageSharp/Formats/Webp/WebpCommonUtils.cs +++ b/src/ImageSharp/Formats/Webp/WebpCommonUtils.cs @@ -4,8 +4,6 @@ using System.Runtime.InteropServices; using System.Runtime.Intrinsics; using System.Runtime.Intrinsics.X86; -using SixLabors.ImageSharp.Formats.Gif; -using SixLabors.ImageSharp.Formats.Png; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Formats.Webp; @@ -15,54 +13,6 @@ namespace SixLabors.ImageSharp.Formats.Webp; /// internal static class WebpCommonUtils { - public static WebpMetadata GetWebpMetadata(Image image) - where TPixel : unmanaged, IPixel - { - if (image.Metadata.TryGetWebpMetadata(out WebpMetadata? webp)) - { - return (WebpMetadata)webp.DeepClone(); - } - - if (image.Metadata.TryGetGifMetadata(out GifMetadata? gif)) - { - AnimatedImageMetadata ani = gif.ToAnimatedImageMetadata(); - return WebpMetadata.FromAnimatedMetadata(ani); - } - - if (image.Metadata.TryGetPngMetadata(out PngMetadata? png)) - { - AnimatedImageMetadata ani = png.ToAnimatedImageMetadata(); - return WebpMetadata.FromAnimatedMetadata(ani); - } - - // Return explicit new instance so we do not mutate the original metadata. - return new(); - } - - public static WebpFrameMetadata GetWebpFrameMetadata(ImageFrame frame) - where TPixel : unmanaged, IPixel - { - if (frame.Metadata.TryGetWebpFrameMetadata(out WebpFrameMetadata? webp)) - { - return (WebpFrameMetadata)webp.DeepClone(); - } - - if (frame.Metadata.TryGetGifMetadata(out GifFrameMetadata? gif)) - { - AnimatedImageFrameMetadata ani = gif.ToAnimatedImageFrameMetadata(); - return WebpFrameMetadata.FromAnimatedMetadata(ani); - } - - if (frame.Metadata.TryGetPngMetadata(out PngFrameMetadata? png)) - { - AnimatedImageFrameMetadata ani = png.ToAnimatedImageFrameMetadata(); - return WebpFrameMetadata.FromAnimatedMetadata(ani); - } - - // Return explicit new instance so we do not mutate the original metadata. - return new(); - } - /// /// Checks if the pixel row is not opaque. /// diff --git a/src/ImageSharp/Formats/Webp/WebpDecoderCore.cs b/src/ImageSharp/Formats/Webp/WebpDecoderCore.cs index 781b8246ff..9ca6e2bee3 100644 --- a/src/ImageSharp/Formats/Webp/WebpDecoderCore.cs +++ b/src/ImageSharp/Formats/Webp/WebpDecoderCore.cs @@ -137,7 +137,6 @@ protected override ImageInfo Identify(BufferedReadStream stream, CancellationTok using (this.webImageInfo = this.ReadVp8Info(stream, metadata, true)) { return new ImageInfo( - new PixelTypeInfo((int)this.webImageInfo.BitsPerPixel), new Size((int)this.webImageInfo.Width, (int)this.webImageInfo.Height), metadata); } @@ -179,39 +178,43 @@ private WebpImageInfo ReadVp8Info(BufferedReadStream stream, ImageMetadata metad Span buffer = stackalloc byte[4]; WebpChunkType chunkType = WebpChunkParsingUtils.ReadChunkType(stream, buffer); - WebpImageInfo webpImageInfo; + WebpImageInfo? info = null; WebpFeatures features = new(); switch (chunkType) { case WebpChunkType.Vp8: + info = WebpChunkParsingUtils.ReadVp8Header(this.memoryAllocator, stream, buffer, features); webpMetadata.FileFormat = WebpFileFormatType.Lossy; - webpImageInfo = WebpChunkParsingUtils.ReadVp8Header(this.memoryAllocator, stream, buffer, features); - break; + webpMetadata.ColorType = WebpColorType.Yuv; + return info; case WebpChunkType.Vp8L: + info = WebpChunkParsingUtils.ReadVp8LHeader(this.memoryAllocator, stream, buffer, features); webpMetadata.FileFormat = WebpFileFormatType.Lossless; - webpImageInfo = WebpChunkParsingUtils.ReadVp8LHeader(this.memoryAllocator, stream, buffer, features); - break; + webpMetadata.ColorType = info.Features?.Alpha == true ? WebpColorType.Rgba : WebpColorType.Rgb; + return info; case WebpChunkType.Vp8X: - webpImageInfo = WebpChunkParsingUtils.ReadVp8XHeader(stream, buffer, features); + info = WebpChunkParsingUtils.ReadVp8XHeader(stream, buffer, features); while (stream.Position < stream.Length) { chunkType = WebpChunkParsingUtils.ReadChunkType(stream, buffer); if (chunkType == WebpChunkType.Vp8) { + info = WebpChunkParsingUtils.ReadVp8Header(this.memoryAllocator, stream, buffer, features); webpMetadata.FileFormat = WebpFileFormatType.Lossy; - webpImageInfo = WebpChunkParsingUtils.ReadVp8Header(this.memoryAllocator, stream, buffer, features); + webpMetadata.ColorType = info.Features?.Alpha == true ? WebpColorType.Rgba : WebpColorType.Rgb; } else if (chunkType == WebpChunkType.Vp8L) { + info = WebpChunkParsingUtils.ReadVp8LHeader(this.memoryAllocator, stream, buffer, features); webpMetadata.FileFormat = WebpFileFormatType.Lossless; - webpImageInfo = WebpChunkParsingUtils.ReadVp8LHeader(this.memoryAllocator, stream, buffer, features); + webpMetadata.ColorType = info.Features?.Alpha == true ? WebpColorType.Rgba : WebpColorType.Rgb; } else if (WebpChunkParsingUtils.IsOptionalVp8XChunk(chunkType)) { bool isAnimationChunk = this.ParseOptionalExtendedChunks(stream, metadata, chunkType, features, ignoreAlpha, buffer); if (isAnimationChunk) { - break; + return info; } } else @@ -222,17 +225,12 @@ private WebpImageInfo ReadVp8Info(BufferedReadStream stream, ImageMetadata metad } } - break; + return info; default: WebpThrowHelper.ThrowImageFormatException("Unrecognized VP8 header"); - - // This return will never be reached, because throw helper will throw an exception. - webpImageInfo = new(); - break; + return + new WebpImageInfo(); // this return will never be reached, because throw helper will throw an exception. } - - this.Dimensions = new Size((int)webpImageInfo.Width, (int)webpImageInfo.Height); - return webpImageInfo; } /// @@ -439,7 +437,7 @@ private static void ReadAnimationParameters(BufferedReadStream stream, WebpFeatu byte green = (byte)stream.ReadByte(); byte red = (byte)stream.ReadByte(); byte alpha = (byte)stream.ReadByte(); - features.AnimationBackgroundColor = new Color(new Rgba32(red, green, blue, alpha)); + features.AnimationBackgroundColor = Color.FromPixel(new Rgba32(red, green, blue, alpha)); int bytesRead = stream.Read(buffer, 0, 2); if (bytesRead != 2) { diff --git a/src/ImageSharp/Formats/Webp/WebpDisposalMethod.cs b/src/ImageSharp/Formats/Webp/WebpDisposalMethod.cs deleted file mode 100644 index 47cc83951d..0000000000 --- a/src/ImageSharp/Formats/Webp/WebpDisposalMethod.cs +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -namespace SixLabors.ImageSharp.Formats.Webp; - -/// -/// Indicates how the current frame is to be treated after it has been displayed (before rendering the next frame) on the canvas. -/// -public enum WebpDisposalMethod -{ - /// - /// Do not dispose. Leave the canvas as is. - /// - DoNotDispose = 0, - - /// - /// Dispose to background color. Fill the rectangle on the canvas covered by the current frame with background color specified in the ANIM chunk. - /// - RestoreToBackground = 1 -} diff --git a/src/ImageSharp/Formats/Webp/WebpEncoderCore.cs b/src/ImageSharp/Formats/Webp/WebpEncoderCore.cs index 5d904380bf..e37462fda4 100644 --- a/src/ImageSharp/Formats/Webp/WebpEncoderCore.cs +++ b/src/ImageSharp/Formats/Webp/WebpEncoderCore.cs @@ -5,6 +5,7 @@ using SixLabors.ImageSharp.Formats.Webp.Lossless; using SixLabors.ImageSharp.Formats.Webp.Lossy; using SixLabors.ImageSharp.Memory; +using SixLabors.ImageSharp.Metadata; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Formats.Webp; @@ -124,7 +125,7 @@ public void Encode(Image image, Stream stream, CancellationToken } else { - WebpMetadata webpMetadata = WebpCommonUtils.GetWebpMetadata(image); + WebpMetadata webpMetadata = image.Metadata.GetWebpMetadata(); lossless = webpMetadata.FileFormat == WebpFileFormatType.Lossless; } @@ -150,12 +151,12 @@ public void Encode(Image image, Stream stream, CancellationToken // Encode the first frame. ImageFrame previousFrame = image.Frames.RootFrame; - WebpFrameMetadata frameMetadata = WebpCommonUtils.GetWebpFrameMetadata(previousFrame); + WebpFrameMetadata frameMetadata = previousFrame.Metadata.GetWebpMetadata(); hasAlpha |= encoder.Encode(previousFrame, previousFrame.Bounds(), frameMetadata, stream, hasAnimation); if (hasAnimation) { - WebpDisposalMethod previousDisposal = frameMetadata.DisposalMethod; + FrameDisposalMode previousDisposal = frameMetadata.DisposalMethod; // Encode additional frames // This frame is reused to store de-duplicated pixel buffers. @@ -163,12 +164,12 @@ public void Encode(Image image, Stream stream, CancellationToken for (int i = 1; i < image.Frames.Count; i++) { - ImageFrame? prev = previousDisposal == WebpDisposalMethod.RestoreToBackground ? null : previousFrame; + ImageFrame? prev = previousDisposal == FrameDisposalMode.RestoreToBackground ? null : previousFrame; ImageFrame currentFrame = image.Frames[i]; ImageFrame? nextFrame = i < image.Frames.Count - 1 ? image.Frames[i + 1] : null; - frameMetadata = WebpCommonUtils.GetWebpFrameMetadata(currentFrame); - bool blend = frameMetadata.BlendMethod == WebpBlendMethod.Over; + frameMetadata = currentFrame.Metadata.GetWebpMetadata(); + bool blend = frameMetadata.BlendMethod == FrameBlendMode.Over; (bool difference, Rectangle bounds) = AnimationUtilities.DeDuplicatePixels( @@ -227,8 +228,8 @@ public void Encode(Image image, Stream stream, CancellationToken // Encode the first frame. ImageFrame previousFrame = image.Frames.RootFrame; - WebpFrameMetadata frameMetadata = WebpCommonUtils.GetWebpFrameMetadata(previousFrame); - WebpDisposalMethod previousDisposal = frameMetadata.DisposalMethod; + WebpFrameMetadata frameMetadata = previousFrame.Metadata.GetWebpMetadata(); + FrameDisposalMode previousDisposal = frameMetadata.DisposalMethod; hasAlpha |= encoder.EncodeAnimation(previousFrame, stream, previousFrame.Bounds(), frameMetadata); @@ -238,12 +239,12 @@ public void Encode(Image image, Stream stream, CancellationToken for (int i = 1; i < image.Frames.Count; i++) { - ImageFrame? prev = previousDisposal == WebpDisposalMethod.RestoreToBackground ? null : previousFrame; + ImageFrame? prev = previousDisposal == FrameDisposalMode.RestoreToBackground ? null : previousFrame; ImageFrame currentFrame = image.Frames[i]; ImageFrame? nextFrame = i < image.Frames.Count - 1 ? image.Frames[i + 1] : null; - frameMetadata = WebpCommonUtils.GetWebpFrameMetadata(currentFrame); - bool blend = frameMetadata.BlendMethod == WebpBlendMethod.Over; + frameMetadata = currentFrame.Metadata.GetWebpMetadata(); + bool blend = frameMetadata.BlendMethod == FrameBlendMode.Over; (bool difference, Rectangle bounds) = AnimationUtilities.DeDuplicatePixels( diff --git a/src/ImageSharp/Formats/Webp/WebpFileFormatType.cs b/src/ImageSharp/Formats/Webp/WebpFileFormatType.cs index 1ed9bbb431..6f606cdf46 100644 --- a/src/ImageSharp/Formats/Webp/WebpFileFormatType.cs +++ b/src/ImageSharp/Formats/Webp/WebpFileFormatType.cs @@ -9,12 +9,12 @@ namespace SixLabors.ImageSharp.Formats.Webp; public enum WebpFileFormatType { /// - /// The lossless webp format. + /// The lossless Webp format, which compresses data without any loss of information. /// Lossless, /// - /// The lossy webp format. + /// The lossy Webp format, which compresses data by discarding some of it. /// Lossy, } diff --git a/src/ImageSharp/Formats/Webp/WebpFormat.cs b/src/ImageSharp/Formats/Webp/WebpFormat.cs index 197041234e..1764182c51 100644 --- a/src/ImageSharp/Formats/Webp/WebpFormat.cs +++ b/src/ImageSharp/Formats/Webp/WebpFormat.cs @@ -18,7 +18,7 @@ private WebpFormat() public static WebpFormat Instance { get; } = new WebpFormat(); /// - public string Name => "Webp"; + public string Name => "WEBP"; /// public string DefaultMimeType => "image/webp"; diff --git a/src/ImageSharp/Formats/Webp/WebpFrameMetadata.cs b/src/ImageSharp/Formats/Webp/WebpFrameMetadata.cs index cd1b5d5905..45e182d223 100644 --- a/src/ImageSharp/Formats/Webp/WebpFrameMetadata.cs +++ b/src/ImageSharp/Formats/Webp/WebpFrameMetadata.cs @@ -6,7 +6,7 @@ namespace SixLabors.ImageSharp.Formats.Webp; /// /// Provides webp specific metadata information for the image frame. /// -public class WebpFrameMetadata : IDeepCloneable +public class WebpFrameMetadata : IFormatFrameMetadata { /// /// Initializes a new instance of the class. @@ -29,12 +29,12 @@ private WebpFrameMetadata(WebpFrameMetadata other) /// /// Gets or sets how transparent pixels of the current frame are to be blended with corresponding pixels of the previous canvas. /// - public WebpBlendMethod BlendMethod { get; set; } + public FrameBlendMode BlendMethod { get; set; } /// /// Gets or sets how the current frame is to be treated after it has been displayed (before rendering the next frame) on the canvas. /// - public WebpDisposalMethod DisposalMethod { get; set; } + public FrameDisposalMode DisposalMethod { get; set; } /// /// Gets or sets the frame duration. The time to wait before displaying the next frame, @@ -43,13 +43,34 @@ private WebpFrameMetadata(WebpFrameMetadata other) public uint FrameDelay { get; set; } /// - public IDeepCloneable DeepClone() => new WebpFrameMetadata(this); - - internal static WebpFrameMetadata FromAnimatedMetadata(AnimatedImageFrameMetadata metadata) + public static WebpFrameMetadata FromFormatConnectingFrameMetadata(FormatConnectingFrameMetadata metadata) => new() { FrameDelay = (uint)metadata.Duration.TotalMilliseconds, - BlendMethod = metadata.BlendMode == FrameBlendMode.Source ? WebpBlendMethod.Source : WebpBlendMethod.Over, - DisposalMethod = metadata.DisposalMode == FrameDisposalMode.RestoreToBackground ? WebpDisposalMethod.RestoreToBackground : WebpDisposalMethod.DoNotDispose + BlendMethod = metadata.BlendMode, + DisposalMethod = GetMode(metadata.DisposalMode) + }; + + /// + public FormatConnectingFrameMetadata ToFormatConnectingFrameMetadata() + => new() + { + ColorTableMode = FrameColorTableMode.Global, + Duration = TimeSpan.FromMilliseconds(this.FrameDelay), + DisposalMode = this.DisposalMethod, + BlendMode = this.BlendMethod, }; + + /// + IDeepCloneable IDeepCloneable.DeepClone() => this.DeepClone(); + + /// + public WebpFrameMetadata DeepClone() => new(this); + + private static FrameDisposalMode GetMode(FrameDisposalMode mode) => mode switch + { + FrameDisposalMode.RestoreToBackground => FrameDisposalMode.RestoreToBackground, + FrameDisposalMode.DoNotDispose => FrameDisposalMode.DoNotDispose, + _ => FrameDisposalMode.DoNotDispose, + }; } diff --git a/src/ImageSharp/Formats/Webp/WebpImageInfo.cs b/src/ImageSharp/Formats/Webp/WebpImageInfo.cs index 5f7301b262..3428ce199a 100644 --- a/src/ImageSharp/Formats/Webp/WebpImageInfo.cs +++ b/src/ImageSharp/Formats/Webp/WebpImageInfo.cs @@ -18,8 +18,14 @@ internal class WebpImageInfo : IDisposable /// public uint Height { get; set; } + /// + /// Gets or sets the horizontal scale. + /// public sbyte XScale { get; set; } + /// + /// Gets or sets the vertical scale. + /// public sbyte YScale { get; set; } /// diff --git a/src/ImageSharp/Formats/Webp/WebpMetadata.cs b/src/ImageSharp/Formats/Webp/WebpMetadata.cs index 536ea09294..33ebbbf6dc 100644 --- a/src/ImageSharp/Formats/Webp/WebpMetadata.cs +++ b/src/ImageSharp/Formats/Webp/WebpMetadata.cs @@ -1,12 +1,14 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. +using SixLabors.ImageSharp.PixelFormats; + namespace SixLabors.ImageSharp.Formats.Webp; /// /// Provides Webp specific metadata information for the image. /// -public class WebpMetadata : IDeepCloneable +public class WebpMetadata : IFormatMetadata { /// /// Initializes a new instance of the class. @@ -21,15 +23,27 @@ public WebpMetadata() /// The metadata to create an instance from. private WebpMetadata(WebpMetadata other) { + this.BitsPerPixel = other.BitsPerPixel; + this.ColorType = other.ColorType; this.FileFormat = other.FileFormat; this.RepeatCount = other.RepeatCount; this.BackgroundColor = other.BackgroundColor; } + /// + /// Gets or sets the number of bits per pixel. + /// + public WebpBitsPerPixel BitsPerPixel { get; set; } = WebpBitsPerPixel.Bit32; + + /// + /// Gets or sets the color type. + /// + public WebpColorType ColorType { get; set; } = WebpColorType.Rgba; + /// /// Gets or sets the webp file format used. Either lossless or lossy. /// - public WebpFileFormatType? FileFormat { get; set; } + public WebpFileFormatType FileFormat { get; set; } = WebpFileFormatType.Lossy; /// /// Gets or sets the loop count. The number of times to loop the animation. 0 means infinitely. @@ -40,18 +54,100 @@ private WebpMetadata(WebpMetadata other) /// Gets or sets the default background color of the canvas when animating. /// This color may be used to fill the unused space on the canvas around the frames, /// as well as the transparent pixels of the first frame. - /// The background color is also used when the Disposal method is . + /// The background color is also used when the Disposal method is . /// public Color BackgroundColor { get; set; } /// - public IDeepCloneable DeepClone() => new WebpMetadata(this); + public static WebpMetadata FromFormatConnectingMetadata(FormatConnectingMetadata metadata) + { + WebpBitsPerPixel bitsPerPixel; + WebpColorType color; + PixelColorType colorType = metadata.PixelTypeInfo.ColorType; + switch (colorType) + { + case PixelColorType.RGB: + case PixelColorType.BGR: + color = WebpColorType.Rgb; + bitsPerPixel = WebpBitsPerPixel.Bit24; + break; + case PixelColorType.YCbCr: + color = WebpColorType.Yuv; + bitsPerPixel = WebpBitsPerPixel.Bit24; + break; + default: + if (colorType.HasFlag(PixelColorType.Alpha)) + { + color = WebpColorType.Rgba; + bitsPerPixel = WebpBitsPerPixel.Bit32; + break; + } - internal static WebpMetadata FromAnimatedMetadata(AnimatedImageMetadata metadata) - => new() + color = WebpColorType.Rgb; + bitsPerPixel = WebpBitsPerPixel.Bit24; + break; + } + + return new() { - FileFormat = WebpFileFormatType.Lossless, + BitsPerPixel = bitsPerPixel, + ColorType = color, BackgroundColor = metadata.BackgroundColor, - RepeatCount = metadata.RepeatCount + RepeatCount = metadata.RepeatCount, + FileFormat = metadata.EncodingType == EncodingType.Lossless ? WebpFileFormatType.Lossless : WebpFileFormatType.Lossy }; + } + + /// + public PixelTypeInfo GetPixelTypeInfo() + { + int bpp; + PixelColorType colorType; + PixelAlphaRepresentation alpha = PixelAlphaRepresentation.None; + PixelComponentInfo info; + switch (this.ColorType) + { + case WebpColorType.Yuv: + bpp = 24; + colorType = PixelColorType.YCbCr; + info = PixelComponentInfo.Create(3, bpp, 8, 8, 8); + break; + case WebpColorType.Rgb: + bpp = 24; + colorType = PixelColorType.RGB; + info = PixelComponentInfo.Create(3, bpp, 8, 8, 8); + break; + case WebpColorType.Rgba: + default: + bpp = 32; + colorType = PixelColorType.RGB | PixelColorType.Alpha; + info = PixelComponentInfo.Create(4, bpp, 8, 8, 8, 8); + alpha = PixelAlphaRepresentation.Unassociated; + break; + } + + return new PixelTypeInfo(bpp) + { + AlphaRepresentation = alpha, + ColorType = colorType, + ComponentInfo = info, + }; + } + + /// + public FormatConnectingMetadata ToFormatConnectingMetadata() + => new() + { + EncodingType = this.FileFormat == WebpFileFormatType.Lossless ? EncodingType.Lossless : EncodingType.Lossy, + PixelTypeInfo = this.GetPixelTypeInfo(), + ColorTableMode = FrameColorTableMode.Global, + RepeatCount = this.RepeatCount, + BackgroundColor = this.BackgroundColor + }; + + /// + IDeepCloneable IDeepCloneable.DeepClone() => this.DeepClone(); + + /// + public WebpMetadata DeepClone() => new(this); } diff --git a/src/ImageSharp/Formats/ImageExtensions.Save.cs b/src/ImageSharp/Formats/_Generated/ImageExtensions.Save.cs similarity index 81% rename from src/ImageSharp/Formats/ImageExtensions.Save.cs rename to src/ImageSharp/Formats/_Generated/ImageExtensions.Save.cs index 7e5989d6fc..73d1145883 100644 --- a/src/ImageSharp/Formats/ImageExtensions.Save.cs +++ b/src/ImageSharp/Formats/_Generated/ImageExtensions.Save.cs @@ -2,10 +2,10 @@ // Licensed under the Six Labors Split License. // -using SixLabors.ImageSharp.Advanced; - using SixLabors.ImageSharp.Formats.Bmp; +using SixLabors.ImageSharp.Formats.Cur; using SixLabors.ImageSharp.Formats.Gif; +using SixLabors.ImageSharp.Formats.Ico; using SixLabors.ImageSharp.Formats.Jpeg; using SixLabors.ImageSharp.Formats.Pbm; using SixLabors.ImageSharp.Formats.Png; @@ -123,6 +123,108 @@ public static Task SaveAsBmpAsync(this Image source, Stream stream, BmpEncoder e encoder ?? source.Configuration.ImageFormatsManager.GetEncoder(BmpFormat.Instance), cancellationToken); + /// + /// Saves the image to the given stream with the Cur format. + /// + /// The image this method extends. + /// The file path to save the image to. + /// Thrown if the path is null. + public static void SaveAsCur(this Image source, string path) => SaveAsCur(source, path, default); + + /// + /// Saves the image to the given stream with the Cur format. + /// + /// The image this method extends. + /// The file path to save the image to. + /// Thrown if the path is null. + /// A representing the asynchronous operation. + public static Task SaveAsCurAsync(this Image source, string path) => SaveAsCurAsync(source, path, default); + + /// + /// Saves the image to the given stream with the Cur format. + /// + /// The image this method extends. + /// The file path to save the image to. + /// The token to monitor for cancellation requests. + /// Thrown if the path is null. + /// A representing the asynchronous operation. + public static Task SaveAsCurAsync(this Image source, string path, CancellationToken cancellationToken) + => SaveAsCurAsync(source, path, default, cancellationToken); + + /// + /// Saves the image to the given stream with the Cur format. + /// + /// The image this method extends. + /// The file path to save the image to. + /// The encoder to save the image with. + /// Thrown if the path is null. + public static void SaveAsCur(this Image source, string path, CurEncoder encoder) => + source.Save( + path, + encoder ?? source.Configuration.ImageFormatsManager.GetEncoder(CurFormat.Instance)); + + /// + /// Saves the image to the given stream with the Cur format. + /// + /// The image this method extends. + /// The file path to save the image to. + /// The encoder to save the image with. + /// The token to monitor for cancellation requests. + /// Thrown if the path is null. + /// A representing the asynchronous operation. + public static Task SaveAsCurAsync(this Image source, string path, CurEncoder encoder, CancellationToken cancellationToken = default) + => source.SaveAsync( + path, + encoder ?? source.Configuration.ImageFormatsManager.GetEncoder(CurFormat.Instance), + cancellationToken); + + /// + /// Saves the image to the given stream with the Cur format. + /// + /// The image this method extends. + /// The stream to save the image to. + /// Thrown if the stream is null. + public static void SaveAsCur(this Image source, Stream stream) + => SaveAsCur(source, stream, default); + + /// + /// Saves the image to the given stream with the Cur format. + /// + /// The image this method extends. + /// The stream to save the image to. + /// The token to monitor for cancellation requests. + /// Thrown if the stream is null. + /// A representing the asynchronous operation. + public static Task SaveAsCurAsync(this Image source, Stream stream, CancellationToken cancellationToken = default) + => SaveAsCurAsync(source, stream, default, cancellationToken); + + /// + /// Saves the image to the given stream with the Cur format. + /// + /// The image this method extends. + /// The stream to save the image to. + /// The encoder to save the image with. + /// Thrown if the stream is null. + public static void SaveAsCur(this Image source, Stream stream, CurEncoder encoder) + => source.Save( + stream, + encoder ?? source.Configuration.ImageFormatsManager.GetEncoder(CurFormat.Instance)); + + /// + /// Saves the image to the given stream with the Cur format. + /// + /// The image this method extends. + /// The stream to save the image to. + /// The encoder to save the image with. + /// The token to monitor for cancellation requests. + /// Thrown if the stream is null. + /// A representing the asynchronous operation. + public static Task SaveAsCurAsync(this Image source, Stream stream, CurEncoder encoder, CancellationToken cancellationToken = default) + => source.SaveAsync( + stream, + encoder ?? source.Configuration.ImageFormatsManager.GetEncoder(CurFormat.Instance), + cancellationToken); + /// /// Saves the image to the given stream with the Gif format. /// @@ -225,6 +327,108 @@ public static Task SaveAsGifAsync(this Image source, Stream stream, GifEncoder e encoder ?? source.Configuration.ImageFormatsManager.GetEncoder(GifFormat.Instance), cancellationToken); + /// + /// Saves the image to the given stream with the Ico format. + /// + /// The image this method extends. + /// The file path to save the image to. + /// Thrown if the path is null. + public static void SaveAsIco(this Image source, string path) => SaveAsIco(source, path, default); + + /// + /// Saves the image to the given stream with the Ico format. + /// + /// The image this method extends. + /// The file path to save the image to. + /// Thrown if the path is null. + /// A representing the asynchronous operation. + public static Task SaveAsIcoAsync(this Image source, string path) => SaveAsIcoAsync(source, path, default); + + /// + /// Saves the image to the given stream with the Ico format. + /// + /// The image this method extends. + /// The file path to save the image to. + /// The token to monitor for cancellation requests. + /// Thrown if the path is null. + /// A representing the asynchronous operation. + public static Task SaveAsIcoAsync(this Image source, string path, CancellationToken cancellationToken) + => SaveAsIcoAsync(source, path, default, cancellationToken); + + /// + /// Saves the image to the given stream with the Ico format. + /// + /// The image this method extends. + /// The file path to save the image to. + /// The encoder to save the image with. + /// Thrown if the path is null. + public static void SaveAsIco(this Image source, string path, IcoEncoder encoder) => + source.Save( + path, + encoder ?? source.Configuration.ImageFormatsManager.GetEncoder(IcoFormat.Instance)); + + /// + /// Saves the image to the given stream with the Ico format. + /// + /// The image this method extends. + /// The file path to save the image to. + /// The encoder to save the image with. + /// The token to monitor for cancellation requests. + /// Thrown if the path is null. + /// A representing the asynchronous operation. + public static Task SaveAsIcoAsync(this Image source, string path, IcoEncoder encoder, CancellationToken cancellationToken = default) + => source.SaveAsync( + path, + encoder ?? source.Configuration.ImageFormatsManager.GetEncoder(IcoFormat.Instance), + cancellationToken); + + /// + /// Saves the image to the given stream with the Ico format. + /// + /// The image this method extends. + /// The stream to save the image to. + /// Thrown if the stream is null. + public static void SaveAsIco(this Image source, Stream stream) + => SaveAsIco(source, stream, default); + + /// + /// Saves the image to the given stream with the Ico format. + /// + /// The image this method extends. + /// The stream to save the image to. + /// The token to monitor for cancellation requests. + /// Thrown if the stream is null. + /// A representing the asynchronous operation. + public static Task SaveAsIcoAsync(this Image source, Stream stream, CancellationToken cancellationToken = default) + => SaveAsIcoAsync(source, stream, default, cancellationToken); + + /// + /// Saves the image to the given stream with the Ico format. + /// + /// The image this method extends. + /// The stream to save the image to. + /// The encoder to save the image with. + /// Thrown if the stream is null. + public static void SaveAsIco(this Image source, Stream stream, IcoEncoder encoder) + => source.Save( + stream, + encoder ?? source.Configuration.ImageFormatsManager.GetEncoder(IcoFormat.Instance)); + + /// + /// Saves the image to the given stream with the Ico format. + /// + /// The image this method extends. + /// The stream to save the image to. + /// The encoder to save the image with. + /// The token to monitor for cancellation requests. + /// Thrown if the stream is null. + /// A representing the asynchronous operation. + public static Task SaveAsIcoAsync(this Image source, Stream stream, IcoEncoder encoder, CancellationToken cancellationToken = default) + => source.SaveAsync( + stream, + encoder ?? source.Configuration.ImageFormatsManager.GetEncoder(IcoFormat.Instance), + cancellationToken); + /// /// Saves the image to the given stream with the Jpeg format. /// diff --git a/src/ImageSharp/Formats/ImageExtensions.Save.tt b/src/ImageSharp/Formats/_Generated/ImageExtensions.Save.tt similarity index 95% rename from src/ImageSharp/Formats/ImageExtensions.Save.tt rename to src/ImageSharp/Formats/_Generated/ImageExtensions.Save.tt index d4f1ed233b..144dd83625 100644 --- a/src/ImageSharp/Formats/ImageExtensions.Save.tt +++ b/src/ImageSharp/Formats/_Generated/ImageExtensions.Save.tt @@ -1,25 +1,8 @@ -<#@ template language="C#" #> +<#@include file="_Formats.ttinclude" #> <#@ import namespace="System.Text" #> <#@ import namespace="System.Collections.Generic" #> -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - // -using SixLabors.ImageSharp.Advanced; - <# - var formats = new []{ - "Bmp", - "Gif", - "Jpeg", - "Pbm", - "Png", - "Qoi", - "Tga", - "Tiff", - "Webp", - }; - foreach (string fmt in formats) { #> diff --git a/src/ImageSharp/Formats/_Generated/ImageMetadataExtensions.cs b/src/ImageSharp/Formats/_Generated/ImageMetadataExtensions.cs new file mode 100644 index 0000000000..e35d00ed39 --- /dev/null +++ b/src/ImageSharp/Formats/_Generated/ImageMetadataExtensions.cs @@ -0,0 +1,365 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +// +using SixLabors.ImageSharp.Metadata; +using SixLabors.ImageSharp.Formats.Bmp; +using SixLabors.ImageSharp.Formats.Cur; +using SixLabors.ImageSharp.Formats.Gif; +using SixLabors.ImageSharp.Formats.Ico; +using SixLabors.ImageSharp.Formats.Jpeg; +using SixLabors.ImageSharp.Formats.Pbm; +using SixLabors.ImageSharp.Formats.Png; +using SixLabors.ImageSharp.Formats.Qoi; +using SixLabors.ImageSharp.Formats.Tga; +using SixLabors.ImageSharp.Formats.Tiff; +using SixLabors.ImageSharp.Formats.Webp; + +namespace SixLabors.ImageSharp; + +/// +/// Extension methods for the and types. +/// +public static class ImageMetadataExtensions +{ + /// + /// Gets the from .
+ /// If none is found, an instance is created either by conversion from the decoded image format metadata + /// or the requested format default constructor. + /// This instance will be added to the metadata for future requests. + ///
+ /// The image metadata. + /// + /// The + /// + public static BmpMetadata GetBmpMetadata(this ImageMetadata source) => source.GetFormatMetadata(BmpFormat.Instance); + + /// + /// Creates a new cloned instance of from the . + /// The instance is created via + /// + /// The image metadata. + /// The new + public static BmpMetadata CloneBmpMetadata(this ImageMetadata source) => source.CloneFormatMetadata(BmpFormat.Instance); + + /// + /// Gets the from .
+ /// If none is found, an instance is created either by conversion from the decoded image format metadata + /// or the requested format default constructor. + /// This instance will be added to the metadata for future requests. + ///
+ /// The image metadata. + /// + /// The + /// + public static CurMetadata GetCurMetadata(this ImageMetadata source) => source.GetFormatMetadata(CurFormat.Instance); + + /// + /// Creates a new cloned instance of from the . + /// The instance is created via + /// + /// The image metadata. + /// The new + public static CurMetadata CloneCurMetadata(this ImageMetadata source) => source.CloneFormatMetadata(CurFormat.Instance); + + /// + /// Gets the from .
+ /// If none is found, an instance is created either by conversion from the decoded image format metadata + /// or the requested format default constructor. + /// This instance will be added to the metadata for future requests. + ///
+ /// The image metadata. + /// + /// The + /// + public static GifMetadata GetGifMetadata(this ImageMetadata source) => source.GetFormatMetadata(GifFormat.Instance); + + /// + /// Creates a new cloned instance of from the . + /// The instance is created via + /// + /// The image metadata. + /// The new + public static GifMetadata CloneGifMetadata(this ImageMetadata source) => source.CloneFormatMetadata(GifFormat.Instance); + + /// + /// Gets the from .
+ /// If none is found, an instance is created either by conversion from the decoded image format metadata + /// or the requested format default constructor. + /// This instance will be added to the metadata for future requests. + ///
+ /// The image metadata. + /// + /// The + /// + public static IcoMetadata GetIcoMetadata(this ImageMetadata source) => source.GetFormatMetadata(IcoFormat.Instance); + + /// + /// Creates a new cloned instance of from the . + /// The instance is created via + /// + /// The image metadata. + /// The new + public static IcoMetadata CloneIcoMetadata(this ImageMetadata source) => source.CloneFormatMetadata(IcoFormat.Instance); + + /// + /// Gets the from .
+ /// If none is found, an instance is created either by conversion from the decoded image format metadata + /// or the requested format default constructor. + /// This instance will be added to the metadata for future requests. + ///
+ /// The image metadata. + /// + /// The + /// + public static JpegMetadata GetJpegMetadata(this ImageMetadata source) => source.GetFormatMetadata(JpegFormat.Instance); + + /// + /// Creates a new cloned instance of from the . + /// The instance is created via + /// + /// The image metadata. + /// The new + public static JpegMetadata CloneJpegMetadata(this ImageMetadata source) => source.CloneFormatMetadata(JpegFormat.Instance); + + /// + /// Gets the from .
+ /// If none is found, an instance is created either by conversion from the decoded image format metadata + /// or the requested format default constructor. + /// This instance will be added to the metadata for future requests. + ///
+ /// The image metadata. + /// + /// The + /// + public static PbmMetadata GetPbmMetadata(this ImageMetadata source) => source.GetFormatMetadata(PbmFormat.Instance); + + /// + /// Creates a new cloned instance of from the . + /// The instance is created via + /// + /// The image metadata. + /// The new + public static PbmMetadata ClonePbmMetadata(this ImageMetadata source) => source.CloneFormatMetadata(PbmFormat.Instance); + + /// + /// Gets the from .
+ /// If none is found, an instance is created either by conversion from the decoded image format metadata + /// or the requested format default constructor. + /// This instance will be added to the metadata for future requests. + ///
+ /// The image metadata. + /// + /// The + /// + public static PngMetadata GetPngMetadata(this ImageMetadata source) => source.GetFormatMetadata(PngFormat.Instance); + + /// + /// Creates a new cloned instance of from the . + /// The instance is created via + /// + /// The image metadata. + /// The new + public static PngMetadata ClonePngMetadata(this ImageMetadata source) => source.CloneFormatMetadata(PngFormat.Instance); + + /// + /// Gets the from .
+ /// If none is found, an instance is created either by conversion from the decoded image format metadata + /// or the requested format default constructor. + /// This instance will be added to the metadata for future requests. + ///
+ /// The image metadata. + /// + /// The + /// + public static QoiMetadata GetQoiMetadata(this ImageMetadata source) => source.GetFormatMetadata(QoiFormat.Instance); + + /// + /// Creates a new cloned instance of from the . + /// The instance is created via + /// + /// The image metadata. + /// The new + public static QoiMetadata CloneQoiMetadata(this ImageMetadata source) => source.CloneFormatMetadata(QoiFormat.Instance); + + /// + /// Gets the from .
+ /// If none is found, an instance is created either by conversion from the decoded image format metadata + /// or the requested format default constructor. + /// This instance will be added to the metadata for future requests. + ///
+ /// The image metadata. + /// + /// The + /// + public static TgaMetadata GetTgaMetadata(this ImageMetadata source) => source.GetFormatMetadata(TgaFormat.Instance); + + /// + /// Creates a new cloned instance of from the . + /// The instance is created via + /// + /// The image metadata. + /// The new + public static TgaMetadata CloneTgaMetadata(this ImageMetadata source) => source.CloneFormatMetadata(TgaFormat.Instance); + + /// + /// Gets the from .
+ /// If none is found, an instance is created either by conversion from the decoded image format metadata + /// or the requested format default constructor. + /// This instance will be added to the metadata for future requests. + ///
+ /// The image metadata. + /// + /// The + /// + public static TiffMetadata GetTiffMetadata(this ImageMetadata source) => source.GetFormatMetadata(TiffFormat.Instance); + + /// + /// Creates a new cloned instance of from the . + /// The instance is created via + /// + /// The image metadata. + /// The new + public static TiffMetadata CloneTiffMetadata(this ImageMetadata source) => source.CloneFormatMetadata(TiffFormat.Instance); + + /// + /// Gets the from .
+ /// If none is found, an instance is created either by conversion from the decoded image format metadata + /// or the requested format default constructor. + /// This instance will be added to the metadata for future requests. + ///
+ /// The image metadata. + /// + /// The + /// + public static WebpMetadata GetWebpMetadata(this ImageMetadata source) => source.GetFormatMetadata(WebpFormat.Instance); + + /// + /// Creates a new cloned instance of from the . + /// The instance is created via + /// + /// The image metadata. + /// The new + public static WebpMetadata CloneWebpMetadata(this ImageMetadata source) => source.CloneFormatMetadata(WebpFormat.Instance); + + + /// + /// Gets the from .
+ /// If none is found, an instance is created either by conversion from the decoded image format metadata + /// or the requested format default constructor. + /// This instance will be added to the metadata for future requests. + ///
+ /// The image frame metadata. + /// + /// The + /// + public static CurFrameMetadata GetCurMetadata(this ImageFrameMetadata source) => source.GetFormatMetadata(CurFormat.Instance); + + /// + /// Creates a new cloned instance of from the . + /// The instance is created via + /// + /// The image frame metadata. + /// The new + public static CurFrameMetadata CloneCurMetadata(this ImageFrameMetadata source) => source.CloneFormatMetadata(CurFormat.Instance); + + /// + /// Gets the from .
+ /// If none is found, an instance is created either by conversion from the decoded image format metadata + /// or the requested format default constructor. + /// This instance will be added to the metadata for future requests. + ///
+ /// The image frame metadata. + /// + /// The + /// + public static IcoFrameMetadata GetIcoMetadata(this ImageFrameMetadata source) => source.GetFormatMetadata(IcoFormat.Instance); + + /// + /// Creates a new cloned instance of from the . + /// The instance is created via + /// + /// The image frame metadata. + /// The new + public static IcoFrameMetadata CloneIcoMetadata(this ImageFrameMetadata source) => source.CloneFormatMetadata(IcoFormat.Instance); + + /// + /// Gets the from .
+ /// If none is found, an instance is created either by conversion from the decoded image format metadata + /// or the requested format default constructor. + /// This instance will be added to the metadata for future requests. + ///
+ /// The image frame metadata. + /// + /// The + /// + public static GifFrameMetadata GetGifMetadata(this ImageFrameMetadata source) => source.GetFormatMetadata(GifFormat.Instance); + + /// + /// Creates a new cloned instance of from the . + /// The instance is created via + /// + /// The image frame metadata. + /// The new + public static GifFrameMetadata CloneGifMetadata(this ImageFrameMetadata source) => source.CloneFormatMetadata(GifFormat.Instance); + + /// + /// Gets the from .
+ /// If none is found, an instance is created either by conversion from the decoded image format metadata + /// or the requested format default constructor. + /// This instance will be added to the metadata for future requests. + ///
+ /// The image frame metadata. + /// + /// The + /// + public static PngFrameMetadata GetPngMetadata(this ImageFrameMetadata source) => source.GetFormatMetadata(PngFormat.Instance); + + /// + /// Creates a new cloned instance of from the . + /// The instance is created via + /// + /// The image frame metadata. + /// The new + public static PngFrameMetadata ClonePngMetadata(this ImageFrameMetadata source) => source.CloneFormatMetadata(PngFormat.Instance); + + /// + /// Gets the from .
+ /// If none is found, an instance is created either by conversion from the decoded image format metadata + /// or the requested format default constructor. + /// This instance will be added to the metadata for future requests. + ///
+ /// The image frame metadata. + /// + /// The + /// + public static TiffFrameMetadata GetTiffMetadata(this ImageFrameMetadata source) => source.GetFormatMetadata(TiffFormat.Instance); + + /// + /// Creates a new cloned instance of from the . + /// The instance is created via + /// + /// The image frame metadata. + /// The new + public static TiffFrameMetadata CloneTiffMetadata(this ImageFrameMetadata source) => source.CloneFormatMetadata(TiffFormat.Instance); + + /// + /// Gets the from .
+ /// If none is found, an instance is created either by conversion from the decoded image format metadata + /// or the requested format default constructor. + /// This instance will be added to the metadata for future requests. + ///
+ /// The image frame metadata. + /// + /// The + /// + public static WebpFrameMetadata GetWebpMetadata(this ImageFrameMetadata source) => source.GetFormatMetadata(WebpFormat.Instance); + + /// + /// Creates a new cloned instance of from the . + /// The instance is created via + /// + /// The image frame metadata. + /// The new + public static WebpFrameMetadata CloneWebpMetadata(this ImageFrameMetadata source) => source.CloneFormatMetadata(WebpFormat.Instance); +} diff --git a/src/ImageSharp/Formats/_Generated/ImageMetadataExtensions.tt b/src/ImageSharp/Formats/_Generated/ImageMetadataExtensions.tt new file mode 100644 index 0000000000..e4db85ed59 --- /dev/null +++ b/src/ImageSharp/Formats/_Generated/ImageMetadataExtensions.tt @@ -0,0 +1,77 @@ +<#@include file="_Formats.ttinclude" #> +<#@ import namespace="System.Text" #> +<#@ import namespace="System.Collections.Generic" #> +// +using SixLabors.ImageSharp.Metadata; +<# + foreach (string fmt in formats) + { +#> +using SixLabors.ImageSharp.Formats.<#= fmt #>; +<# + + } +#> + +namespace SixLabors.ImageSharp; + +/// +/// Extension methods for the and types. +/// +public static class ImageMetadataExtensions +{ +<# + foreach (string fmt in formats) + { +#> + /// + /// Gets the from .
+ /// If none is found, an instance is created either by conversion from the decoded image format metadata + /// or the requested format default constructor. + /// This instance will be added to the metadata for future requests. + ///
+ /// The image metadata. + /// + /// The + /// + public static <#= fmt #>Metadata Get<#= fmt #>Metadata(this ImageMetadata source) => source.GetFormatMetadata(<#= fmt #>Format.Instance); + + /// + /// Creates a new cloned instance of from the . + /// The instance is created via + /// + /// The image metadata. + /// The new + public static <#= fmt #>Metadata Clone<#= fmt #>Metadata(this ImageMetadata source) => source.CloneFormatMetadata(<#= fmt #>Format.Instance); + +<# + } +#> +<# + foreach (string fmt in frameFormats) + { +#> + + /// + /// Gets the from .
+ /// If none is found, an instance is created either by conversion from the decoded image format metadata + /// or the requested format default constructor. + /// This instance will be added to the metadata for future requests. + ///
+ /// The image frame metadata. + /// + /// The + /// + public static <#= fmt #>FrameMetadata Get<#= fmt #>Metadata(this ImageFrameMetadata source) => source.GetFormatMetadata(<#= fmt #>Format.Instance); + + /// + /// Creates a new cloned instance of from the . + /// The instance is created via + /// + /// The image frame metadata. + /// The new + public static <#= fmt #>FrameMetadata Clone<#= fmt #>Metadata(this ImageFrameMetadata source) => source.CloneFormatMetadata(<#= fmt #>Format.Instance); +<# + } +#> +} diff --git a/src/ImageSharp/Formats/_Generated/_Formats.ttinclude b/src/ImageSharp/Formats/_Generated/_Formats.ttinclude new file mode 100644 index 0000000000..89940d406e --- /dev/null +++ b/src/ImageSharp/Formats/_Generated/_Formats.ttinclude @@ -0,0 +1,28 @@ +<#@ template debug="false" hostspecific="false" language="C#" #> +<#@ assembly name="System.Core" #> +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. +<#+ + private static readonly string[] formats = new []{ + "Bmp", + "Cur", + "Gif", + "Ico", + "Jpeg", + "Pbm", + "Png", + "Qoi", + "Tga", + "Tiff", + "Webp", + }; + + private static readonly string[] frameFormats = new []{ + "Cur", + "Ico", + "Gif", + "Png", + "Tiff", + "Webp", + }; +#> diff --git a/src/ImageSharp/Image.Decode.cs b/src/ImageSharp/Image.Decode.cs index 887cb23ca4..7f58c6ecd8 100644 --- a/src/ImageSharp/Image.Decode.cs +++ b/src/ImageSharp/Image.Decode.cs @@ -1,6 +1,7 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. +using System.Buffers; using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Metadata; @@ -67,20 +68,70 @@ private static IImageFormat InternalDetectFormat(Configuration configuration, St int i; do { - i = stream.Read(headersBuffer, n, headerSize - n); + i = stream.Read(headersBuffer[n..headerSize]); n += i; } while (n < headerSize && i > 0); stream.Position = startPosition; + return InternalDetectFormat(configuration, headersBuffer[..n]); + } + + /// + /// By reading the header on the provided stream this calculates the images format. + /// + /// The general configuration. + /// The image stream to read the header from. + /// The token to monitor for cancellation requests. + /// The mime type or null if none found. + /// The input format is not recognized. + private static async ValueTask InternalDetectFormatAsync( + Configuration configuration, + Stream stream, + CancellationToken cancellationToken) + { + // We take a minimum of the stream length vs the max header size and always check below + // to ensure that only formats that headers fit within the given buffer length are tested. + int headerSize = (int)Math.Min(configuration.MaxHeaderSize, stream.Length); + if (headerSize <= 0) + { + ImageFormatManager.ThrowInvalidDecoder(configuration.ImageFormatsManager); + } + + using (IMemoryOwner memoryOwner = configuration.MemoryAllocator.Allocate(headerSize)) + { + Memory headersBuffer = memoryOwner.Memory; + long startPosition = stream.Position; + + // Read doesn't always guarantee the full returned length so read a byte + // at a time until we get either our count or hit the end of the stream. + int n = 0; + int i; + do + { + i = await stream.ReadAsync(headersBuffer[n..headerSize], cancellationToken); + n += i; + } + while (n < headerSize && i > 0); + + stream.Position = startPosition; + + return InternalDetectFormat(configuration, headersBuffer.Span[..n]); + } + } + + private static IImageFormat InternalDetectFormat( + Configuration configuration, + ReadOnlySpan headersBuffer) + { // Does the given stream contain enough data to fit in the header for the format // and does that data match the format specification? // Individual formats should still check since they are public. IImageFormat? format = null; foreach (IImageFormatDetector formatDetector in configuration.ImageFormatsManager.FormatDetectors) { - if (formatDetector.HeaderSize <= headerSize && formatDetector.TryDetectFormat(headersBuffer, out IImageFormat? attemptFormat)) + if (formatDetector.HeaderSize <= headersBuffer.Length && formatDetector.TryDetectFormat(headersBuffer, out IImageFormat? attemptFormat)) { format = attemptFormat; } @@ -106,6 +157,22 @@ private static IImageDecoder DiscoverDecoder(DecoderOptions options, Stream stre return options.Configuration.ImageFormatsManager.GetDecoder(format); } + /// + /// By reading the header on the provided stream this calculates the images format. + /// + /// The general decoder options. + /// The image stream to read the header from. + /// The token to monitor for cancellation requests. + /// The . + private static async ValueTask DiscoverDecoderAsync( + DecoderOptions options, + Stream stream, + CancellationToken cancellationToken) + { + IImageFormat format = await InternalDetectFormatAsync(options.Configuration, stream, cancellationToken); + return options.Configuration.ImageFormatsManager.GetDecoder(format); + } + /// /// Decodes the image stream to the current image. /// @@ -122,14 +189,14 @@ private static Image Decode(DecoderOptions options, Stream strea return decoder.Decode(options, stream); } - private static Task> DecodeAsync( + private static async Task> DecodeAsync( DecoderOptions options, Stream stream, CancellationToken cancellationToken) where TPixel : unmanaged, IPixel { - IImageDecoder decoder = DiscoverDecoder(options, stream); - return decoder.DecodeAsync(options, stream, cancellationToken); + IImageDecoder decoder = await DiscoverDecoderAsync(options, stream, cancellationToken); + return await decoder.DecodeAsync(options, stream, cancellationToken); } private static Image Decode(DecoderOptions options, Stream stream) @@ -138,13 +205,13 @@ private static Image Decode(DecoderOptions options, Stream stream) return decoder.Decode(options, stream); } - private static Task DecodeAsync( + private static async Task DecodeAsync( DecoderOptions options, Stream stream, CancellationToken cancellationToken) { - IImageDecoder decoder = DiscoverDecoder(options, stream); - return decoder.DecodeAsync(options, stream, cancellationToken); + IImageDecoder decoder = await DiscoverDecoderAsync(options, stream, cancellationToken); + return await decoder.DecodeAsync(options, stream, cancellationToken); } /// @@ -166,12 +233,12 @@ private static ImageInfo InternalIdentify(DecoderOptions options, Stream stream) /// The stream. /// The token to monitor for cancellation requests. /// The . - private static Task InternalIdentifyAsync( + private static async Task InternalIdentifyAsync( DecoderOptions options, Stream stream, CancellationToken cancellationToken) { - IImageDecoder decoder = DiscoverDecoder(options, stream); - return decoder.IdentifyAsync(options, stream, cancellationToken); + IImageDecoder decoder = await DiscoverDecoderAsync(options, stream, cancellationToken); + return await decoder.IdentifyAsync(options, stream, cancellationToken); } } diff --git a/src/ImageSharp/Image.FromStream.cs b/src/ImageSharp/Image.FromStream.cs index 63f9e64f6c..21345fdeb0 100644 --- a/src/ImageSharp/Image.FromStream.cs +++ b/src/ImageSharp/Image.FromStream.cs @@ -72,7 +72,7 @@ public static Task DetectFormatAsync( => WithSeekableStreamAsync( options, stream, - (s, _) => Task.FromResult(InternalDetectFormat(options.Configuration, s)), + async (s, ct) => await InternalDetectFormatAsync(options.Configuration, s, ct).ConfigureAwait(false), cancellationToken); /// diff --git a/src/ImageSharp/Image.WrapMemory.cs b/src/ImageSharp/Image.WrapMemory.cs index d8cea246fe..03bec8bc6a 100644 --- a/src/ImageSharp/Image.WrapMemory.cs +++ b/src/ImageSharp/Image.WrapMemory.cs @@ -50,7 +50,7 @@ public static Image WrapMemory( { Guard.NotNull(configuration, nameof(configuration)); Guard.NotNull(metadata, nameof(metadata)); - Guard.IsTrue(pixelMemory.Length >= width * height, nameof(pixelMemory), "The length of the input memory is less than the specified image size"); + Guard.IsTrue(pixelMemory.Length >= (long)width * height, nameof(pixelMemory), "The length of the input memory is less than the specified image size"); MemoryGroup memorySource = MemoryGroup.Wrap(pixelMemory); return new Image(configuration, memorySource, width, height, metadata); @@ -145,7 +145,7 @@ public static Image WrapMemory( { Guard.NotNull(configuration, nameof(configuration)); Guard.NotNull(metadata, nameof(metadata)); - Guard.IsTrue(pixelMemoryOwner.Memory.Length >= width * height, nameof(pixelMemoryOwner), "The length of the input memory is less than the specified image size"); + Guard.IsTrue(pixelMemoryOwner.Memory.Length >= (long)width * height, nameof(pixelMemoryOwner), "The length of the input memory is less than the specified image size"); MemoryGroup memorySource = MemoryGroup.Wrap(pixelMemoryOwner); return new Image(configuration, memorySource, width, height, metadata); @@ -232,7 +232,7 @@ public static Image WrapMemory( ByteMemoryManager memoryManager = new(byteMemory); - Guard.IsTrue(memoryManager.Memory.Length >= width * height, nameof(byteMemory), "The length of the input memory is less than the specified image size"); + Guard.IsTrue(memoryManager.Memory.Length >= (long)width * height, nameof(byteMemory), "The length of the input memory is less than the specified image size"); MemoryGroup memorySource = MemoryGroup.Wrap(memoryManager.Memory); return new Image(configuration, memorySource, width, height, metadata); @@ -422,10 +422,11 @@ public static unsafe Image WrapMemory( Guard.IsFalse(pointer == null, nameof(pointer), "Pointer must be not null"); Guard.NotNull(configuration, nameof(configuration)); Guard.NotNull(metadata, nameof(metadata)); + Guard.MustBeLessThanOrEqualTo(height * (long)width, int.MaxValue, "Total amount of pixels exceeds int.MaxValue"); UnmanagedMemoryManager memoryManager = new(pointer, width * height); - Guard.MustBeGreaterThanOrEqualTo(bufferSizeInBytes, memoryManager.Memory.Span.Length, nameof(bufferSizeInBytes)); + Guard.MustBeGreaterThanOrEqualTo(bufferSizeInBytes / sizeof(TPixel), memoryManager.Memory.Span.Length, nameof(bufferSizeInBytes)); MemoryGroup memorySource = MemoryGroup.Wrap(memoryManager.Memory); return new Image(configuration, memorySource, width, height, metadata); diff --git a/src/ImageSharp/Image.cs b/src/ImageSharp/Image.cs index 03a19a4be8..d4f773abe1 100644 --- a/src/ImageSharp/Image.cs +++ b/src/ImageSharp/Image.cs @@ -157,6 +157,28 @@ public Image CloneAs() public abstract Image CloneAs(Configuration configuration) where TPixel2 : unmanaged, IPixel; + /// + /// Synchronizes any embedded metadata profiles with the current image properties. + /// + public void SynchronizeMetadata() + { + this.Metadata.SynchronizeProfiles(); + foreach (ImageFrame frame in this.Frames) + { + frame.Metadata.SynchronizeProfiles(); + } + } + + /// + /// Synchronizes any embedded metadata profiles with the current image properties. + /// + /// A synchronization action to run in addition to the default process. + public void SynchronizeMetadata(Action action) + { + this.SynchronizeMetadata(); + action(this); + } + /// /// Update the size of the image after mutation. /// diff --git a/src/ImageSharp/ImageInfo.cs b/src/ImageSharp/ImageInfo.cs index 00319e9b55..0bbd73b63a 100644 --- a/src/ImageSharp/ImageInfo.cs +++ b/src/ImageSharp/ImageInfo.cs @@ -1,8 +1,8 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.Metadata; +using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp; @@ -14,40 +14,43 @@ public class ImageInfo /// /// Initializes a new instance of the class. /// - /// The pixel type information. /// The size of the image in px units. /// The image metadata. public ImageInfo( - PixelTypeInfo pixelType, Size size, - ImageMetadata? metadata) - : this(pixelType, size, metadata, null) + ImageMetadata metadata) + : this(size, metadata, null) { } /// /// Initializes a new instance of the class. /// - /// The pixel type information. /// The size of the image in px units. /// The image metadata. /// The collection of image frame metadata. public ImageInfo( - PixelTypeInfo pixelType, Size size, - ImageMetadata? metadata, + ImageMetadata metadata, IReadOnlyList? frameMetadataCollection) { - this.PixelType = pixelType; this.Size = size; - this.Metadata = metadata ?? new ImageMetadata(); - this.FrameMetadataCollection = frameMetadataCollection ?? Array.Empty(); + this.Metadata = metadata; + + // PixelTpe is normally set following decoding + // See ImageDecoder.SetDecoderFormat(Configuration configuration, ImageInfo info). + if (metadata.DecodedImageFormat is not null) + { + this.PixelType = metadata.GetDecodedPixelTypeInfo(); + } + + this.FrameMetadataCollection = frameMetadataCollection ?? []; } /// /// Gets information about the image pixels. /// - public PixelTypeInfo PixelType { get; } + public PixelTypeInfo PixelType { get; internal set; } /// /// Gets the image width in px units. @@ -59,6 +62,11 @@ public ImageInfo( /// public int Height => this.Size.Height; + /// + /// Gets the number of frames in the image. + /// + public int FrameCount => this.FrameMetadataCollection.Count; + /// /// Gets any metadata associated with the image. /// @@ -72,10 +80,10 @@ public ImageInfo( /// /// Gets the size of the image in px units. /// - public Size Size { get; internal set; } + public Size Size { get; } /// /// Gets the bounds of the image. /// - public Rectangle Bounds => new(0, 0, this.Width, this.Height); + public Rectangle Bounds => new(Point.Empty, this.Size); } diff --git a/src/ImageSharp/ImageSharp.csproj b/src/ImageSharp/ImageSharp.csproj index b08c27c41b..d3c4034717 100644 --- a/src/ImageSharp/ImageSharp.csproj +++ b/src/ImageSharp/ImageSharp.csproj @@ -22,20 +22,20 @@ - - 3.1 + + 4.0 - net7.0;net6.0 + net8.0 true - net6.0 + net8.0 true @@ -48,6 +48,15 @@ + + + + + + True + True + ImageMetadataExtensions.tt + True True @@ -138,7 +147,7 @@ True PorterDuffFunctions.Generated.tt - + True True ImageExtensions.Save.tt @@ -146,6 +155,10 @@ + + ImageMetadataExtensions.cs + TextTemplatingFileGenerator + TextTemplatingFileGenerator Block8x8F.Generated.cs @@ -218,7 +231,7 @@ DefaultPixelBlenders.Generated.cs TextTemplatingFileGenerator - + TextTemplatingFileGenerator ImageExtensions.Save.cs diff --git a/src/ImageSharp/Image{TPixel}.cs b/src/ImageSharp/Image{TPixel}.cs index c24014e698..e12631cbd7 100644 --- a/src/ImageSharp/Image{TPixel}.cs +++ b/src/ImageSharp/Image{TPixel}.cs @@ -4,7 +4,6 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using SixLabors.ImageSharp.Advanced; -using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Metadata; using SixLabors.ImageSharp.PixelFormats; @@ -78,7 +77,7 @@ public Image(int width, int height) /// The height of the image in pixels. /// The images metadata. internal Image(Configuration configuration, int width, int height, ImageMetadata? metadata) - : base(configuration, PixelTypeInfo.Create(), metadata ?? new(), width, height) + : base(configuration, TPixel.GetPixelTypeInfo(), metadata ?? new(), width, height) => this.frames = new ImageFrameCollection(this, width, height, default(TPixel)); /// @@ -111,7 +110,7 @@ internal Image( int width, int height, ImageMetadata metadata) - : base(configuration, PixelTypeInfo.Create(), metadata, width, height) + : base(configuration, TPixel.GetPixelTypeInfo(), metadata, width, height) => this.frames = new ImageFrameCollection(this, width, height, memoryGroup); /// @@ -129,7 +128,7 @@ internal Image( int height, TPixel backgroundColor, ImageMetadata? metadata) - : base(configuration, PixelTypeInfo.Create(), metadata ?? new(), width, height) + : base(configuration, TPixel.GetPixelTypeInfo(), metadata ?? new(), width, height) => this.frames = new ImageFrameCollection(this, width, height, backgroundColor); /// @@ -140,7 +139,7 @@ internal Image( /// The images metadata. /// The frames that will be owned by this image instance. internal Image(Configuration configuration, ImageMetadata metadata, IEnumerable> frames) - : base(configuration, PixelTypeInfo.Create(), metadata, ValidateFramesAndGetSize(frames)) + : base(configuration, TPixel.GetPixelTypeInfo(), metadata, ValidateFramesAndGetSize(frames)) => this.frames = new ImageFrameCollection(this, frames); /// diff --git a/src/ImageSharp/Memory/Allocators/Internals/SharedArrayPoolBuffer{T}.cs b/src/ImageSharp/Memory/Allocators/Internals/SharedArrayPoolBuffer{T}.cs index f9434ee941..02bdf0f48d 100644 --- a/src/ImageSharp/Memory/Allocators/Internals/SharedArrayPoolBuffer{T}.cs +++ b/src/ImageSharp/Memory/Allocators/Internals/SharedArrayPoolBuffer{T}.cs @@ -57,13 +57,7 @@ public void AddRef() [Conditional("DEBUG")] [MemberNotNull(nameof(Array))] - private void CheckDisposed() - { - if (this.Array == null) - { - throw new ObjectDisposedException("SharedArrayPoolBuffer"); - } - } + private void CheckDisposed() => ObjectDisposedException.ThrowIf(this.Array == null, this.Array); private sealed class LifetimeGuard : RefCountedMemoryLifetimeGuard { diff --git a/src/ImageSharp/Metadata/ImageFrameMetadata.cs b/src/ImageSharp/Metadata/ImageFrameMetadata.cs index 1c0330d5d0..9c0de1edbe 100644 --- a/src/ImageSharp/Metadata/ImageFrameMetadata.cs +++ b/src/ImageSharp/Metadata/ImageFrameMetadata.cs @@ -15,7 +15,7 @@ namespace SixLabors.ImageSharp.Metadata; /// public sealed class ImageFrameMetadata : IDeepCloneable { - private readonly Dictionary formatMetadata = new(); + private readonly Dictionary formatMetadata = []; /// /// Initializes a new instance of the class. @@ -35,9 +35,9 @@ internal ImageFrameMetadata(ImageFrameMetadata other) { DebugGuard.NotNull(other, nameof(other)); - foreach (KeyValuePair meta in other.formatMetadata) + foreach (KeyValuePair meta in other.formatMetadata) { - this.formatMetadata.Add(meta.Key, meta.Value.DeepClone()); + this.formatMetadata.Add(meta.Key, (IFormatFrameMetadata)meta.Value.DeepClone()); } this.ExifProfile = other.ExifProfile?.DeepClone(); @@ -45,6 +45,10 @@ internal ImageFrameMetadata(ImageFrameMetadata other) this.IptcProfile = other.IptcProfile?.DeepClone(); this.XmpProfile = other.XmpProfile?.DeepClone(); this.CicpProfile = other.CicpProfile?.DeepClone(); + + // NOTE: This clone is actually shallow but we share the same format + // instances for all images in the configuration. + this.DecodedImageFormat = other.DecodedImageFormat; } /// @@ -72,12 +76,19 @@ internal ImageFrameMetadata(ImageFrameMetadata other) /// public CicpProfile? CicpProfile { get; set; } + /// + /// Gets the original format, if any, the image was decode from. + /// + public IImageFormat? DecodedImageFormat { get; internal set; } + /// public ImageFrameMetadata DeepClone() => new(this); /// - /// Gets the metadata value associated with the specified key. This method will always return a result creating - /// a new instance and binding it to the frame metadata if none is found. + /// Gets the metadata value associated with the specified key.
+ /// If none is found, an instance is created either by conversion from the decoded image format metadata + /// or the requested format default constructor. + /// This instance will be added to the metadata for future requests. ///
/// The type of format metadata. /// The type of format frame metadata. @@ -87,43 +98,49 @@ internal ImageFrameMetadata(ImageFrameMetadata other) /// public TFormatFrameMetadata GetFormatMetadata(IImageFormat key) where TFormatMetadata : class - where TFormatFrameMetadata : class, IDeepCloneable + where TFormatFrameMetadata : class, IFormatFrameMetadata { - if (this.formatMetadata.TryGetValue(key, out IDeepCloneable? meta)) + if (this.formatMetadata.TryGetValue(key, out IFormatFrameMetadata? meta)) { return (TFormatFrameMetadata)meta; } + // None found. Check if we have a decoded format to convert from. + if (this.DecodedImageFormat is not null + && this.formatMetadata.TryGetValue(this.DecodedImageFormat, out IFormatFrameMetadata? decodedMetadata)) + { + TFormatFrameMetadata derivedMeta = TFormatFrameMetadata.FromFormatConnectingFrameMetadata(decodedMetadata.ToFormatConnectingFrameMetadata()); + this.formatMetadata[key] = derivedMeta; + return derivedMeta; + } + TFormatFrameMetadata newMeta = key.CreateDefaultFormatFrameMetadata(); this.formatMetadata[key] = newMeta; return newMeta; } + internal void SetFormatMetadata(IImageFormat key, TFormatFrameMetadata value) + where TFormatMetadata : class + where TFormatFrameMetadata : class, IFormatFrameMetadata + => this.formatMetadata[key] = value; + /// - /// Gets the metadata value associated with the specified key. + /// Creates a new instance the metadata value associated with the specified key. + /// The instance is created from a clone generated via . /// - /// The type of format metadata. + /// The type of metadata. /// The type of format frame metadata. /// The key of the value to get. - /// - /// When this method returns, contains the metadata associated with the specified key, - /// if the key is found; otherwise, the default value for the type of the metadata parameter. - /// This parameter is passed uninitialized. - /// /// - /// if the frame metadata exists for the specified key; otherwise, . + /// The . /// - public bool TryGetFormatMetadata(IImageFormat key, out TFormatFrameMetadata? metadata) + public TFormatFrameMetadata CloneFormatMetadata(IImageFormat key) where TFormatMetadata : class - where TFormatFrameMetadata : class, IDeepCloneable - { - if (this.formatMetadata.TryGetValue(key, out IDeepCloneable? meta)) - { - metadata = (TFormatFrameMetadata)meta; - return true; - } + where TFormatFrameMetadata : class, IFormatFrameMetadata + => ((IDeepCloneable)this.GetFormatMetadata(key)).DeepClone(); - metadata = default; - return false; - } + /// + /// Synchronizes the profiles with the current metadata. + /// + internal void SynchronizeProfiles() => this.ExifProfile?.Sync(this); } diff --git a/src/ImageSharp/Metadata/ImageMetadata.cs b/src/ImageSharp/Metadata/ImageMetadata.cs index 6b62be08ff..37557ba1dc 100644 --- a/src/ImageSharp/Metadata/ImageMetadata.cs +++ b/src/ImageSharp/Metadata/ImageMetadata.cs @@ -7,6 +7,7 @@ using SixLabors.ImageSharp.Metadata.Profiles.Icc; using SixLabors.ImageSharp.Metadata.Profiles.Iptc; using SixLabors.ImageSharp.Metadata.Profiles.Xmp; +using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Metadata; @@ -33,7 +34,7 @@ public sealed class ImageMetadata : IDeepCloneable ///
public const PixelResolutionUnit DefaultPixelResolutionUnits = PixelResolutionUnit.PixelsPerInch; - private readonly Dictionary formatMetadata = new(); + private readonly Dictionary formatMetadata = []; private double horizontalResolution; private double verticalResolution; @@ -60,9 +61,9 @@ private ImageMetadata(ImageMetadata other) this.VerticalResolution = other.VerticalResolution; this.ResolutionUnits = other.ResolutionUnits; - foreach (KeyValuePair meta in other.formatMetadata) + foreach (KeyValuePair meta in other.formatMetadata) { - this.formatMetadata.Add(meta.Key, meta.Value.DeepClone()); + this.formatMetadata.Add(meta.Key, (IFormatMetadata)meta.Value.DeepClone()); } this.ExifProfile = other.ExifProfile?.DeepClone(); @@ -165,12 +166,15 @@ public double VerticalResolution public CicpProfile? CicpProfile { get; set; } /// - /// Gets the original format, if any, the image was decode from. + /// Gets the original format, if any, from which the image was decoded. /// public IImageFormat? DecodedImageFormat { get; internal set; } /// - /// Gets the metadata value associated with the specified key. + /// Gets the metadata value associated with the specified key.
+ /// If none is found, an instance is created either by conversion from the decoded image format metadata + /// or the requested format default constructor. + /// This instance will be added to the metadata for future requests. ///
/// The type of metadata. /// The key of the value to get. @@ -178,43 +182,45 @@ public double VerticalResolution /// The . /// public TFormatMetadata GetFormatMetadata(IImageFormat key) - where TFormatMetadata : class, IDeepCloneable + where TFormatMetadata : class, IFormatMetadata { - if (this.formatMetadata.TryGetValue(key, out IDeepCloneable? meta)) + // Check for existing metadata. + if (this.formatMetadata.TryGetValue(key, out IFormatMetadata? meta)) { return (TFormatMetadata)meta; } + // None found. Check if we have a decoded format to convert from. + if (this.DecodedImageFormat is not null + && this.formatMetadata.TryGetValue(this.DecodedImageFormat, out IFormatMetadata? decodedMetadata)) + { + TFormatMetadata derivedMeta = TFormatMetadata.FromFormatConnectingMetadata(decodedMetadata.ToFormatConnectingMetadata()); + this.formatMetadata[key] = derivedMeta; + return derivedMeta; + } + + // Fall back to a default instance. TFormatMetadata newMeta = key.CreateDefaultFormatMetadata(); this.formatMetadata[key] = newMeta; return newMeta; } /// - /// Gets the metadata value associated with the specified key. + /// Creates a new instance the metadata value associated with the specified key. + /// The instance is created from a clone generated via . /// - /// The type of format metadata. + /// The type of metadata. /// The key of the value to get. - /// - /// When this method returns, contains the metadata associated with the specified key, - /// if the key is found; otherwise, the default value for the type of the metadata parameter. - /// This parameter is passed uninitialized. - /// /// - /// if the frame metadata exists for the specified key; otherwise, . + /// The . /// - public bool TryGetFormatMetadata(IImageFormat key, out TFormatMetadata? metadata) - where TFormatMetadata : class, IDeepCloneable - { - if (this.formatMetadata.TryGetValue(key, out IDeepCloneable? meta)) - { - metadata = (TFormatMetadata)meta; - return true; - } + public TFormatMetadata CloneFormatMetadata(IImageFormat key) + where TFormatMetadata : class, IFormatMetadata + => ((IDeepCloneable)this.GetFormatMetadata(key)).DeepClone(); - metadata = default; - return false; - } + internal void SetFormatMetadata(IImageFormat key, TFormatMetadata value) + where TFormatMetadata : class, IFormatMetadata + => this.formatMetadata[key] = value; /// public ImageMetadata DeepClone() => new(this); @@ -222,5 +228,18 @@ public bool TryGetFormatMetadata(IImageFormat /// /// Synchronizes the profiles with the current metadata. /// - internal void SyncProfiles() => this.ExifProfile?.Sync(this); + internal void SynchronizeProfiles() => this.ExifProfile?.Sync(this); + + internal PixelTypeInfo GetDecodedPixelTypeInfo() + { + // None found. Check if we have a decoded format to convert from. + if (this.DecodedImageFormat is not null + && this.formatMetadata.TryGetValue(this.DecodedImageFormat, out IFormatMetadata? decodedMetadata)) + { + return decodedMetadata.GetPixelTypeInfo(); + } + + // This should never happen. + return default; + } } diff --git a/src/ImageSharp/Metadata/Profiles/Exif/ExifProfile.cs b/src/ImageSharp/Metadata/Profiles/Exif/ExifProfile.cs index dd5792ae79..41d3c293b6 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/ExifProfile.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/ExifProfile.cs @@ -298,6 +298,17 @@ internal void Sync(ImageMetadata metadata) this.SyncResolution(ExifTag.YResolution, metadata.VerticalResolution); } + /// + /// Synchronizes the profiles with the specified metadata. + /// + /// The metadata. +#pragma warning disable CA1822, RCS1163, IDE0060 + internal void Sync(ImageFrameMetadata metadata) +#pragma warning restore IDE0060, RCS1163, CA1822 + { + // Nothing to do ....YET. + } + private void SyncResolution(ExifTag tag, double resolution) { if (!this.TryGetValue(tag, out IExifValue? value)) diff --git a/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs b/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs index 953ef74afb..a4fcd9275b 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs @@ -472,7 +472,7 @@ private void ReadValue64(List values, Span offsetBuffer) } } - private void Add(IList values, IExifValue exif, object? value) + private void Add(IList values, ExifValue exif, object? value) { if (!exif.TrySetValue(value)) { diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifValue.cs b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifValue.cs index eacb41cfb3..41b947e20c 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifValue.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifValue.cs @@ -1,10 +1,12 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. +using System.Diagnostics; using System.Runtime.CompilerServices; namespace SixLabors.ImageSharp.Metadata.Profiles.Exif; +[DebuggerDisplay("{Tag} = {IsArray?\"[..]\":ToString(),nq} ({GetType().Name,nq})")] internal abstract class ExifValue : IExifValue, IEquatable { protected ExifValue(ExifTag tag) => this.Tag = tag; diff --git a/src/ImageSharp/Metadata/Profiles/IPTC/IptcValue.cs b/src/ImageSharp/Metadata/Profiles/IPTC/IptcValue.cs index 1a75ecba22..78f7f6de08 100644 --- a/src/ImageSharp/Metadata/Profiles/IPTC/IptcValue.cs +++ b/src/ImageSharp/Metadata/Profiles/IPTC/IptcValue.cs @@ -1,6 +1,7 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. +using System.Diagnostics; using System.Text; namespace SixLabors.ImageSharp.Metadata.Profiles.Iptc; @@ -8,6 +9,7 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Iptc; /// /// Represents a single value of the IPTC profile. /// +[DebuggerDisplay("{Tag} = {ToString(),nq} ({GetType().Name,nq})")] public sealed class IptcValue : IDeepCloneable { private byte[] data = Array.Empty(); diff --git a/src/ImageSharp/PixelFormats/IPackedVector{TPacked}.cs b/src/ImageSharp/PixelFormats/IPackedVector{TPacked}.cs index b74c0ff44e..18a8df3481 100644 --- a/src/ImageSharp/PixelFormats/IPackedVector{TPacked}.cs +++ b/src/ImageSharp/PixelFormats/IPackedVector{TPacked}.cs @@ -1,4 +1,4 @@ -// Copyright (c) Six Labors. +// Copyright (c) Six Labors. // Licensed under the Six Labors Split License. namespace SixLabors.ImageSharp.PixelFormats; diff --git a/src/ImageSharp/PixelFormats/IPixel.cs b/src/ImageSharp/PixelFormats/IPixel.cs index 0994444668..adf386614d 100644 --- a/src/ImageSharp/PixelFormats/IPixel.cs +++ b/src/ImageSharp/PixelFormats/IPixel.cs @@ -14,127 +14,150 @@ namespace SixLabors.ImageSharp.PixelFormats; public interface IPixel : IPixel, IEquatable where TSelf : unmanaged, IPixel { +#pragma warning disable CA1000 // Do not declare static members on generic types /// /// Creates a instance for this pixel type. /// This method is not intended to be consumed directly. Use instead. /// /// The instance. - PixelOperations CreatePixelOperations(); -} + static abstract PixelOperations CreatePixelOperations(); -/// -/// A base interface for all pixels, defining the mandatory operations to be implemented by a pixel type. -/// -public interface IPixel -{ /// - /// Initializes the pixel instance from a generic ("scaled") . + /// Initializes the pixel instance from a generic scaled . /// - /// The vector to load the pixel from. - void FromScaledVector4(Vector4 vector); - - /// - /// Expands the pixel into a generic ("scaled") representation - /// with values scaled and clamped between 0 and 1. - /// The vector components are typically expanded in least to greatest significance order. - /// - /// The . - Vector4 ToScaledVector4(); + /// The vector to load the pixel from. + /// The . + static abstract TSelf FromScaledVector4(Vector4 source); /// /// Initializes the pixel instance from a which is specific to the current pixel type. /// - /// The vector to load the pixel from. - void FromVector4(Vector4 vector); + /// The vector to load the pixel from. + /// The . + static abstract TSelf FromVector4(Vector4 source); /// - /// Expands the pixel into a which is specific to the current pixel type. - /// The vector components are typically expanded in least to greatest significance order. + /// Initializes the pixel instance from an value. /// - /// The . - Vector4 ToVector4(); + /// The value. + /// The . + static abstract TSelf FromAbgr32(Abgr32 source); /// /// Initializes the pixel instance from an value. /// /// The value. - void FromArgb32(Argb32 source); + /// The . + static abstract TSelf FromArgb32(Argb32 source); /// /// Initializes the pixel instance from an value. /// /// The value. - void FromBgra5551(Bgra5551 source); + /// The . + static abstract TSelf FromBgra5551(Bgra5551 source); /// /// Initializes the pixel instance from an value. /// /// The value. - void FromBgr24(Bgr24 source); + /// The . + static abstract TSelf FromBgr24(Bgr24 source); /// /// Initializes the pixel instance from an value. /// /// The value. - void FromBgra32(Bgra32 source); - - /// - /// Initializes the pixel instance from an value. - /// - /// The value. - void FromAbgr32(Abgr32 source); + /// The . + static abstract TSelf FromBgra32(Bgra32 source); /// /// Initializes the pixel instance from an value. /// /// The value. - void FromL8(L8 source); + /// The . + static abstract TSelf FromL8(L8 source); /// /// Initializes the pixel instance from an value. /// /// The value. - void FromL16(L16 source); + /// The . + static abstract TSelf FromL16(L16 source); /// /// Initializes the pixel instance from an value. /// /// The value. - void FromLa16(La16 source); + /// The . + static abstract TSelf FromLa16(La16 source); /// /// Initializes the pixel instance from an value. /// /// The value. - void FromLa32(La32 source); + /// The . + static abstract TSelf FromLa32(La32 source); /// /// Initializes the pixel instance from an value. /// /// The value. - void FromRgb24(Rgb24 source); + /// The . + static abstract TSelf FromRgb24(Rgb24 source); /// /// Initializes the pixel instance from an value. /// /// The value. - void FromRgba32(Rgba32 source); - - /// - /// Convert the pixel instance into representation. - /// - /// The reference to the destination pixel - void ToRgba32(ref Rgba32 dest); + /// The . + static abstract TSelf FromRgba32(Rgba32 source); /// /// Initializes the pixel instance from an value. /// /// The value. - void FromRgb48(Rgb48 source); + /// The . + static abstract TSelf FromRgb48(Rgb48 source); /// /// Initializes the pixel instance from an value. /// /// The value. - void FromRgba64(Rgba64 source); + /// The . + static abstract TSelf FromRgba64(Rgba64 source); +#pragma warning restore CA1000 // Do not declare static members on generic types +} + +/// +/// A base interface for all pixels, defining the mandatory operations to be implemented by a pixel type. +/// +public interface IPixel +{ + /// + /// Gets the pixel type information. + /// + /// The . + static abstract PixelTypeInfo GetPixelTypeInfo(); + + /// + /// Convert the pixel instance into representation. + /// + /// The + Rgba32 ToRgba32(); + + /// + /// Expands the pixel into a generic ("scaled") representation + /// with values scaled and clamped between 0 and 1. + /// The vector components are typically expanded in least to greatest significance order. + /// + /// The . + Vector4 ToScaledVector4(); + + /// + /// Expands the pixel into a which is specific to the current pixel type. + /// The vector components are typically expanded in least to greatest significance order. + /// + /// The . + Vector4 ToVector4(); } diff --git a/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.cs b/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.cs index 0792306760..f62d3c6761 100644 --- a/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.cs @@ -38,9 +38,7 @@ public class NormalSrc : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.NormalSrc(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.NormalSrc(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -143,9 +141,7 @@ public class MultiplySrc : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.MultiplySrc(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.MultiplySrc(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -248,9 +244,7 @@ public class AddSrc : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.AddSrc(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.AddSrc(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -353,9 +347,7 @@ public class SubtractSrc : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.SubtractSrc(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.SubtractSrc(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -458,9 +450,7 @@ public class ScreenSrc : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.ScreenSrc(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.ScreenSrc(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -563,9 +553,7 @@ public class DarkenSrc : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.DarkenSrc(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.DarkenSrc(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -668,9 +656,7 @@ public class LightenSrc : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.LightenSrc(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.LightenSrc(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -773,9 +759,7 @@ public class OverlaySrc : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.OverlaySrc(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.OverlaySrc(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -878,9 +862,7 @@ public class HardLightSrc : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.HardLightSrc(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.HardLightSrc(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -983,9 +965,7 @@ public class NormalSrcAtop : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.NormalSrcAtop(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.NormalSrcAtop(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -1088,9 +1068,7 @@ public class MultiplySrcAtop : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.MultiplySrcAtop(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.MultiplySrcAtop(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -1193,9 +1171,7 @@ public class AddSrcAtop : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.AddSrcAtop(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.AddSrcAtop(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -1298,9 +1274,7 @@ public class SubtractSrcAtop : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.SubtractSrcAtop(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.SubtractSrcAtop(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -1403,9 +1377,7 @@ public class ScreenSrcAtop : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.ScreenSrcAtop(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.ScreenSrcAtop(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -1508,9 +1480,7 @@ public class DarkenSrcAtop : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.DarkenSrcAtop(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.DarkenSrcAtop(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -1613,9 +1583,7 @@ public class LightenSrcAtop : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.LightenSrcAtop(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.LightenSrcAtop(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -1718,9 +1686,7 @@ public class OverlaySrcAtop : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.OverlaySrcAtop(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.OverlaySrcAtop(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -1823,9 +1789,7 @@ public class HardLightSrcAtop : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.HardLightSrcAtop(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.HardLightSrcAtop(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -1928,9 +1892,7 @@ public class NormalSrcOver : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.NormalSrcOver(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.NormalSrcOver(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -2033,9 +1995,7 @@ public class MultiplySrcOver : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.MultiplySrcOver(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.MultiplySrcOver(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -2138,9 +2098,7 @@ public class AddSrcOver : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.AddSrcOver(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.AddSrcOver(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -2243,9 +2201,7 @@ public class SubtractSrcOver : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.SubtractSrcOver(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.SubtractSrcOver(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -2348,9 +2304,7 @@ public class ScreenSrcOver : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.ScreenSrcOver(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.ScreenSrcOver(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -2453,9 +2407,7 @@ public class DarkenSrcOver : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.DarkenSrcOver(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.DarkenSrcOver(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -2558,9 +2510,7 @@ public class LightenSrcOver : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.LightenSrcOver(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.LightenSrcOver(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -2663,9 +2613,7 @@ public class OverlaySrcOver : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.OverlaySrcOver(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.OverlaySrcOver(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -2768,9 +2716,7 @@ public class HardLightSrcOver : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.HardLightSrcOver(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.HardLightSrcOver(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -2873,9 +2819,7 @@ public class NormalSrcIn : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.NormalSrcIn(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.NormalSrcIn(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -2978,9 +2922,7 @@ public class MultiplySrcIn : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.MultiplySrcIn(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.MultiplySrcIn(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -3083,9 +3025,7 @@ public class AddSrcIn : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.AddSrcIn(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.AddSrcIn(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -3188,9 +3128,7 @@ public class SubtractSrcIn : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.SubtractSrcIn(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.SubtractSrcIn(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -3293,9 +3231,7 @@ public class ScreenSrcIn : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.ScreenSrcIn(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.ScreenSrcIn(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -3398,9 +3334,7 @@ public class DarkenSrcIn : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.DarkenSrcIn(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.DarkenSrcIn(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -3503,9 +3437,7 @@ public class LightenSrcIn : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.LightenSrcIn(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.LightenSrcIn(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -3608,9 +3540,7 @@ public class OverlaySrcIn : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.OverlaySrcIn(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.OverlaySrcIn(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -3713,9 +3643,7 @@ public class HardLightSrcIn : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.HardLightSrcIn(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.HardLightSrcIn(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -3818,9 +3746,7 @@ public class NormalSrcOut : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.NormalSrcOut(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.NormalSrcOut(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -3923,9 +3849,7 @@ public class MultiplySrcOut : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.MultiplySrcOut(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.MultiplySrcOut(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -4028,9 +3952,7 @@ public class AddSrcOut : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.AddSrcOut(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.AddSrcOut(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -4133,9 +4055,7 @@ public class SubtractSrcOut : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.SubtractSrcOut(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.SubtractSrcOut(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -4238,9 +4158,7 @@ public class ScreenSrcOut : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.ScreenSrcOut(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.ScreenSrcOut(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -4343,9 +4261,7 @@ public class DarkenSrcOut : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.DarkenSrcOut(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.DarkenSrcOut(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -4448,9 +4364,7 @@ public class LightenSrcOut : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.LightenSrcOut(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.LightenSrcOut(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -4553,9 +4467,7 @@ public class OverlaySrcOut : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.OverlaySrcOut(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.OverlaySrcOut(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -4658,9 +4570,7 @@ public class HardLightSrcOut : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.HardLightSrcOut(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.HardLightSrcOut(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -4763,9 +4673,7 @@ public class NormalDest : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.NormalDest(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.NormalDest(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -4868,9 +4776,7 @@ public class MultiplyDest : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.MultiplyDest(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.MultiplyDest(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -4973,9 +4879,7 @@ public class AddDest : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.AddDest(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.AddDest(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -5078,9 +4982,7 @@ public class SubtractDest : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.SubtractDest(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.SubtractDest(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -5183,9 +5085,7 @@ public class ScreenDest : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.ScreenDest(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.ScreenDest(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -5288,9 +5188,7 @@ public class DarkenDest : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.DarkenDest(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.DarkenDest(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -5393,9 +5291,7 @@ public class LightenDest : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.LightenDest(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.LightenDest(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -5498,9 +5394,7 @@ public class OverlayDest : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.OverlayDest(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.OverlayDest(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -5603,9 +5497,7 @@ public class HardLightDest : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.HardLightDest(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.HardLightDest(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -5708,9 +5600,7 @@ public class NormalDestAtop : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.NormalDestAtop(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.NormalDestAtop(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -5813,9 +5703,7 @@ public class MultiplyDestAtop : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.MultiplyDestAtop(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.MultiplyDestAtop(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -5918,9 +5806,7 @@ public class AddDestAtop : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.AddDestAtop(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.AddDestAtop(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -6023,9 +5909,7 @@ public class SubtractDestAtop : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.SubtractDestAtop(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.SubtractDestAtop(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -6128,9 +6012,7 @@ public class ScreenDestAtop : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.ScreenDestAtop(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.ScreenDestAtop(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -6233,9 +6115,7 @@ public class DarkenDestAtop : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.DarkenDestAtop(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.DarkenDestAtop(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -6338,9 +6218,7 @@ public class LightenDestAtop : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.LightenDestAtop(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.LightenDestAtop(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -6443,9 +6321,7 @@ public class OverlayDestAtop : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.OverlayDestAtop(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.OverlayDestAtop(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -6548,9 +6424,7 @@ public class HardLightDestAtop : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.HardLightDestAtop(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.HardLightDestAtop(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -6653,9 +6527,7 @@ public class NormalDestOver : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.NormalDestOver(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.NormalDestOver(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -6758,9 +6630,7 @@ public class MultiplyDestOver : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.MultiplyDestOver(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.MultiplyDestOver(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -6863,9 +6733,7 @@ public class AddDestOver : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.AddDestOver(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.AddDestOver(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -6968,9 +6836,7 @@ public class SubtractDestOver : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.SubtractDestOver(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.SubtractDestOver(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -7073,9 +6939,7 @@ public class ScreenDestOver : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.ScreenDestOver(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.ScreenDestOver(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -7178,9 +7042,7 @@ public class DarkenDestOver : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.DarkenDestOver(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.DarkenDestOver(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -7283,9 +7145,7 @@ public class LightenDestOver : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.LightenDestOver(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.LightenDestOver(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -7388,9 +7248,7 @@ public class OverlayDestOver : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.OverlayDestOver(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.OverlayDestOver(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -7493,9 +7351,7 @@ public class HardLightDestOver : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.HardLightDestOver(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.HardLightDestOver(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -7598,9 +7454,7 @@ public class NormalDestIn : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.NormalDestIn(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.NormalDestIn(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -7703,9 +7557,7 @@ public class MultiplyDestIn : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.MultiplyDestIn(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.MultiplyDestIn(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -7808,9 +7660,7 @@ public class AddDestIn : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.AddDestIn(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.AddDestIn(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -7913,9 +7763,7 @@ public class SubtractDestIn : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.SubtractDestIn(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.SubtractDestIn(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -8018,9 +7866,7 @@ public class ScreenDestIn : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.ScreenDestIn(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.ScreenDestIn(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -8123,9 +7969,7 @@ public class DarkenDestIn : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.DarkenDestIn(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.DarkenDestIn(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -8228,9 +8072,7 @@ public class LightenDestIn : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.LightenDestIn(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.LightenDestIn(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -8333,9 +8175,7 @@ public class OverlayDestIn : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.OverlayDestIn(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.OverlayDestIn(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -8438,9 +8278,7 @@ public class HardLightDestIn : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.HardLightDestIn(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.HardLightDestIn(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -8543,9 +8381,7 @@ public class NormalDestOut : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.NormalDestOut(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.NormalDestOut(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -8648,9 +8484,7 @@ public class MultiplyDestOut : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.MultiplyDestOut(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.MultiplyDestOut(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -8753,9 +8587,7 @@ public class AddDestOut : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.AddDestOut(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.AddDestOut(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -8858,9 +8690,7 @@ public class SubtractDestOut : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.SubtractDestOut(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.SubtractDestOut(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -8963,9 +8793,7 @@ public class ScreenDestOut : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.ScreenDestOut(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.ScreenDestOut(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -9068,9 +8896,7 @@ public class DarkenDestOut : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.DarkenDestOut(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.DarkenDestOut(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -9173,9 +8999,7 @@ public class LightenDestOut : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.LightenDestOut(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.LightenDestOut(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -9278,9 +9102,7 @@ public class OverlayDestOut : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.OverlayDestOut(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.OverlayDestOut(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -9383,9 +9205,7 @@ public class HardLightDestOut : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.HardLightDestOut(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.HardLightDestOut(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -9488,9 +9308,7 @@ public class NormalClear : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.NormalClear(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.NormalClear(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -9593,9 +9411,7 @@ public class MultiplyClear : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.MultiplyClear(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.MultiplyClear(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -9698,9 +9514,7 @@ public class AddClear : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.AddClear(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.AddClear(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -9803,9 +9617,7 @@ public class SubtractClear : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.SubtractClear(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.SubtractClear(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -9908,9 +9720,7 @@ public class ScreenClear : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.ScreenClear(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.ScreenClear(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -10013,9 +9823,7 @@ public class DarkenClear : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.DarkenClear(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.DarkenClear(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -10118,9 +9926,7 @@ public class LightenClear : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.LightenClear(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.LightenClear(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -10223,9 +10029,7 @@ public class OverlayClear : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.OverlayClear(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.OverlayClear(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -10328,9 +10132,7 @@ public class HardLightClear : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.HardLightClear(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.HardLightClear(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -10433,9 +10235,7 @@ public class NormalXor : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.NormalXor(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.NormalXor(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -10538,9 +10338,7 @@ public class MultiplyXor : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.MultiplyXor(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.MultiplyXor(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -10643,9 +10441,7 @@ public class AddXor : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.AddXor(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.AddXor(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -10748,9 +10544,7 @@ public class SubtractXor : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.SubtractXor(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.SubtractXor(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -10853,9 +10647,7 @@ public class ScreenXor : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.ScreenXor(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.ScreenXor(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -10958,9 +10750,7 @@ public class DarkenXor : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.DarkenXor(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.DarkenXor(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -11063,9 +10853,7 @@ public class LightenXor : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.LightenXor(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.LightenXor(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -11168,9 +10956,7 @@ public class OverlayXor : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.OverlayXor(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.OverlayXor(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -11273,9 +11059,7 @@ public class HardLightXor : PixelBlender /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.HardLightXor(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.HardLightXor(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// diff --git a/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.tt b/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.tt index da6208eaa2..5b71bb0a64 100644 --- a/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.tt @@ -81,9 +81,7 @@ var blenders = new []{ /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.<#=blender_composer#>(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.<#=blender_composer#>(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// diff --git a/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.cs b/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.cs index e7cf3b2921..255bafc798 100644 --- a/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.cs @@ -355,9 +355,7 @@ public static TPixel NormalSrc(TPixel backdrop, TPixel source, float opa where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(NormalSrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(NormalSrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -373,9 +371,7 @@ public static TPixel NormalSrcAtop(TPixel backdrop, TPixel source, float where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(NormalSrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(NormalSrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -391,9 +387,7 @@ public static TPixel NormalSrcOver(TPixel backdrop, TPixel source, float where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(NormalSrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(NormalSrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -409,9 +403,7 @@ public static TPixel NormalSrcIn(TPixel backdrop, TPixel source, float o where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(NormalSrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(NormalSrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -427,9 +419,7 @@ public static TPixel NormalSrcOut(TPixel backdrop, TPixel source, float where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(NormalSrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(NormalSrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -445,9 +435,7 @@ public static TPixel NormalDest(TPixel backdrop, TPixel source, float op where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(NormalDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(NormalDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -463,9 +451,7 @@ public static TPixel NormalDestAtop(TPixel backdrop, TPixel source, floa where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(NormalDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(NormalDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -481,9 +467,7 @@ public static TPixel NormalDestOver(TPixel backdrop, TPixel source, floa where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(NormalDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(NormalDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -499,9 +483,7 @@ public static TPixel NormalDestIn(TPixel backdrop, TPixel source, float where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(NormalDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(NormalDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -517,9 +499,7 @@ public static TPixel NormalDestOut(TPixel backdrop, TPixel source, float where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(NormalDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(NormalDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -535,9 +515,7 @@ public static TPixel NormalClear(TPixel backdrop, TPixel source, float o where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(NormalClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(NormalClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -553,9 +531,7 @@ public static TPixel NormalXor(TPixel backdrop, TPixel source, float opa where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(NormalXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(NormalXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -900,9 +876,7 @@ public static TPixel MultiplySrc(TPixel backdrop, TPixel source, float o where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(MultiplySrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(MultiplySrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -918,9 +892,7 @@ public static TPixel MultiplySrcAtop(TPixel backdrop, TPixel source, flo where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(MultiplySrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(MultiplySrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -936,9 +908,7 @@ public static TPixel MultiplySrcOver(TPixel backdrop, TPixel source, flo where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(MultiplySrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(MultiplySrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -954,9 +924,7 @@ public static TPixel MultiplySrcIn(TPixel backdrop, TPixel source, float where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(MultiplySrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(MultiplySrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -972,9 +940,7 @@ public static TPixel MultiplySrcOut(TPixel backdrop, TPixel source, floa where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(MultiplySrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(MultiplySrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -990,9 +956,7 @@ public static TPixel MultiplyDest(TPixel backdrop, TPixel source, float where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(MultiplyDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(MultiplyDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -1008,9 +972,7 @@ public static TPixel MultiplyDestAtop(TPixel backdrop, TPixel source, fl where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(MultiplyDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(MultiplyDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -1026,9 +988,7 @@ public static TPixel MultiplyDestOver(TPixel backdrop, TPixel source, fl where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(MultiplyDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(MultiplyDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -1044,9 +1004,7 @@ public static TPixel MultiplyDestIn(TPixel backdrop, TPixel source, floa where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(MultiplyDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(MultiplyDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -1062,9 +1020,7 @@ public static TPixel MultiplyDestOut(TPixel backdrop, TPixel source, flo where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(MultiplyDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(MultiplyDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -1080,9 +1036,7 @@ public static TPixel MultiplyClear(TPixel backdrop, TPixel source, float where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(MultiplyClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(MultiplyClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -1098,9 +1052,7 @@ public static TPixel MultiplyXor(TPixel backdrop, TPixel source, float o where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(MultiplyXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(MultiplyXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -1445,9 +1397,7 @@ public static TPixel AddSrc(TPixel backdrop, TPixel source, float opacit where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(AddSrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(AddSrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -1463,9 +1413,7 @@ public static TPixel AddSrcAtop(TPixel backdrop, TPixel source, float op where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(AddSrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(AddSrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -1481,9 +1429,7 @@ public static TPixel AddSrcOver(TPixel backdrop, TPixel source, float op where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(AddSrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(AddSrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -1499,9 +1445,7 @@ public static TPixel AddSrcIn(TPixel backdrop, TPixel source, float opac where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(AddSrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(AddSrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -1517,9 +1461,7 @@ public static TPixel AddSrcOut(TPixel backdrop, TPixel source, float opa where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(AddSrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(AddSrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -1535,9 +1477,7 @@ public static TPixel AddDest(TPixel backdrop, TPixel source, float opaci where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(AddDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(AddDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -1553,9 +1493,7 @@ public static TPixel AddDestAtop(TPixel backdrop, TPixel source, float o where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(AddDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(AddDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -1571,9 +1509,7 @@ public static TPixel AddDestOver(TPixel backdrop, TPixel source, float o where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(AddDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(AddDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -1589,9 +1525,7 @@ public static TPixel AddDestIn(TPixel backdrop, TPixel source, float opa where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(AddDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(AddDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -1607,9 +1541,7 @@ public static TPixel AddDestOut(TPixel backdrop, TPixel source, float op where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(AddDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(AddDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -1625,9 +1557,7 @@ public static TPixel AddClear(TPixel backdrop, TPixel source, float opac where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(AddClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(AddClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -1643,9 +1573,7 @@ public static TPixel AddXor(TPixel backdrop, TPixel source, float opacit where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(AddXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(AddXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -1990,9 +1918,7 @@ public static TPixel SubtractSrc(TPixel backdrop, TPixel source, float o where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(SubtractSrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(SubtractSrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -2008,9 +1934,7 @@ public static TPixel SubtractSrcAtop(TPixel backdrop, TPixel source, flo where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(SubtractSrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(SubtractSrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -2026,9 +1950,7 @@ public static TPixel SubtractSrcOver(TPixel backdrop, TPixel source, flo where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(SubtractSrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(SubtractSrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -2044,9 +1966,7 @@ public static TPixel SubtractSrcIn(TPixel backdrop, TPixel source, float where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(SubtractSrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(SubtractSrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -2062,9 +1982,7 @@ public static TPixel SubtractSrcOut(TPixel backdrop, TPixel source, floa where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(SubtractSrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(SubtractSrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -2080,9 +1998,7 @@ public static TPixel SubtractDest(TPixel backdrop, TPixel source, float where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(SubtractDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(SubtractDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -2098,9 +2014,7 @@ public static TPixel SubtractDestAtop(TPixel backdrop, TPixel source, fl where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(SubtractDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(SubtractDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -2116,9 +2030,7 @@ public static TPixel SubtractDestOver(TPixel backdrop, TPixel source, fl where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(SubtractDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(SubtractDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -2134,9 +2046,7 @@ public static TPixel SubtractDestIn(TPixel backdrop, TPixel source, floa where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(SubtractDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(SubtractDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -2152,9 +2062,7 @@ public static TPixel SubtractDestOut(TPixel backdrop, TPixel source, flo where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(SubtractDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(SubtractDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -2170,9 +2078,7 @@ public static TPixel SubtractClear(TPixel backdrop, TPixel source, float where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(SubtractClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(SubtractClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -2188,9 +2094,7 @@ public static TPixel SubtractXor(TPixel backdrop, TPixel source, float o where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(SubtractXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(SubtractXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -2535,9 +2439,7 @@ public static TPixel ScreenSrc(TPixel backdrop, TPixel source, float opa where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(ScreenSrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(ScreenSrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -2553,9 +2455,7 @@ public static TPixel ScreenSrcAtop(TPixel backdrop, TPixel source, float where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(ScreenSrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(ScreenSrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -2571,9 +2471,7 @@ public static TPixel ScreenSrcOver(TPixel backdrop, TPixel source, float where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(ScreenSrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(ScreenSrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -2589,9 +2487,7 @@ public static TPixel ScreenSrcIn(TPixel backdrop, TPixel source, float o where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(ScreenSrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(ScreenSrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -2607,9 +2503,7 @@ public static TPixel ScreenSrcOut(TPixel backdrop, TPixel source, float where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(ScreenSrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(ScreenSrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -2625,9 +2519,7 @@ public static TPixel ScreenDest(TPixel backdrop, TPixel source, float op where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(ScreenDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(ScreenDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -2643,9 +2535,7 @@ public static TPixel ScreenDestAtop(TPixel backdrop, TPixel source, floa where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(ScreenDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(ScreenDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -2661,9 +2551,7 @@ public static TPixel ScreenDestOver(TPixel backdrop, TPixel source, floa where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(ScreenDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(ScreenDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -2679,9 +2567,7 @@ public static TPixel ScreenDestIn(TPixel backdrop, TPixel source, float where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(ScreenDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(ScreenDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -2697,9 +2583,7 @@ public static TPixel ScreenDestOut(TPixel backdrop, TPixel source, float where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(ScreenDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(ScreenDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -2715,9 +2599,7 @@ public static TPixel ScreenClear(TPixel backdrop, TPixel source, float o where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(ScreenClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(ScreenClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -2733,9 +2615,7 @@ public static TPixel ScreenXor(TPixel backdrop, TPixel source, float opa where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(ScreenXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(ScreenXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -3080,9 +2960,7 @@ public static TPixel DarkenSrc(TPixel backdrop, TPixel source, float opa where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(DarkenSrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(DarkenSrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -3098,9 +2976,7 @@ public static TPixel DarkenSrcAtop(TPixel backdrop, TPixel source, float where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(DarkenSrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(DarkenSrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -3116,9 +2992,7 @@ public static TPixel DarkenSrcOver(TPixel backdrop, TPixel source, float where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(DarkenSrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(DarkenSrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -3134,9 +3008,7 @@ public static TPixel DarkenSrcIn(TPixel backdrop, TPixel source, float o where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(DarkenSrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(DarkenSrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -3152,9 +3024,7 @@ public static TPixel DarkenSrcOut(TPixel backdrop, TPixel source, float where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(DarkenSrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(DarkenSrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -3170,9 +3040,7 @@ public static TPixel DarkenDest(TPixel backdrop, TPixel source, float op where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(DarkenDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(DarkenDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -3188,9 +3056,7 @@ public static TPixel DarkenDestAtop(TPixel backdrop, TPixel source, floa where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(DarkenDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(DarkenDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -3206,9 +3072,7 @@ public static TPixel DarkenDestOver(TPixel backdrop, TPixel source, floa where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(DarkenDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(DarkenDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -3224,9 +3088,7 @@ public static TPixel DarkenDestIn(TPixel backdrop, TPixel source, float where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(DarkenDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(DarkenDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -3242,9 +3104,7 @@ public static TPixel DarkenDestOut(TPixel backdrop, TPixel source, float where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(DarkenDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(DarkenDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -3260,9 +3120,7 @@ public static TPixel DarkenClear(TPixel backdrop, TPixel source, float o where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(DarkenClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(DarkenClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -3278,9 +3136,7 @@ public static TPixel DarkenXor(TPixel backdrop, TPixel source, float opa where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(DarkenXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(DarkenXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -3625,9 +3481,7 @@ public static TPixel LightenSrc(TPixel backdrop, TPixel source, float op where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(LightenSrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(LightenSrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -3643,9 +3497,7 @@ public static TPixel LightenSrcAtop(TPixel backdrop, TPixel source, floa where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(LightenSrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(LightenSrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -3661,9 +3513,7 @@ public static TPixel LightenSrcOver(TPixel backdrop, TPixel source, floa where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(LightenSrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(LightenSrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -3679,9 +3529,7 @@ public static TPixel LightenSrcIn(TPixel backdrop, TPixel source, float where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(LightenSrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(LightenSrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -3697,9 +3545,7 @@ public static TPixel LightenSrcOut(TPixel backdrop, TPixel source, float where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(LightenSrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(LightenSrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -3715,9 +3561,7 @@ public static TPixel LightenDest(TPixel backdrop, TPixel source, float o where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(LightenDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(LightenDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -3733,9 +3577,7 @@ public static TPixel LightenDestAtop(TPixel backdrop, TPixel source, flo where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(LightenDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(LightenDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -3751,9 +3593,7 @@ public static TPixel LightenDestOver(TPixel backdrop, TPixel source, flo where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(LightenDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(LightenDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -3769,9 +3609,7 @@ public static TPixel LightenDestIn(TPixel backdrop, TPixel source, float where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(LightenDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(LightenDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -3787,9 +3625,7 @@ public static TPixel LightenDestOut(TPixel backdrop, TPixel source, floa where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(LightenDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(LightenDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -3805,9 +3641,7 @@ public static TPixel LightenClear(TPixel backdrop, TPixel source, float where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(LightenClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(LightenClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -3823,9 +3657,7 @@ public static TPixel LightenXor(TPixel backdrop, TPixel source, float op where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(LightenXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(LightenXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -4170,9 +4002,7 @@ public static TPixel OverlaySrc(TPixel backdrop, TPixel source, float op where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(OverlaySrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(OverlaySrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -4188,9 +4018,7 @@ public static TPixel OverlaySrcAtop(TPixel backdrop, TPixel source, floa where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(OverlaySrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(OverlaySrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -4206,9 +4034,7 @@ public static TPixel OverlaySrcOver(TPixel backdrop, TPixel source, floa where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(OverlaySrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(OverlaySrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -4224,9 +4050,7 @@ public static TPixel OverlaySrcIn(TPixel backdrop, TPixel source, float where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(OverlaySrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(OverlaySrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -4242,9 +4066,7 @@ public static TPixel OverlaySrcOut(TPixel backdrop, TPixel source, float where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(OverlaySrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(OverlaySrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -4260,9 +4082,7 @@ public static TPixel OverlayDest(TPixel backdrop, TPixel source, float o where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(OverlayDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(OverlayDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -4278,9 +4098,7 @@ public static TPixel OverlayDestAtop(TPixel backdrop, TPixel source, flo where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(OverlayDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(OverlayDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -4296,9 +4114,7 @@ public static TPixel OverlayDestOver(TPixel backdrop, TPixel source, flo where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(OverlayDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(OverlayDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -4314,9 +4130,7 @@ public static TPixel OverlayDestIn(TPixel backdrop, TPixel source, float where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(OverlayDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(OverlayDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -4332,9 +4146,7 @@ public static TPixel OverlayDestOut(TPixel backdrop, TPixel source, floa where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(OverlayDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(OverlayDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -4350,9 +4162,7 @@ public static TPixel OverlayClear(TPixel backdrop, TPixel source, float where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(OverlayClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(OverlayClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -4368,9 +4178,7 @@ public static TPixel OverlayXor(TPixel backdrop, TPixel source, float op where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(OverlayXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(OverlayXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -4715,9 +4523,7 @@ public static TPixel HardLightSrc(TPixel backdrop, TPixel source, float where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(HardLightSrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(HardLightSrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -4733,9 +4539,7 @@ public static TPixel HardLightSrcAtop(TPixel backdrop, TPixel source, fl where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(HardLightSrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(HardLightSrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -4751,9 +4555,7 @@ public static TPixel HardLightSrcOver(TPixel backdrop, TPixel source, fl where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(HardLightSrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(HardLightSrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -4769,9 +4571,7 @@ public static TPixel HardLightSrcIn(TPixel backdrop, TPixel source, floa where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(HardLightSrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(HardLightSrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -4787,9 +4587,7 @@ public static TPixel HardLightSrcOut(TPixel backdrop, TPixel source, flo where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(HardLightSrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(HardLightSrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -4805,9 +4603,7 @@ public static TPixel HardLightDest(TPixel backdrop, TPixel source, float where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(HardLightDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(HardLightDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -4823,9 +4619,7 @@ public static TPixel HardLightDestAtop(TPixel backdrop, TPixel source, f where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(HardLightDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(HardLightDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -4841,9 +4635,7 @@ public static TPixel HardLightDestOver(TPixel backdrop, TPixel source, f where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(HardLightDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(HardLightDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -4859,9 +4651,7 @@ public static TPixel HardLightDestIn(TPixel backdrop, TPixel source, flo where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(HardLightDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(HardLightDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -4877,9 +4667,7 @@ public static TPixel HardLightDestOut(TPixel backdrop, TPixel source, fl where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(HardLightDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(HardLightDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -4895,9 +4683,7 @@ public static TPixel HardLightClear(TPixel backdrop, TPixel source, floa where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(HardLightClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(HardLightClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -4913,8 +4699,6 @@ public static TPixel HardLightXor(TPixel backdrop, TPixel source, float where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(HardLightXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(HardLightXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } } diff --git a/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.tt b/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.tt index 64eee502bb..150adb33a8 100644 --- a/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.tt @@ -368,9 +368,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(<#=blender#><#=composer#>(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(<#=blender#><#=composer#>(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } <# } #> <# diff --git a/src/ImageSharp/PixelFormats/PixelColorType.cs b/src/ImageSharp/PixelFormats/PixelColorType.cs new file mode 100644 index 0000000000..315c0f6584 --- /dev/null +++ b/src/ImageSharp/PixelFormats/PixelColorType.cs @@ -0,0 +1,116 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +namespace SixLabors.ImageSharp.PixelFormats; + +/// +/// Represents the color type and format of a pixel. +/// +[Flags] +public enum PixelColorType +{ + /// + /// No color type. + /// + None = 0, + + /// + /// Represents the Red component of the color. + /// + Red = 1 << 0, + + /// + /// Represents the Green component of the color. + /// + Green = 1 << 1, + + /// + /// Represents the Blue component of the color. + /// + Blue = 1 << 2, + + /// + /// Represents the Alpha component of the color for transparency. + /// + Alpha = 1 << 3, + + /// + /// Represents the Exponent component used in formats like R9G9B9E5. + /// + Exponent = 1 << 4, + + /// + /// Indicates that the color is in luminance (grayscale) format. + /// + Luminance = 1 << 5, + + /// + /// Indicates that the color is in binary (black and white) format. + /// + Binary = 1 << 6, + + /// + /// Indicates that the color is indexed using a palette. + /// + Indexed = 1 << 7, + + /// + /// Indicates that the color is in RGB (Red, Green, Blue) format. + /// + RGB = Red | Green | Blue | (1 << 8), + + /// + /// Indicates that the color is in BGR (Blue, Green, Red) format. + /// + BGR = Blue | Green | Red | (1 << 9), + + /// + /// Represents the Chrominance Blue component. + /// + ChrominanceBlue = 1 << 10, + + /// + /// Represents the Chrominance Red component. + /// + ChrominanceRed = 1 << 11, + + /// + /// Indicates that the color is in YCbCr (Luminance, Chrominance Blue, Chrominance Red) format. + /// + YCbCr = Luminance | ChrominanceBlue | ChrominanceRed | (1 << 12), + + /// + /// Represents the Cyan component in CMYK. + /// + Cyan = 1 << 13, + + /// + /// Represents the Magenta component in CMYK. + /// + Magenta = 1 << 14, + + /// + /// Represents the Yellow component in CMYK. + /// + Yellow = 1 << 15, + + /// + /// Represents the Key (black) component in CMYK and YCCK. + /// + Key = 1 << 16, + + /// + /// Indicates that the color is in CMYK (Cyan, Magenta, Yellow, Key) format. + /// + CMYK = Cyan | Magenta | Yellow | Key, + + /// + /// Indicates that the color is in YCCK (Luminance, Chrominance Blue, Chrominance Red, Key) format. + /// + YCCK = Luminance | ChrominanceBlue | ChrominanceRed | Key, + + /// + /// Indicates that the color is of a type not specified in this enum. + /// + Other = 1 << 17 +} diff --git a/src/ImageSharp/PixelFormats/PixelComponentBitDepth.cs b/src/ImageSharp/PixelFormats/PixelComponentBitDepth.cs new file mode 100644 index 0000000000..674c9363b5 --- /dev/null +++ b/src/ImageSharp/PixelFormats/PixelComponentBitDepth.cs @@ -0,0 +1,50 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +namespace SixLabors.ImageSharp.PixelFormats; + +/// +/// Provides enumeration of the precision in bits of individual components within a pixel format. +/// +public enum PixelComponentBitDepth +{ + /// + /// 1 bit per component. + /// + Bit1 = 1, + + /// + /// 2 bits per component. + /// + Bit2 = 2, + + /// + /// 4 bits per component. + /// + Bit4 = 4, + + /// + /// 8 bits per component. + /// + Bit8 = 8, + + /// + /// 16 bits per component. + /// + Bit16 = 16, + + /// + /// 32 bits per component. + /// + Bit32 = 32, + + /// + /// 64 bits per component. + /// + Bit64 = 64, + + /// + /// 128 bits per component. + /// + Bit128 = 128 +} diff --git a/src/ImageSharp/PixelFormats/PixelComponentInfo.cs b/src/ImageSharp/PixelFormats/PixelComponentInfo.cs new file mode 100644 index 0000000000..1444b344b6 --- /dev/null +++ b/src/ImageSharp/PixelFormats/PixelComponentInfo.cs @@ -0,0 +1,122 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Runtime.CompilerServices; + +namespace SixLabors.ImageSharp.PixelFormats; + +/// +/// Represents pixel component information within a pixel format. +/// +public readonly struct PixelComponentInfo +{ + private readonly long precisionData1; + private readonly long precisionData2; + + private PixelComponentInfo(int count, int padding, long precisionData1, long precisionData2) + { + this.ComponentCount = count; + this.Padding = padding; + this.precisionData1 = precisionData1; + this.precisionData2 = precisionData2; + } + + /// + /// Gets the number of components within the pixel. + /// + public int ComponentCount { get; } + + /// + /// Gets the number of bytes of padding within the pixel. + /// + public int Padding { get; } + + /// + /// Creates a new instance. + /// + /// The type of pixel format. + /// The number of components within the pixel format. + /// The precision in bits of each component. + /// The . + /// The component precision and index cannot exceed the component range. + public static PixelComponentInfo Create(int count, params int[] precision) + where TPixel : unmanaged, IPixel + => Create(count, Unsafe.SizeOf() * 8, precision); + + /// + /// Creates a new instance. + /// + /// The number of components within the pixel format. + /// The number of bits per pixel. + /// The precision in bits of each component. + /// The . + /// The component precision and index cannot exceed the component range. + public static PixelComponentInfo Create(int count, int bitsPerPixel, params int[] precision) + { + if (precision.Length < count || precision.Length > 16) + { + throw new ArgumentOutOfRangeException(nameof(count), $"Count {count} must match the length of precision array and cannot exceed 16."); + } + + long precisionData1 = 0; + long precisionData2 = 0; + int sum = 0; + for (int i = 0; i < precision.Length; i++) + { + int p = precision[i]; + if (p is < 0 or > 255) + { + throw new ArgumentOutOfRangeException(nameof(precision), $"Precision {precision.Length} must be between 0 and 255."); + } + + if (i < 8) + { + precisionData1 |= ((long)p) << (8 * i); + } + else + { + precisionData2 |= ((long)p) << (8 * (i - 8)); + } + + sum += p; + } + + return new PixelComponentInfo(count, bitsPerPixel - sum, precisionData1, precisionData2); + } + + /// + /// Returns the precision of the component in bits at the given index. + /// + /// The component index. + /// The . + /// The component index cannot exceed the component range. + public int GetComponentPrecision(int componentIndex) + { + if (componentIndex < 0 || componentIndex >= this.ComponentCount) + { + throw new ArgumentOutOfRangeException($"Component index must be between 0 and {this.ComponentCount - 1} inclusive."); + } + + long selectedPrecisionData = componentIndex < 8 ? this.precisionData1 : this.precisionData2; + return (int)((selectedPrecisionData >> (8 * (componentIndex & 7))) & 0xFF); + } + + /// + /// Returns the maximum precision in bits of all components. + /// + /// The . + public int GetMaximumComponentPrecision() + { + int maxPrecision = 0; + for (int i = 0; i < this.ComponentCount; i++) + { + int componentPrecision = this.GetComponentPrecision(i); + if (componentPrecision > maxPrecision) + { + maxPrecision = componentPrecision; + } + } + + return maxPrecision; + } +} diff --git a/src/ImageSharp/PixelFormats/PixelConversionModifiers.cs b/src/ImageSharp/PixelFormats/PixelConversionModifiers.cs index 9db3d30045..edc04fa7ce 100644 --- a/src/ImageSharp/PixelFormats/PixelConversionModifiers.cs +++ b/src/ImageSharp/PixelFormats/PixelConversionModifiers.cs @@ -1,15 +1,15 @@ -// Copyright (c) Six Labors. +// Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.ColorSpaces.Companding; +using SixLabors.ImageSharp.ColorProfiles.Companding; namespace SixLabors.ImageSharp.PixelFormats; /// /// Flags responsible to select additional operations which could be efficiently applied in -/// +/// /// or -/// +/// /// knowing the pixel type. /// [Flags] @@ -21,7 +21,7 @@ public enum PixelConversionModifiers None = 0, /// - /// Select and instead the standard (non scaled) variants. + /// Select and instead the standard (non scaled) variants. /// Scale = 1 << 0, diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/A8.cs b/src/ImageSharp/PixelFormats/PixelImplementations/A8.cs index 0256907121..94fbf7eb76 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/A8.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/A8.cs @@ -41,7 +41,7 @@ public partial struct A8 : IPixel, IPackedVector /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(A8 left, A8 right) => left.Equals(right); /// @@ -52,87 +52,90 @@ public partial struct A8 : IPixel, IPackedVector /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(A8 left, A8 right) => !left.Equals(right); /// - public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Rgba32 ToRgba32() => new() { A = this.PackedValue }; /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector); - - /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Vector4 ToScaledVector4() => this.ToVector4(); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromVector4(Vector4 vector) => this.PackedValue = Pack(vector.W); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Vector4 ToVector4() => new(0, 0, 0, this.PackedValue / 255f); + + /// + public static PixelTypeInfo GetPixelTypeInfo() + => PixelTypeInfo.Create( + PixelComponentInfo.Create(1, 8), + PixelColorType.Alpha, + PixelAlphaRepresentation.Unassociated); /// - [MethodImpl(InliningOptions.ShortMethod)] - public readonly Vector4 ToVector4() => new(0, 0, 0, this.PackedValue / 255F); + public static PixelOperations CreatePixelOperations() => new PixelOperations(); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromArgb32(Argb32 source) => this.PackedValue = source.A; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static A8 FromScaledVector4(Vector4 source) => FromVector4(source); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgr24(Bgr24 source) => this.PackedValue = byte.MaxValue; + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static A8 FromVector4(Vector4 source) => new(Pack(source.W)); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra32(Bgra32 source) => this.PackedValue = source.A; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static A8 FromAbgr32(Abgr32 source) => new(source.A); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromAbgr32(Abgr32 source) => this.PackedValue = source.A; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static A8 FromArgb32(Argb32 source) => new(source.A); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static A8 FromBgra5551(Bgra5551 source) => FromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static A8 FromBgr24(Bgr24 source) => new(byte.MaxValue); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL8(L8 source) => this.PackedValue = byte.MaxValue; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static A8 FromBgra32(Bgra32 source) => new(source.A); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL16(L16 source) => this.PackedValue = byte.MaxValue; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static A8 FromL8(L8 source) => new(byte.MaxValue); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa16(La16 source) => this.PackedValue = source.A; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static A8 FromL16(L16 source) => new(byte.MaxValue); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa32(La32 source) => this.PackedValue = ColorNumerics.DownScaleFrom16BitTo8Bit(source.A); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static A8 FromLa16(La16 source) => new(source.A); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb24(Rgb24 source) => this.PackedValue = byte.MaxValue; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static A8 FromLa32(La32 source) => new(ColorNumerics.From16BitTo8Bit(source.A)); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba32(Rgba32 source) => this.PackedValue = source.A; + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static A8 FromRgb24(Rgb24 source) => new(byte.MaxValue); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void ToRgba32(ref Rgba32 dest) - { - dest = default; - dest.A = this.PackedValue; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static A8 FromRgba32(Rgba32 source) => new(source.A); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb48(Rgb48 source) => this.PackedValue = byte.MaxValue; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static A8 FromRgb48(Rgb48 source) => new(byte.MaxValue); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static A8 FromRgba64(Rgba64 source) => new(ColorNumerics.From16BitTo8Bit(source.A)); /// /// Compares an object with the packed vector. @@ -146,7 +149,6 @@ public void ToRgba32(ref Rgba32 dest) /// /// The A8 packed vector to compare. /// True if the packed vectors are equal. - [MethodImpl(InliningOptions.ShortMethod)] public readonly bool Equals(A8 other) => this.PackedValue.Equals(other.PackedValue); /// @@ -156,7 +158,6 @@ public void ToRgba32(ref Rgba32 dest) public override readonly string ToString() => $"A8({this.PackedValue})"; /// - [MethodImpl(InliningOptions.ShortMethod)] public override readonly int GetHashCode() => this.PackedValue.GetHashCode(); /// @@ -164,6 +165,6 @@ public void ToRgba32(ref Rgba32 dest) /// /// The float containing the value to pack. /// The containing the packed values. - [MethodImpl(InliningOptions.ShortMethod)] - private static byte Pack(float alpha) => (byte)Math.Round(Numerics.Clamp(alpha, 0, 1F) * 255F); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static byte Pack(float alpha) => (byte)Math.Round(Numerics.Clamp(alpha, 0, 1f) * 255f); } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Abgr32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Abgr32.cs index 4891abba8c..453a392289 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Abgr32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Abgr32.cs @@ -4,6 +4,7 @@ using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; namespace SixLabors.ImageSharp.PixelFormats; @@ -44,12 +45,12 @@ public partial struct Abgr32 : IPixel, IPackedVector /// /// The maximum byte value. /// - private static readonly Vector4 MaxBytes = new(255); + private static readonly Vector4 MaxBytes = Vector128.Create(255f).AsVector4(); /// /// The half vector value. /// - private static readonly Vector4 Half = new(0.5F); + private static readonly Vector4 Half = Vector128.Create(.5f).AsVector4(); /// /// Initializes a new instance of the struct. @@ -57,7 +58,7 @@ public partial struct Abgr32 : IPixel, IPackedVector /// The red component. /// The green component. /// The blue component. - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public Abgr32(byte r, byte g, byte b) { this.R = r; @@ -73,7 +74,7 @@ public Abgr32(byte r, byte g, byte b) /// The green component. /// The blue component. /// The alpha component. - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public Abgr32(byte r, byte g, byte b, byte a) { this.R = r; @@ -89,9 +90,11 @@ public Abgr32(byte r, byte g, byte b, byte a) /// The green component. /// The blue component. /// The alpha component. - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public Abgr32(float r, float g, float b, float a = 1) - : this() => this.Pack(r, g, b, a); + : this(new Vector4(r, g, b, a)) + { + } /// /// Initializes a new instance of the struct. @@ -99,9 +102,11 @@ public Abgr32(float r, float g, float b, float a = 1) /// /// The vector containing the components for the packed vector. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public Abgr32(Vector3 vector) - : this() => this.Pack(ref vector); + : this(new Vector4(vector, 1f)) + { + } /// /// Initializes a new instance of the struct. @@ -109,9 +114,9 @@ public Abgr32(Vector3 vector) /// /// The vector containing the components for the packed vector. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public Abgr32(Vector4 vector) - : this() => this.Pack(ref vector); + : this() => this = Pack(vector); /// /// Initializes a new instance of the struct. @@ -119,48 +124,32 @@ public Abgr32(Vector4 vector) /// /// The packed value. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public Abgr32(uint packed) : this() => this.Abgr = packed; /// - /// Gets or sets the packed representation of the Abgrb32 struct. + /// Gets or sets the packed representation of the Abgr struct. /// public uint Abgr { - [MethodImpl(InliningOptions.ShortMethod)] - readonly get => Unsafe.As(ref Unsafe.AsRef(this)); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + readonly get => Unsafe.As(ref Unsafe.AsRef(in this)); - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] set => Unsafe.As(ref this) = value; } /// public uint PackedValue { - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get => this.Abgr; - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] set => this.Abgr = value; } - /// - /// Converts an to . - /// - /// The . - /// The . - [MethodImpl(InliningOptions.ShortMethod)] - public static implicit operator Color(Abgr32 source) => new(source); - - /// - /// Converts a to . - /// - /// The . - /// The . - [MethodImpl(InliningOptions.ShortMethod)] - public static implicit operator Abgr32(Color color) => color.ToAbgr32(); - /// /// Compares two objects for equality. /// @@ -169,7 +158,7 @@ public uint PackedValue /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Abgr32 left, Abgr32 right) => left.Equals(right); /// @@ -180,164 +169,117 @@ public uint PackedValue /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Abgr32 left, Abgr32 right) => !left.Equals(right); /// - public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Rgba32 ToRgba32() => Rgba32.FromAbgr32(this); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector); - - /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Vector4 ToScaledVector4() => this.ToVector4(); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromVector4(Vector4 vector) => this.Pack(ref vector); - - /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Vector4 ToVector4() => new Vector4(this.R, this.G, this.B, this.A) / MaxBytes; + /// + public static PixelTypeInfo GetPixelTypeInfo() + => PixelTypeInfo.Create( + PixelComponentInfo.Create(4, 8, 8, 8, 8), + PixelColorType.Alpha | PixelColorType.BGR, + PixelAlphaRepresentation.Unassociated); + + /// + public static PixelOperations CreatePixelOperations() => new PixelOperations(); + /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromAbgr32(Abgr32 source) => this = source; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Abgr32 FromScaledVector4(Vector4 source) => FromVector4(source); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Abgr32 FromVector4(Vector4 source) => Pack(source); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgr24(Bgr24 source) - { - // We can assign the Bgr24 value directly to last three bytes of this instance. - ref byte thisRef = ref Unsafe.As(ref this); - ref byte thisRefFromB = ref Unsafe.AddByteOffset(ref thisRef, 1); - Unsafe.As(ref thisRefFromB) = source; - this.A = byte.MaxValue; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Abgr32 FromAbgr32(Abgr32 source) => new() { PackedValue = source.PackedValue }; /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromArgb32(Argb32 source) - { - this.R = source.R; - this.G = source.G; - this.B = source.B; - this.A = source.A; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Abgr32 FromArgb32(Argb32 source) => new(source.R, source.G, source.B, source.A); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Abgr32 FromBgra5551(Bgra5551 source) => FromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra32(Bgra32 source) - { - this.R = source.R; - this.G = source.G; - this.B = source.B; - this.A = source.A; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Abgr32 FromBgr24(Bgr24 source) => new(source.R, source.G, source.B); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL8(L8 source) - { - this.R = source.PackedValue; - this.G = source.PackedValue; - this.B = source.PackedValue; - this.A = byte.MaxValue; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Abgr32 FromBgra32(Bgra32 source) => new(source.R, source.G, source.B, source.A); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL16(L16 source) - { - byte rgb = ColorNumerics.DownScaleFrom16BitTo8Bit(source.PackedValue); - this.R = rgb; - this.G = rgb; - this.B = rgb; - this.A = byte.MaxValue; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Abgr32 FromL8(L8 source) => new(source.PackedValue, source.PackedValue, source.PackedValue); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa16(La16 source) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Abgr32 FromL16(L16 source) { - this.R = source.L; - this.G = source.L; - this.B = source.L; - this.A = source.A; + byte rgb = ColorNumerics.From16BitTo8Bit(source.PackedValue); + return new(rgb, rgb, rgb); } /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa32(La32 source) - { - byte rgb = ColorNumerics.DownScaleFrom16BitTo8Bit(source.L); - this.R = rgb; - this.G = rgb; - this.B = rgb; - this.A = ColorNumerics.DownScaleFrom16BitTo8Bit(source.A); - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Abgr32 FromLa16(La16 source) => new(source.L, source.L, source.L, source.A); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb24(Rgb24 source) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Abgr32 FromLa32(La32 source) { - this.R = source.R; - this.G = source.G; - this.B = source.B; - this.A = byte.MaxValue; + byte rgb = ColorNumerics.From16BitTo8Bit(source.L); + return new(rgb, rgb, rgb, ColorNumerics.From16BitTo8Bit(source.A)); } /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba32(Rgba32 source) - { - this.R = source.R; - this.G = source.G; - this.B = source.B; - this.A = source.A; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Abgr32 FromRgb24(Rgb24 source) => new(source.R, source.G, source.B); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void ToRgba32(ref Rgba32 dest) - { - dest.R = this.R; - dest.G = this.G; - dest.B = this.B; - dest.A = this.A; - } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Abgr32 FromRgba32(Rgba32 source) => new(source.R, source.G, source.B, source.A); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb48(Rgb48 source) - { - this.R = ColorNumerics.DownScaleFrom16BitTo8Bit(source.R); - this.G = ColorNumerics.DownScaleFrom16BitTo8Bit(source.G); - this.B = ColorNumerics.DownScaleFrom16BitTo8Bit(source.B); - this.A = byte.MaxValue; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Abgr32 FromRgb48(Rgb48 source) + => new() + { + R = ColorNumerics.From16BitTo8Bit(source.R), + G = ColorNumerics.From16BitTo8Bit(source.G), + B = ColorNumerics.From16BitTo8Bit(source.B), + A = byte.MaxValue + }; /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba64(Rgba64 source) - { - this.R = ColorNumerics.DownScaleFrom16BitTo8Bit(source.R); - this.G = ColorNumerics.DownScaleFrom16BitTo8Bit(source.G); - this.B = ColorNumerics.DownScaleFrom16BitTo8Bit(source.B); - this.A = ColorNumerics.DownScaleFrom16BitTo8Bit(source.A); - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Abgr32 FromRgba64(Rgba64 source) + => new() + { + R = ColorNumerics.From16BitTo8Bit(source.R), + G = ColorNumerics.From16BitTo8Bit(source.G), + B = ColorNumerics.From16BitTo8Bit(source.B), + A = ColorNumerics.From16BitTo8Bit(source.A) + }; /// public override readonly bool Equals(object? obj) => obj is Abgr32 abgr32 && this.Equals(abgr32); /// - [MethodImpl(InliningOptions.ShortMethod)] public readonly bool Equals(Abgr32 other) => this.Abgr == other.Abgr; /// @@ -347,7 +289,6 @@ public void FromRgba64(Rgba64 source) public override readonly string ToString() => $"Abgr({this.A}, {this.B}, {this.G}, {this.R})"; /// - [MethodImpl(InliningOptions.ShortMethod)] public override readonly int GetHashCode() => this.Abgr.GetHashCode(); /// @@ -357,38 +298,28 @@ public void FromRgba64(Rgba64 source) /// The y-component /// The z-component /// The w-component - [MethodImpl(InliningOptions.ShortMethod)] - private void Pack(float x, float y, float z, float w) - { - var value = new Vector4(x, y, z, w); - this.Pack(ref value); - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static Abgr32 Pack(float x, float y, float z, float w) => Pack(new Vector4(x, y, z, w)); /// /// Packs a into a uint. /// /// The vector containing the values to pack. - [MethodImpl(InliningOptions.ShortMethod)] - private void Pack(ref Vector3 vector) - { - var value = new Vector4(vector, 1); - this.Pack(ref value); - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static Abgr32 Pack(Vector3 vector) => Pack(new Vector4(vector, 1)); /// /// Packs a into a color. /// /// The vector containing the values to pack. - [MethodImpl(InliningOptions.ShortMethod)] - private void Pack(ref Vector4 vector) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static Abgr32 Pack(Vector4 vector) { vector *= MaxBytes; vector += Half; vector = Numerics.Clamp(vector, Vector4.Zero, MaxBytes); - this.R = (byte)vector.X; - this.G = (byte)vector.Y; - this.B = (byte)vector.Z; - this.A = (byte)vector.W; + Vector128 result = Vector128.ConvertToInt32(vector.AsVector128()).AsByte(); + return new(result.GetElement(0), result.GetElement(4), result.GetElement(8), result.GetElement(12)); } } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs index 0c99adb52d..f8608ecc52 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs @@ -4,6 +4,7 @@ using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; namespace SixLabors.ImageSharp.PixelFormats; @@ -41,15 +42,8 @@ public partial struct Argb32 : IPixel, IPackedVector /// public byte B; - /// - /// The maximum byte value. - /// - private static readonly Vector4 MaxBytes = new(255); - - /// - /// The half vector value. - /// - private static readonly Vector4 Half = new(0.5F); + private static readonly Vector4 MaxBytes = Vector128.Create(255f).AsVector4(); + private static readonly Vector4 Half = Vector128.Create(.5f).AsVector4(); /// /// Initializes a new instance of the struct. @@ -57,7 +51,7 @@ public partial struct Argb32 : IPixel, IPackedVector /// The red component. /// The green component. /// The blue component. - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public Argb32(byte r, byte g, byte b) { this.R = r; @@ -73,7 +67,7 @@ public Argb32(byte r, byte g, byte b) /// The green component. /// The blue component. /// The alpha component. - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public Argb32(byte r, byte g, byte b, byte a) { this.R = r; @@ -89,9 +83,11 @@ public Argb32(byte r, byte g, byte b, byte a) /// The green component. /// The blue component. /// The alpha component. - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public Argb32(float r, float g, float b, float a = 1) - : this() => this.Pack(r, g, b, a); + : this(new Vector4(r, g, b, a)) + { + } /// /// Initializes a new instance of the struct. @@ -99,9 +95,11 @@ public Argb32(float r, float g, float b, float a = 1) /// /// The vector containing the components for the packed vector. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public Argb32(Vector3 vector) - : this() => this.Pack(ref vector); + : this(new Vector4(vector, 1f)) + { + } /// /// Initializes a new instance of the struct. @@ -109,9 +107,9 @@ public Argb32(Vector3 vector) /// /// The vector containing the components for the packed vector. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public Argb32(Vector4 vector) - : this() => this.Pack(ref vector); + : this() => this = Pack(vector); /// /// Initializes a new instance of the struct. @@ -119,7 +117,7 @@ public Argb32(Vector4 vector) /// /// The packed value. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public Argb32(uint packed) : this() => this.Argb = packed; @@ -128,39 +126,23 @@ public Argb32(uint packed) /// public uint Argb { - [MethodImpl(InliningOptions.ShortMethod)] - readonly get => Unsafe.As(ref Unsafe.AsRef(this)); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + readonly get => Unsafe.As(ref Unsafe.AsRef(in this)); - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] set => Unsafe.As(ref this) = value; } /// public uint PackedValue { - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get => this.Argb; - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] set => this.Argb = value; } - /// - /// Converts an to . - /// - /// The . - /// The . - [MethodImpl(InliningOptions.ShortMethod)] - public static implicit operator Color(Argb32 source) => new(source); - - /// - /// Converts a to . - /// - /// The . - /// The . - [MethodImpl(InliningOptions.ShortMethod)] - public static implicit operator Argb32(Color color) => color.ToArgb32(); - /// /// Compares two objects for equality. /// @@ -169,7 +151,7 @@ public uint PackedValue /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Argb32 left, Argb32 right) => left.Equals(right); /// @@ -180,163 +162,117 @@ public uint PackedValue /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Argb32 left, Argb32 right) => !left.Equals(right); /// - public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Rgba32 ToRgba32() => Rgba32.FromArgb32(this); /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Vector4 ToScaledVector4() => this.ToVector4(); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromVector4(Vector4 vector) => this.Pack(ref vector); - - /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Vector4 ToVector4() => new Vector4(this.R, this.G, this.B, this.A) / MaxBytes; + /// + public static PixelTypeInfo GetPixelTypeInfo() + => PixelTypeInfo.Create( + PixelComponentInfo.Create(4, 8, 8, 8, 8), + PixelColorType.Alpha | PixelColorType.RGB, + PixelAlphaRepresentation.Unassociated); + + /// + public static PixelOperations CreatePixelOperations() => new PixelOperations(); + /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromArgb32(Argb32 source) => this.PackedValue = source.PackedValue; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Argb32 FromScaledVector4(Vector4 source) => FromVector4(source); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Argb32 FromVector4(Vector4 source) => Pack(source); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgr24(Bgr24 source) - { - this.R = source.R; - this.G = source.G; - this.B = source.B; - this.A = byte.MaxValue; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Argb32 FromAbgr32(Abgr32 source) => new(source.R, source.G, source.B, source.A); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra32(Bgra32 source) - { - this.R = source.R; - this.G = source.G; - this.B = source.B; - this.A = source.A; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Argb32 FromArgb32(Argb32 source) => new() { PackedValue = source.PackedValue }; + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Argb32 FromBgra5551(Bgra5551 source) => FromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromAbgr32(Abgr32 source) - { - this.R = source.R; - this.G = source.G; - this.B = source.B; - this.A = source.A; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Argb32 FromBgr24(Bgr24 source) => new(source.R, source.G, source.B); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL8(L8 source) - { - this.R = source.PackedValue; - this.G = source.PackedValue; - this.B = source.PackedValue; - this.A = byte.MaxValue; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Argb32 FromBgra32(Bgra32 source) => new(source.R, source.G, source.B, source.A); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL16(L16 source) - { - byte rgb = ColorNumerics.DownScaleFrom16BitTo8Bit(source.PackedValue); - this.R = rgb; - this.G = rgb; - this.B = rgb; - this.A = byte.MaxValue; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Argb32 FromL8(L8 source) => new(source.PackedValue, source.PackedValue, source.PackedValue); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa16(La16 source) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Argb32 FromL16(L16 source) { - this.R = source.L; - this.G = source.L; - this.B = source.L; - this.A = source.A; + byte rgb = ColorNumerics.From16BitTo8Bit(source.PackedValue); + return new(rgb, rgb, rgb); } /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa32(La32 source) - { - byte rgb = ColorNumerics.DownScaleFrom16BitTo8Bit(source.L); - this.R = rgb; - this.G = rgb; - this.B = rgb; - this.A = ColorNumerics.DownScaleFrom16BitTo8Bit(source.A); - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Argb32 FromLa16(La16 source) => new(source.L, source.L, source.L, source.A); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb24(Rgb24 source) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Argb32 FromLa32(La32 source) { - this.R = source.R; - this.G = source.G; - this.B = source.B; - this.A = byte.MaxValue; + byte rgb = ColorNumerics.From16BitTo8Bit(source.L); + return new(rgb, rgb, rgb, ColorNumerics.From16BitTo8Bit(source.A)); } /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba32(Rgba32 source) - { - this.R = source.R; - this.G = source.G; - this.B = source.B; - this.A = source.A; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Argb32 FromRgb24(Rgb24 source) => new(source.R, source.G, source.B); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void ToRgba32(ref Rgba32 dest) - { - dest.R = this.R; - dest.G = this.G; - dest.B = this.B; - dest.A = this.A; - } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Argb32 FromRgba32(Rgba32 source) => new(source.R, source.G, source.B, source.A); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb48(Rgb48 source) - { - this.R = ColorNumerics.DownScaleFrom16BitTo8Bit(source.R); - this.G = ColorNumerics.DownScaleFrom16BitTo8Bit(source.G); - this.B = ColorNumerics.DownScaleFrom16BitTo8Bit(source.B); - this.A = byte.MaxValue; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Argb32 FromRgb48(Rgb48 source) + => new() + { + R = ColorNumerics.From16BitTo8Bit(source.R), + G = ColorNumerics.From16BitTo8Bit(source.G), + B = ColorNumerics.From16BitTo8Bit(source.B), + A = byte.MaxValue + }; /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba64(Rgba64 source) - { - this.R = ColorNumerics.DownScaleFrom16BitTo8Bit(source.R); - this.G = ColorNumerics.DownScaleFrom16BitTo8Bit(source.G); - this.B = ColorNumerics.DownScaleFrom16BitTo8Bit(source.B); - this.A = ColorNumerics.DownScaleFrom16BitTo8Bit(source.A); - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Argb32 FromRgba64(Rgba64 source) + => new() + { + R = ColorNumerics.From16BitTo8Bit(source.R), + G = ColorNumerics.From16BitTo8Bit(source.G), + B = ColorNumerics.From16BitTo8Bit(source.B), + A = ColorNumerics.From16BitTo8Bit(source.A) + }; /// public override readonly bool Equals(object? obj) => obj is Argb32 argb32 && this.Equals(argb32); /// - [MethodImpl(InliningOptions.ShortMethod)] public readonly bool Equals(Argb32 other) => this.Argb == other.Argb; /// @@ -346,48 +282,20 @@ public void FromRgba64(Rgba64 source) public override readonly string ToString() => $"Argb({this.A}, {this.R}, {this.G}, {this.B})"; /// - [MethodImpl(InliningOptions.ShortMethod)] public override readonly int GetHashCode() => this.Argb.GetHashCode(); - /// - /// Packs the four floats into a color. - /// - /// The x-component - /// The y-component - /// The z-component - /// The w-component - [MethodImpl(InliningOptions.ShortMethod)] - private void Pack(float x, float y, float z, float w) - { - var value = new Vector4(x, y, z, w); - this.Pack(ref value); - } - - /// - /// Packs a into a uint. - /// - /// The vector containing the values to pack. - [MethodImpl(InliningOptions.ShortMethod)] - private void Pack(ref Vector3 vector) - { - var value = new Vector4(vector, 1); - this.Pack(ref value); - } - /// /// Packs a into a color. /// /// The vector containing the values to pack. - [MethodImpl(InliningOptions.ShortMethod)] - private void Pack(ref Vector4 vector) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static Argb32 Pack(Vector4 vector) { vector *= MaxBytes; vector += Half; vector = Numerics.Clamp(vector, Vector4.Zero, MaxBytes); - this.R = (byte)vector.X; - this.G = (byte)vector.Y; - this.B = (byte)vector.Z; - this.A = (byte)vector.W; + Vector128 result = Vector128.ConvertToInt32(vector.AsVector128()).AsByte(); + return new(result.GetElement(0), result.GetElement(4), result.GetElement(8), result.GetElement(12)); } } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Bgr24.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgr24.cs index aedf4ad198..a860edc567 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Bgr24.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Bgr24.cs @@ -4,6 +4,7 @@ using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; namespace SixLabors.ImageSharp.PixelFormats; @@ -35,13 +36,16 @@ public partial struct Bgr24 : IPixel [FieldOffset(2)] public byte R; + private static readonly Vector4 MaxBytes = Vector128.Create(255f).AsVector4(); + private static readonly Vector4 Half = Vector128.Create(.5f).AsVector4(); + /// /// Initializes a new instance of the struct. /// /// The red component. /// The green component. /// The blue component. - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public Bgr24(byte r, byte g, byte b) { this.R = r; @@ -49,22 +53,6 @@ public Bgr24(byte r, byte g, byte b) this.B = b; } - /// - /// Converts an to . - /// - /// The . - /// The . - [MethodImpl(InliningOptions.ShortMethod)] - public static implicit operator Color(Bgr24 source) => new(source); - - /// - /// Converts a to . - /// - /// The . - /// The . - [MethodImpl(InliningOptions.ShortMethod)] - public static implicit operator Bgr24(Color color) => color.ToBgr24(); - /// /// Compares two objects for equality. /// @@ -73,7 +61,7 @@ public Bgr24(byte r, byte g, byte b) /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Bgr24 left, Bgr24 right) => left.Equals(right); /// @@ -84,150 +72,120 @@ public Bgr24(byte r, byte g, byte b) /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Bgr24 left, Bgr24 right) => !left.Equals(right); - /// - public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Rgba32 ToRgba32() => Rgba32.FromBgr24(this); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Vector4 ToScaledVector4() => this.ToVector4(); /// - [MethodImpl(InliningOptions.ShortMethod)] - public readonly Vector4 ToScaledVector4() => this.ToVector4(); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Vector4 ToVector4() => new Vector4(this.R, this.G, this.B, byte.MaxValue) / MaxBytes; + + /// + public static PixelTypeInfo GetPixelTypeInfo() + => PixelTypeInfo.Create( + PixelComponentInfo.Create(3, 8, 8, 8), + PixelColorType.BGR, + PixelAlphaRepresentation.None); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromVector4(Vector4 vector) - { - Rgba32 rgba = default; - rgba.FromVector4(vector); - this.FromRgba32(rgba); - } + public static PixelOperations CreatePixelOperations() => new PixelOperations(); /// - [MethodImpl(InliningOptions.ShortMethod)] - public readonly Vector4 ToVector4() => new Rgba32(this.R, this.G, this.B, byte.MaxValue).ToVector4(); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgr24 FromScaledVector4(Vector4 source) => FromVector4(source); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromArgb32(Argb32 source) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgr24 FromVector4(Vector4 source) { - this.R = source.R; - this.G = source.G; - this.B = source.B; + source *= MaxBytes; + source += Half; + source = Numerics.Clamp(source, Vector4.Zero, MaxBytes); + + Vector128 result = Vector128.ConvertToInt32(source.AsVector128()).AsByte(); + return new(result.GetElement(0), result.GetElement(4), result.GetElement(8)); } /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgr24(Bgr24 source) => this = source; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgr24 FromAbgr32(Abgr32 source) => new(source.R, source.G, source.B); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgr24 FromArgb32(Argb32 source) => new(source.R, source.G, source.B); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra32(Bgra32 source) - { - this.R = source.R; - this.G = source.G; - this.B = source.B; - } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgr24 FromBgra5551(Bgra5551 source) => FromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL8(L8 source) - { - this.R = source.PackedValue; - this.G = source.PackedValue; - this.B = source.PackedValue; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgr24 FromBgr24(Bgr24 source) => new(source.R, source.G, source.B); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL16(L16 source) - { - byte rgb = ColorNumerics.DownScaleFrom16BitTo8Bit(source.PackedValue); - this.R = rgb; - this.G = rgb; - this.B = rgb; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgr24 FromBgra32(Bgra32 source) => new(source.R, source.G, source.B); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa16(La16 source) - { - this.R = source.L; - this.G = source.L; - this.B = source.L; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgr24 FromL8(L8 source) => new(source.PackedValue, source.PackedValue, source.PackedValue); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa32(La32 source) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgr24 FromL16(L16 source) { - byte rgb = ColorNumerics.DownScaleFrom16BitTo8Bit(source.L); - this.R = rgb; - this.G = rgb; - this.B = rgb; + byte rgb = ColorNumerics.From16BitTo8Bit(source.PackedValue); + return new(rgb, rgb, rgb); } /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb24(Rgb24 source) - { - this.R = source.R; - this.G = source.G; - this.B = source.B; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgr24 FromLa16(La16 source) => new(source.L, source.L, source.L); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromAbgr32(Abgr32 source) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgr24 FromLa32(La32 source) { - // We can assign this instances value directly to last three bytes of the Abgr32. - ref byte sourceRef = ref Unsafe.As(ref source); - ref byte sourceRefFromB = ref Unsafe.AddByteOffset(ref sourceRef, 1); - this = Unsafe.As(ref sourceRefFromB); + byte rgb = ColorNumerics.From16BitTo8Bit(source.L); + return new(rgb, rgb, rgb); } /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba32(Rgba32 source) => this = source.Bgr; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgr24 FromRgb24(Rgb24 source) => new(source.R, source.G, source.B); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void ToRgba32(ref Rgba32 dest) - { - dest.R = this.R; - dest.G = this.G; - dest.B = this.B; - dest.A = byte.MaxValue; - } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgr24 FromRgba32(Rgba32 source) => new(source.R, source.G, source.B); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb48(Rgb48 source) - { - this.R = ColorNumerics.DownScaleFrom16BitTo8Bit(source.R); - this.G = ColorNumerics.DownScaleFrom16BitTo8Bit(source.G); - this.B = ColorNumerics.DownScaleFrom16BitTo8Bit(source.B); - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgr24 FromRgb48(Rgb48 source) + => new() + { + R = ColorNumerics.From16BitTo8Bit(source.R), + G = ColorNumerics.From16BitTo8Bit(source.G), + B = ColorNumerics.From16BitTo8Bit(source.B) + }; /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba64(Rgba64 source) - { - this.R = ColorNumerics.DownScaleFrom16BitTo8Bit(source.R); - this.G = ColorNumerics.DownScaleFrom16BitTo8Bit(source.G); - this.B = ColorNumerics.DownScaleFrom16BitTo8Bit(source.B); - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgr24 FromRgba64(Rgba64 source) + => new() + { + R = ColorNumerics.From16BitTo8Bit(source.R), + G = ColorNumerics.From16BitTo8Bit(source.G), + B = ColorNumerics.From16BitTo8Bit(source.B) + }; /// - [MethodImpl(InliningOptions.ShortMethod)] public readonly bool Equals(Bgr24 other) => this.R.Equals(other.R) && this.G.Equals(other.G) && this.B.Equals(other.B); /// @@ -237,6 +195,5 @@ public void FromRgba64(Rgba64 source) public override readonly string ToString() => $"Bgr24({this.B}, {this.G}, {this.R})"; /// - [MethodImpl(InliningOptions.ShortMethod)] public override readonly int GetHashCode() => HashCode.Combine(this.R, this.B, this.G); } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Bgr565.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgr565.cs index ac3b6f8299..87055bf22d 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Bgr565.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Bgr565.cs @@ -13,7 +13,13 @@ namespace SixLabors.ImageSharp.PixelFormats; /// Ranges from [0, 0, 0, 1] to [1, 1, 1, 1] in vector form. /// /// -public partial struct Bgr565 : IPixel, IPackedVector +/// +/// Initializes a new instance of the struct. +/// +/// +/// The vector containing the components for the packed value. +/// +public partial struct Bgr565(Vector3 vector) : IPixel, IPackedVector { /// /// Initializes a new instance of the struct. @@ -26,16 +32,8 @@ public Bgr565(float x, float y, float z) { } - /// - /// Initializes a new instance of the struct. - /// - /// - /// The vector containing the components for the packed value. - /// - public Bgr565(Vector3 vector) => this.PackedValue = Pack(ref vector); - /// - public ushort PackedValue { get; set; } + public ushort PackedValue { get; set; } = Pack(vector); /// /// Compares two objects for equality. @@ -45,7 +43,7 @@ public Bgr565(float x, float y, float z) /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Bgr565 left, Bgr565 right) => left.Equals(right); /// @@ -56,94 +54,96 @@ public Bgr565(float x, float y, float z) /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Bgr565 left, Bgr565 right) => !left.Equals(right); - /// - public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector); - /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Vector4 ToScaledVector4() => this.ToVector4(); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromVector4(Vector4 vector) - { - var vector3 = new Vector3(vector.X, vector.Y, vector.Z); - this.PackedValue = Pack(ref vector3); - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Vector4 ToVector4() => new(this.ToVector3(), 1F); /// - [MethodImpl(InliningOptions.ShortMethod)] - public readonly Vector4 ToVector4() => new(this.ToVector3(), 1F); + public static PixelTypeInfo GetPixelTypeInfo() + => PixelTypeInfo.Create( + PixelComponentInfo.Create(3, 5, 6, 5), + PixelColorType.BGR, + PixelAlphaRepresentation.None); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromArgb32(Argb32 source) => this.FromVector4(source.ToVector4()); + /// + public static PixelOperations CreatePixelOperations() => new PixelOperations(); + + /// + public readonly Rgba32 ToRgba32() => Rgba32.FromScaledVector4(this.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra5551(Bgra5551 source) => this.FromVector4(source.ToVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgr565 FromScaledVector4(Vector4 source) => FromVector4(source); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgr24(Bgr24 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgr565 FromVector4(Vector4 source) => new() { PackedValue = Pack(new Vector3(source.X, source.Y, source.Z)) }; - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra32(Bgra32 source) => this.FromVector4(source.ToVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgr565 FromAbgr32(Abgr32 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromAbgr32(Abgr32 source) => this.FromVector4(source.ToVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgr565 FromArgb32(Argb32 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL8(L8 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgr565 FromBgra5551(Bgra5551 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL16(L16 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgr565 FromBgr24(Bgr24 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa16(La16 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgr565 FromBgra32(Bgra32 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa32(La32 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgr565 FromL8(L8 source) => FromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb24(Rgb24 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgr565 FromL16(L16 source) => FromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba32(Rgba32 source) => this.FromVector4(source.ToVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgr565 FromLa16(La16 source) => FromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void ToRgba32(ref Rgba32 dest) => dest.FromScaledVector4(this.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgr565 FromLa32(La32 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb48(Rgb48 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgr565 FromRgb24(Rgb24 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgr565 FromRgba32(Rgba32 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgr565 FromRgb48(Rgb48 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgr565 FromRgba64(Rgba64 source) => FromScaledVector4(source.ToScaledVector4()); /// /// Expands the packed representation into a . /// The vector components are typically expanded in least to greatest significance order. /// /// The . - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Vector3 ToVector3() => new( ((this.PackedValue >> 11) & 0x1F) * (1F / 31F), ((this.PackedValue >> 5) & 0x3F) * (1F / 63F), @@ -153,22 +153,20 @@ public void FromVector4(Vector4 vector) public override readonly bool Equals(object? obj) => obj is Bgr565 other && this.Equals(other); /// - [MethodImpl(InliningOptions.ShortMethod)] public readonly bool Equals(Bgr565 other) => this.PackedValue.Equals(other.PackedValue); /// public override readonly string ToString() { - var vector = this.ToVector3(); + Vector3 vector = this.ToVector3(); return FormattableString.Invariant($"Bgr565({vector.Z:#0.##}, {vector.Y:#0.##}, {vector.X:#0.##})"); } /// - [MethodImpl(InliningOptions.ShortMethod)] public override readonly int GetHashCode() => this.PackedValue.GetHashCode(); - [MethodImpl(InliningOptions.ShortMethod)] - private static ushort Pack(ref Vector3 vector) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static ushort Pack(Vector3 vector) { vector = Vector3.Clamp(vector, Vector3.Zero, Vector3.One); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs index 6b859cda64..0fe7e4cc2c 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs @@ -4,6 +4,7 @@ using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; namespace SixLabors.ImageSharp.PixelFormats; @@ -38,15 +39,8 @@ public partial struct Bgra32 : IPixel, IPackedVector /// public byte A; - /// - /// The maximum byte value. - /// - private static readonly Vector4 MaxBytes = new(255); - - /// - /// The half vector value. - /// - private static readonly Vector4 Half = new(0.5F); + private static readonly Vector4 MaxBytes = Vector128.Create(255f).AsVector4(); + private static readonly Vector4 Half = Vector128.Create(.5f).AsVector4(); /// /// Initializes a new instance of the struct. @@ -54,7 +48,7 @@ public partial struct Bgra32 : IPixel, IPackedVector /// The red component. /// The green component. /// The blue component. - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public Bgra32(byte r, byte g, byte b) { this.R = r; @@ -70,7 +64,7 @@ public Bgra32(byte r, byte g, byte b) /// The green component. /// The blue component. /// The alpha component. - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public Bgra32(byte r, byte g, byte b, byte a) { this.R = r; @@ -84,10 +78,10 @@ public Bgra32(byte r, byte g, byte b, byte a) /// public uint Bgra { - [MethodImpl(InliningOptions.ShortMethod)] - readonly get => Unsafe.As(ref Unsafe.AsRef(this)); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + readonly get => Unsafe.As(ref Unsafe.AsRef(in this)); - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] set => Unsafe.As(ref this) = value; } @@ -98,22 +92,6 @@ public uint PackedValue set => this.Bgra = value; } - /// - /// Converts an to . - /// - /// The . - /// The . - [MethodImpl(InliningOptions.ShortMethod)] - public static implicit operator Color(Bgra32 source) => new(source); - - /// - /// Converts a to . - /// - /// The . - /// The . - [MethodImpl(InliningOptions.ShortMethod)] - public static implicit operator Bgra32(Color color) => color.ToBgra32(); - /// /// Compares two objects for equality. /// @@ -122,7 +100,7 @@ public uint PackedValue /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Bgra32 left, Bgra32 right) => left.Equals(right); /// @@ -133,157 +111,112 @@ public uint PackedValue /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Bgra32 left, Bgra32 right) => !left.Equals(right); - /// - public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Rgba32 ToRgba32() => Rgba32.FromBgra32(this); /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Vector4 ToScaledVector4() => this.ToVector4(); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromVector4(Vector4 vector) => this.Pack(vector); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Vector4 ToVector4() => new Vector4(this.R, this.G, this.B, this.A) / MaxBytes; + + /// + public static PixelTypeInfo GetPixelTypeInfo() + => PixelTypeInfo.Create( + PixelComponentInfo.Create(4, 8, 8, 8, 8), + PixelColorType.BGR | PixelColorType.Alpha, + PixelAlphaRepresentation.Unassociated); /// - [MethodImpl(InliningOptions.ShortMethod)] - public readonly Vector4 ToVector4() => new Vector4(this.R, this.G, this.B, this.A) / MaxBytes; + public static PixelOperations CreatePixelOperations() => new PixelOperations(); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromArgb32(Argb32 source) - { - this.R = source.R; - this.G = source.G; - this.B = source.B; - this.A = source.A; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgra32 FromScaledVector4(Vector4 source) => FromVector4(source); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromAbgr32(Abgr32 source) - { - this.R = source.R; - this.G = source.G; - this.B = source.B; - this.A = source.A; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgra32 FromVector4(Vector4 source) => Pack(source); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgr24(Bgr24 source) - { - this.R = source.R; - this.G = source.G; - this.B = source.B; - this.A = byte.MaxValue; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgra32 FromAbgr32(Abgr32 source) => new(source.R, source.G, source.B, source.A); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgra32 FromArgb32(Argb32 source) => new(source.R, source.G, source.B, source.A); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgra32 FromBgra5551(Bgra5551 source) => FromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra32(Bgra32 source) => this = source; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgra32 FromBgr24(Bgr24 source) => new(source.R, source.G, source.B); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL8(L8 source) - { - this.R = source.PackedValue; - this.G = source.PackedValue; - this.B = source.PackedValue; - this.A = byte.MaxValue; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgra32 FromBgra32(Bgra32 source) => new() { PackedValue = source.PackedValue }; /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL16(L16 source) - { - byte rgb = ColorNumerics.DownScaleFrom16BitTo8Bit(source.PackedValue); - this.R = rgb; - this.G = rgb; - this.B = rgb; - this.A = byte.MaxValue; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgra32 FromL8(L8 source) => new(source.PackedValue, source.PackedValue, source.PackedValue); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa16(La16 source) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgra32 FromL16(L16 source) { - this.R = source.L; - this.G = source.L; - this.B = source.L; - this.A = source.A; + byte rgb = ColorNumerics.From16BitTo8Bit(source.PackedValue); + return new(rgb, rgb, rgb); } /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa32(La32 source) - { - byte rgb = ColorNumerics.DownScaleFrom16BitTo8Bit(source.L); - this.R = rgb; - this.G = rgb; - this.B = rgb; - this.A = ColorNumerics.DownScaleFrom16BitTo8Bit(source.A); - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgra32 FromLa16(La16 source) => new(source.L, source.L, source.L, source.A); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba32(Rgba32 source) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgra32 FromLa32(La32 source) { - this.R = source.R; - this.G = source.G; - this.B = source.B; - this.A = source.A; + byte rgb = ColorNumerics.From16BitTo8Bit(source.L); + return new(rgb, rgb, rgb, ColorNumerics.From16BitTo8Bit(source.A)); } /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb24(Rgb24 source) - { - this.R = source.R; - this.G = source.G; - this.B = source.B; - this.A = byte.MaxValue; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgra32 FromRgb24(Rgb24 source) => new(source.R, source.G, source.B); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void ToRgba32(ref Rgba32 dest) - { - dest.R = this.R; - dest.G = this.G; - dest.B = this.B; - dest.A = this.A; - } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgra32 FromRgba32(Rgba32 source) => new(source.R, source.G, source.B, source.A); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb48(Rgb48 source) - { - this.R = ColorNumerics.DownScaleFrom16BitTo8Bit(source.R); - this.G = ColorNumerics.DownScaleFrom16BitTo8Bit(source.G); - this.B = ColorNumerics.DownScaleFrom16BitTo8Bit(source.B); - this.A = byte.MaxValue; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgra32 FromRgb48(Rgb48 source) + => new() + { + R = ColorNumerics.From16BitTo8Bit(source.R), + G = ColorNumerics.From16BitTo8Bit(source.G), + B = ColorNumerics.From16BitTo8Bit(source.B), + A = byte.MaxValue + }; /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba64(Rgba64 source) - { - this.R = ColorNumerics.DownScaleFrom16BitTo8Bit(source.R); - this.G = ColorNumerics.DownScaleFrom16BitTo8Bit(source.G); - this.B = ColorNumerics.DownScaleFrom16BitTo8Bit(source.B); - this.A = ColorNumerics.DownScaleFrom16BitTo8Bit(source.A); - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgra32 FromRgba64(Rgba64 source) + => new() + { + R = ColorNumerics.From16BitTo8Bit(source.R), + G = ColorNumerics.From16BitTo8Bit(source.G), + B = ColorNumerics.From16BitTo8Bit(source.B), + A = ColorNumerics.From16BitTo8Bit(source.A) + }; /// public override readonly bool Equals(object? obj) => obj is Bgra32 other && this.Equals(other); @@ -301,16 +234,14 @@ public void FromRgba64(Rgba64 source) /// Packs a into a color. /// /// The vector containing the values to pack. - [MethodImpl(InliningOptions.ShortMethod)] - private void Pack(Vector4 vector) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static Bgra32 Pack(Vector4 vector) { vector *= MaxBytes; vector += Half; vector = Numerics.Clamp(vector, Vector4.Zero, MaxBytes); - this.R = (byte)vector.X; - this.G = (byte)vector.Y; - this.B = (byte)vector.Z; - this.A = (byte)vector.W; + Vector128 result = Vector128.ConvertToInt32(vector.AsVector128()).AsByte(); + return new(result.GetElement(0), result.GetElement(4), result.GetElement(8), result.GetElement(12)); } } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra4444.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra4444.cs index 8ba32c8ac2..55971210c3 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra4444.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra4444.cs @@ -30,7 +30,7 @@ public Bgra4444(float x, float y, float z, float w) /// Initializes a new instance of the struct. /// /// The vector containing the components for the packed vector. - public Bgra4444(Vector4 vector) => this.PackedValue = Pack(ref vector); + public Bgra4444(Vector4 vector) => this.PackedValue = Pack(vector); /// public ushort PackedValue { get; set; } @@ -43,7 +43,7 @@ public Bgra4444(float x, float y, float z, float w) /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Bgra4444 left, Bgra4444 right) => left.Equals(right); /// @@ -54,113 +54,118 @@ public Bgra4444(float x, float y, float z, float w) /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Bgra4444 left, Bgra4444 right) => !left.Equals(right); /// - public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Rgba32 ToRgba32() => Rgba32.FromScaledVector4(this.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector); - - /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Vector4 ToScaledVector4() => this.ToVector4(); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector); - - /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Vector4 ToVector4() { - const float Max = 1 / 15F; + const float max = 1 / 15f; return new Vector4( (this.PackedValue >> 8) & 0x0F, (this.PackedValue >> 4) & 0x0F, this.PackedValue & 0x0F, - (this.PackedValue >> 12) & 0x0F) * Max; + (this.PackedValue >> 12) & 0x0F) * max; } /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromArgb32(Argb32 source) => this.FromScaledVector4(source.ToScaledVector4()); + public static PixelTypeInfo GetPixelTypeInfo() + => PixelTypeInfo.Create( + PixelComponentInfo.Create(4, 4, 4, 4, 4), + PixelColorType.BGR | PixelColorType.Alpha, + PixelAlphaRepresentation.Unassociated); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4()); + public static PixelOperations CreatePixelOperations() => new PixelOperations(); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgra4444 FromScaledVector4(Vector4 source) => FromVector4(source); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgr24(Bgr24 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgra4444 FromVector4(Vector4 source) => new() { PackedValue = Pack(source) }; /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgra4444 FromAbgr32(Abgr32 source) => FromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromAbgr32(Abgr32 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgra4444 FromArgb32(Argb32 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL8(L8 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgra4444 FromBgra5551(Bgra5551 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL16(L16 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgra4444 FromBgr24(Bgr24 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa16(La16 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgra4444 FromBgra32(Bgra32 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa32(La32 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgra4444 FromL8(L8 source) => FromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb24(Rgb24 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgra4444 FromL16(L16 source) => FromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba32(Rgba32 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgra4444 FromLa16(La16 source) => FromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void ToRgba32(ref Rgba32 dest) => dest.FromScaledVector4(this.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgra4444 FromLa32(La32 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb48(Rgb48 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgra4444 FromRgb24(Rgb24 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgra4444 FromRgba32(Rgba32 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgra4444 FromRgb48(Rgb48 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgra4444 FromRgba64(Rgba64 source) => FromScaledVector4(source.ToScaledVector4()); /// public override readonly bool Equals(object? obj) => obj is Bgra4444 other && this.Equals(other); /// - [MethodImpl(InliningOptions.ShortMethod)] public readonly bool Equals(Bgra4444 other) => this.PackedValue.Equals(other.PackedValue); /// public override readonly string ToString() { - var vector = this.ToVector4(); + Vector4 vector = this.ToVector4(); return FormattableString.Invariant($"Bgra4444({vector.Z:#0.##}, {vector.Y:#0.##}, {vector.X:#0.##}, {vector.W:#0.##})"); } /// - [MethodImpl(InliningOptions.ShortMethod)] public override readonly int GetHashCode() => this.PackedValue.GetHashCode(); - [MethodImpl(InliningOptions.ShortMethod)] - private static ushort Pack(ref Vector4 vector) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static ushort Pack(Vector4 vector) { vector = Numerics.Clamp(vector, Vector4.Zero, Vector4.One); return (ushort)((((int)Math.Round(vector.W * 15F) & 0x0F) << 12) diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra5551.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra5551.cs index c282f03d89..4c94dea5f1 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra5551.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra5551.cs @@ -33,7 +33,7 @@ public Bgra5551(float x, float y, float z, float w) /// /// The vector containing the components for the packed vector. /// - public Bgra5551(Vector4 vector) => this.PackedValue = Pack(ref vector); + public Bgra5551(Vector4 vector) => this.PackedValue = Pack(vector); /// public ushort PackedValue { get; set; } @@ -46,7 +46,7 @@ public Bgra5551(float x, float y, float z, float w) /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Bgra5551 left, Bgra5551 right) => left.Equals(right); /// @@ -57,26 +57,19 @@ public Bgra5551(float x, float y, float z, float w) /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Bgra5551 left, Bgra5551 right) => !left.Equals(right); /// - public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Rgba32 ToRgba32() => Rgba32.FromScaledVector4(this.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector); - - /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Vector4 ToScaledVector4() => this.ToVector4(); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector); - - /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Vector4 ToVector4() => new( ((this.PackedValue >> 10) & 0x1F) / 31F, ((this.PackedValue >> 5) & 0x1F) / 31F, @@ -84,81 +77,93 @@ public Bgra5551(float x, float y, float z, float w) (this.PackedValue >> 15) & 0x01); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra5551(Bgra5551 source) => this = source; + public static PixelTypeInfo GetPixelTypeInfo() + => PixelTypeInfo.Create( + PixelComponentInfo.Create(4, 5, 5, 5, 1), + PixelColorType.BGR | PixelColorType.Alpha, + PixelAlphaRepresentation.Unassociated); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromArgb32(Argb32 source) => this.FromScaledVector4(source.ToScaledVector4()); + public static PixelOperations CreatePixelOperations() => new PixelOperations(); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgra5551 FromScaledVector4(Vector4 source) => FromVector4(source); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgr24(Bgr24 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgra5551 FromVector4(Vector4 source) => new() { PackedValue = Pack(source) }; /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgra5551 FromAbgr32(Abgr32 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL8(L8 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgra5551 FromArgb32(Argb32 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL16(L16 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgra5551 FromBgra5551(Bgra5551 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa16(La16 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgra5551 FromBgr24(Bgr24 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa32(La32 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgra5551 FromBgra32(Bgra32 source) => FromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb24(Rgb24 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgra5551 FromL8(L8 source) => FromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba32(Rgba32 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgra5551 FromL16(L16 source) => FromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromAbgr32(Abgr32 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgra5551 FromLa16(La16 source) => FromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void ToRgba32(ref Rgba32 dest) => dest.FromScaledVector4(this.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgra5551 FromLa32(La32 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb48(Rgb48 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgra5551 FromRgb24(Rgb24 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgra5551 FromRgba32(Rgba32 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgra5551 FromRgb48(Rgb48 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgra5551 FromRgba64(Rgba64 source) => FromScaledVector4(source.ToScaledVector4()); /// - public override bool Equals(object? obj) => obj is Bgra5551 other && this.Equals(other); + public override readonly bool Equals(object? obj) => obj is Bgra5551 other && this.Equals(other); /// - [MethodImpl(InliningOptions.ShortMethod)] public readonly bool Equals(Bgra5551 other) => this.PackedValue.Equals(other.PackedValue); /// public override readonly string ToString() { - var vector = this.ToVector4(); + Vector4 vector = this.ToVector4(); return FormattableString.Invariant($"Bgra5551({vector.Z:#0.##}, {vector.Y:#0.##}, {vector.X:#0.##}, {vector.W:#0.##})"); } /// - [MethodImpl(InliningOptions.ShortMethod)] public override readonly int GetHashCode() => this.PackedValue.GetHashCode(); - [MethodImpl(InliningOptions.ShortMethod)] - private static ushort Pack(ref Vector4 vector) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static ushort Pack(Vector4 vector) { vector = Numerics.Clamp(vector, Vector4.Zero, Vector4.One); return (ushort)( diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Byte4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Byte4.cs index e699e5fe58..680a7ee0bd 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Byte4.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Byte4.cs @@ -3,6 +3,7 @@ using System.Numerics; using System.Runtime.CompilerServices; +using System.Runtime.Intrinsics; namespace SixLabors.ImageSharp.PixelFormats; @@ -14,13 +15,7 @@ namespace SixLabors.ImageSharp.PixelFormats; /// public partial struct Byte4 : IPixel, IPackedVector { - /// - /// Initializes a new instance of the struct. - /// - /// - /// A vector containing the initial values for the components of the Byte4 structure. - /// - public Byte4(Vector4 vector) => this.PackedValue = Pack(ref vector); + private static readonly Vector4 MaxBytes = Vector128.Create(255f).AsVector4(); /// /// Initializes a new instance of the struct. @@ -30,11 +25,18 @@ public partial struct Byte4 : IPixel, IPackedVector /// The z-component /// The w-component public Byte4(float x, float y, float z, float w) + : this(new Vector4(x, y, z, w)) { - var vector = new Vector4(x, y, z, w); - this.PackedValue = Pack(ref vector); } + /// + /// Initializes a new instance of the struct. + /// + /// + /// A vector containing the initial values for the components of the Byte4 structure. + /// + public Byte4(Vector4 vector) => this.PackedValue = Pack(vector); + /// public uint PackedValue { get; set; } @@ -46,7 +48,7 @@ public Byte4(float x, float y, float z, float w) /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Byte4 left, Byte4 right) => left.Equals(right); /// @@ -57,103 +59,108 @@ public Byte4(float x, float y, float z, float w) /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Byte4 left, Byte4 right) => !left.Equals(right); /// - public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Rgba32 ToRgba32() => new() { PackedValue = this.PackedValue }; /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector * 255F); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Vector4 ToScaledVector4() => this.ToVector4() / 255f; - /// - [MethodImpl(InliningOptions.ShortMethod)] - public readonly Vector4 ToScaledVector4() => this.ToVector4() / 255F; + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Vector4 ToVector4() => new( + this.PackedValue & 0xFF, + (this.PackedValue >> 8) & 0xFF, + (this.PackedValue >> 16) & 0xFF, + (this.PackedValue >> 24) & 0xFF); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector); + public static PixelTypeInfo GetPixelTypeInfo() + => PixelTypeInfo.Create( + PixelComponentInfo.Create(4, 8, 8, 8, 8), + PixelColorType.RGB | PixelColorType.Alpha, + PixelAlphaRepresentation.Unassociated); /// - [MethodImpl(InliningOptions.ShortMethod)] - public readonly Vector4 ToVector4() => new( - this.PackedValue & 0xFF, - (this.PackedValue >> 0x8) & 0xFF, - (this.PackedValue >> 0x10) & 0xFF, - (this.PackedValue >> 0x18) & 0xFF); + public static PixelOperations CreatePixelOperations() => new PixelOperations(); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Byte4 FromScaledVector4(Vector4 source) => FromVector4(source * 255f); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromArgb32(Argb32 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Byte4 FromVector4(Vector4 source) => new() { PackedValue = Pack(source) }; /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgr24(Bgr24 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Byte4 FromAbgr32(Abgr32 source) => FromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Byte4 FromArgb32(Argb32 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL8(L8 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Byte4 FromBgra5551(Bgra5551 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL16(L16 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Byte4 FromBgr24(Bgr24 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa16(La16 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Byte4 FromBgra32(Bgra32 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa32(La32 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Byte4 FromL8(L8 source) => FromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb24(Rgb24 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Byte4 FromL16(L16 source) => FromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Byte4 FromLa16(La16 source) => FromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba32(Rgba32 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Byte4 FromLa32(La32 source) => FromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromAbgr32(Abgr32 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Byte4 FromRgb24(Rgb24 source) => FromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void ToRgba32(ref Rgba32 dest) => dest.FromScaledVector4(this.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Byte4 FromRgba32(Rgba32 source) => new() { PackedValue = source.PackedValue }; - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb48(Rgb48 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Byte4 FromRgb48(Rgb48 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Byte4 FromRgba64(Rgba64 source) => FromScaledVector4(source.ToScaledVector4()); /// public override readonly bool Equals(object? obj) => obj is Byte4 byte4 && this.Equals(byte4); /// - [MethodImpl(InliningOptions.ShortMethod)] public readonly bool Equals(Byte4 other) => this.PackedValue.Equals(other.PackedValue); /// - [MethodImpl(InliningOptions.ShortMethod)] public override readonly int GetHashCode() => this.PackedValue.GetHashCode(); /// public override readonly string ToString() { - var vector = this.ToVector4(); + Vector4 vector = this.ToVector4(); return FormattableString.Invariant($"Byte4({vector.X:#0.##}, {vector.Y:#0.##}, {vector.Z:#0.##}, {vector.W:#0.##})"); } @@ -162,13 +169,10 @@ public override readonly string ToString() /// /// The vector containing the values to pack. /// The containing the packed values. - [MethodImpl(InliningOptions.ShortMethod)] - private static uint Pack(ref Vector4 vector) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static uint Pack(Vector4 vector) { - const float Max = 255F; - - // Clamp the value between min and max values - vector = Numerics.Clamp(vector, Vector4.Zero, new Vector4(Max)); + vector = Numerics.Clamp(vector, Vector4.Zero, MaxBytes); uint byte4 = (uint)Math.Round(vector.X) & 0xFF; uint byte3 = ((uint)Math.Round(vector.Y) & 0xFF) << 0x8; diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/HalfSingle.cs b/src/ImageSharp/PixelFormats/PixelImplementations/HalfSingle.cs index db1e02adc2..888d992d8c 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/HalfSingle.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/HalfSingle.cs @@ -31,7 +31,7 @@ public partial struct HalfSingle : IPixel, IPackedVector /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(HalfSingle left, HalfSingle right) => left.Equals(right); /// @@ -42,24 +42,15 @@ public partial struct HalfSingle : IPixel, IPackedVector /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(HalfSingle left, HalfSingle right) => !left.Equals(right); /// - public PixelOperations CreatePixelOperations() => new PixelOperations(); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Rgba32 ToRgba32() => Rgba32.FromScaledVector4(this.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromScaledVector4(Vector4 vector) - { - float scaled = vector.X; - scaled *= 2F; - scaled--; - this.PackedValue = HalfTypeHelper.Pack(scaled); - } - - /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Vector4 ToScaledVector4() { float single = this.ToSingle() + 1F; @@ -68,87 +59,101 @@ public readonly Vector4 ToScaledVector4() } /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromVector4(Vector4 vector) => this.PackedValue = HalfTypeHelper.Pack(vector.X); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Vector4 ToVector4() => new(this.ToSingle(), 0, 0, 1F); /// - [MethodImpl(InliningOptions.ShortMethod)] - public readonly Vector4 ToVector4() => new(this.ToSingle(), 0, 0, 1F); + public static PixelTypeInfo GetPixelTypeInfo() + => PixelTypeInfo.Create( + PixelComponentInfo.Create(1, 16), + PixelColorType.Red, + PixelAlphaRepresentation.None); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromArgb32(Argb32 source) => this.FromScaledVector4(source.ToScaledVector4()); + public static PixelOperations CreatePixelOperations() => new PixelOperations(); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static HalfSingle FromScaledVector4(Vector4 source) + { + float scaled = source.X; + scaled *= 2F; + scaled--; + return new() { PackedValue = HalfTypeHelper.Pack(scaled) }; + } /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgr24(Bgr24 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static HalfSingle FromVector4(Vector4 source) => new() { PackedValue = HalfTypeHelper.Pack(source.X) }; /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static HalfSingle FromAbgr32(Abgr32 source) => FromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromAbgr32(Abgr32 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static HalfSingle FromArgb32(Argb32 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static HalfSingle FromBgra5551(Bgra5551 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL8(L8 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static HalfSingle FromBgr24(Bgr24 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL16(L16 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static HalfSingle FromBgra32(Bgra32 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa16(La16 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static HalfSingle FromL8(L8 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa32(La32 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static HalfSingle FromL16(L16 source) => FromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb24(Rgb24 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static HalfSingle FromLa16(La16 source) => FromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba32(Rgba32 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static HalfSingle FromLa32(La32 source) => FromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void ToRgba32(ref Rgba32 dest) => dest.FromScaledVector4(this.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static HalfSingle FromRgb24(Rgb24 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb48(Rgb48 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static HalfSingle FromRgba32(Rgba32 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static HalfSingle FromRgb48(Rgb48 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static HalfSingle FromRgba64(Rgba64 source) => FromScaledVector4(source.ToScaledVector4()); /// /// Expands the packed representation into a . /// /// The . - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly float ToSingle() => HalfTypeHelper.Unpack(this.PackedValue); /// public override readonly bool Equals(object? obj) => obj is HalfSingle other && this.Equals(other); /// - [MethodImpl(InliningOptions.ShortMethod)] public readonly bool Equals(HalfSingle other) => this.PackedValue.Equals(other.PackedValue); /// public override readonly string ToString() => FormattableString.Invariant($"HalfSingle({this.ToSingle():#0.##})"); /// - [MethodImpl(InliningOptions.ShortMethod)] public override readonly int GetHashCode() => this.PackedValue.GetHashCode(); } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector2.cs b/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector2.cs index 9caae58c95..861a8480aa 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector2.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector2.cs @@ -38,7 +38,7 @@ public partial struct HalfVector2 : IPixel, IPackedVector /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(HalfVector2 left, HalfVector2 right) => left.Equals(right); /// @@ -49,104 +49,111 @@ public partial struct HalfVector2 : IPixel, IPackedVector /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(HalfVector2 left, HalfVector2 right) => !left.Equals(right); /// - public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Rgba32 ToRgba32() => Rgba32.FromScaledVector4(this.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromScaledVector4(Vector4 vector) - { - Vector2 scaled = new Vector2(vector.X, vector.Y) * 2F; - scaled -= Vector2.One; - this.PackedValue = Pack(scaled.X, scaled.Y); - } - - /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Vector4 ToScaledVector4() { - var scaled = this.ToVector2(); + Vector2 scaled = this.ToVector2(); scaled += Vector2.One; scaled /= 2F; - return new Vector4(scaled, 0F, 1F); + return new(scaled, 0F, 1F); + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Vector4 ToVector4() + { + Vector2 vector = this.ToVector2(); + return new(vector.X, vector.Y, 0F, 1F); } /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromVector4(Vector4 vector) => this.PackedValue = Pack(vector.X, vector.Y); + public static PixelTypeInfo GetPixelTypeInfo() + => PixelTypeInfo.Create( + PixelComponentInfo.Create(2, 16, 16), + PixelColorType.Red | PixelColorType.Green, + PixelAlphaRepresentation.None); /// - [MethodImpl(InliningOptions.ShortMethod)] - public readonly Vector4 ToVector4() + public static PixelOperations CreatePixelOperations() => new PixelOperations(); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static HalfVector2 FromScaledVector4(Vector4 source) { - var vector = this.ToVector2(); - return new Vector4(vector.X, vector.Y, 0F, 1F); + Vector2 scaled = new Vector2(source.X, source.Y) * 2F; + scaled -= Vector2.One; + return new() { PackedValue = Pack(scaled.X, scaled.Y) }; } /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromArgb32(Argb32 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static HalfVector2 FromVector4(Vector4 source) => new() { PackedValue = Pack(source.X, source.Y) }; /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgr24(Bgr24 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static HalfVector2 FromAbgr32(Abgr32 source) => FromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static HalfVector2 FromArgb32(Argb32 source) => FromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromAbgr32(Abgr32 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static HalfVector2 FromBgra5551(Bgra5551 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static HalfVector2 FromBgr24(Bgr24 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL8(L8 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static HalfVector2 FromBgra32(Bgra32 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL16(L16 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static HalfVector2 FromL8(L8 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa16(La16 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static HalfVector2 FromL16(L16 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa32(La32 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static HalfVector2 FromLa16(La16 source) => FromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb24(Rgb24 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static HalfVector2 FromLa32(La32 source) => FromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba32(Rgba32 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static HalfVector2 FromRgb24(Rgb24 source) => FromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void ToRgba32(ref Rgba32 dest) => dest.FromScaledVector4(this.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static HalfVector2 FromRgba32(Rgba32 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb48(Rgb48 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static HalfVector2 FromRgb48(Rgb48 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static HalfVector2 FromRgba64(Rgba64 source) => FromScaledVector4(source.ToScaledVector4()); /// /// Expands the packed representation into a . /// /// The . - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Vector2 ToVector2() { Vector2 vector; @@ -159,21 +166,19 @@ public readonly Vector2 ToVector2() public override readonly bool Equals(object? obj) => obj is HalfVector2 other && this.Equals(other); /// - [MethodImpl(InliningOptions.ShortMethod)] public readonly bool Equals(HalfVector2 other) => this.PackedValue.Equals(other.PackedValue); /// public override readonly string ToString() { - var vector = this.ToVector2(); + Vector2 vector = this.ToVector2(); return FormattableString.Invariant($"HalfVector2({vector.X:#0.##}, {vector.Y:#0.##})"); } /// - [MethodImpl(InliningOptions.ShortMethod)] public override readonly int GetHashCode() => this.PackedValue.GetHashCode(); - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] private static uint Pack(float x, float y) { uint num2 = HalfTypeHelper.Pack(x); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector4.cs index 609fec3bd7..d0b57d788f 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector4.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector4.cs @@ -30,7 +30,7 @@ public HalfVector4(float x, float y, float z, float w) /// Initializes a new instance of the struct. /// /// A vector containing the initial values for the components - public HalfVector4(Vector4 vector) => this.PackedValue = Pack(ref vector); + public HalfVector4(Vector4 vector) => this.PackedValue = Pack(vector); /// public ulong PackedValue { get; set; } @@ -43,7 +43,7 @@ public HalfVector4(float x, float y, float z, float w) /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(HalfVector4 left, HalfVector4 right) => left.Equals(right); /// @@ -54,37 +54,25 @@ public HalfVector4(float x, float y, float z, float w) /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(HalfVector4 left, HalfVector4 right) => !left.Equals(right); /// - public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Rgba32 ToRgba32() => Rgba32.FromScaledVector4(this.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromScaledVector4(Vector4 vector) - { - vector *= 2F; - vector -= Vector4.One; - this.FromVector4(vector); - } - - /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Vector4 ToScaledVector4() { - var scaled = this.ToVector4(); + Vector4 scaled = this.ToVector4(); scaled += Vector4.One; - scaled /= 2F; + scaled /= 2f; return scaled; } /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector); - - /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Vector4 ToVector4() => new( HalfTypeHelper.Unpack((ushort)this.PackedValue), HalfTypeHelper.Unpack((ushort)(this.PackedValue >> 0x10)), @@ -92,77 +80,94 @@ public readonly Vector4 ToScaledVector4() HalfTypeHelper.Unpack((ushort)(this.PackedValue >> 0x30))); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromArgb32(Argb32 source) => this.FromScaledVector4(source.ToScaledVector4()); + public static PixelTypeInfo GetPixelTypeInfo() + => PixelTypeInfo.Create( + PixelComponentInfo.Create(4, 16, 16, 16, 16), + PixelColorType.RGB | PixelColorType.Alpha, + PixelAlphaRepresentation.Unassociated); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgr24(Bgr24 source) => this.FromScaledVector4(source.ToScaledVector4()); + public static PixelOperations CreatePixelOperations() => new PixelOperations(); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static HalfVector4 FromScaledVector4(Vector4 source) + { + source *= 2f; + source -= Vector4.One; + return FromVector4(source); + } /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static HalfVector4 FromVector4(Vector4 source) => new() { PackedValue = Pack(source) }; /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromAbgr32(Abgr32 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static HalfVector4 FromAbgr32(Abgr32 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static HalfVector4 FromArgb32(Argb32 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL8(L8 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static HalfVector4 FromBgra5551(Bgra5551 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL16(L16 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static HalfVector4 FromBgr24(Bgr24 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa16(La16 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static HalfVector4 FromBgra32(Bgra32 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa32(La32 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static HalfVector4 FromL8(L8 source) => FromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb24(Rgb24 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static HalfVector4 FromL16(L16 source) => FromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba32(Rgba32 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static HalfVector4 FromLa16(La16 source) => FromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void ToRgba32(ref Rgba32 dest) => dest.FromScaledVector4(this.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static HalfVector4 FromLa32(La32 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb48(Rgb48 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static HalfVector4 FromRgb24(Rgb24 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static HalfVector4 FromRgba32(Rgba32 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static HalfVector4 FromRgb48(Rgb48 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static HalfVector4 FromRgba64(Rgba64 source) => FromScaledVector4(source.ToScaledVector4()); /// public override readonly bool Equals(object? obj) => obj is HalfVector4 other && this.Equals(other); /// - [MethodImpl(InliningOptions.ShortMethod)] public readonly bool Equals(HalfVector4 other) => this.PackedValue.Equals(other.PackedValue); /// public override readonly string ToString() { - var vector = this.ToVector4(); + Vector4 vector = this.ToVector4(); return FormattableString.Invariant($"HalfVector4({vector.X:#0.##}, {vector.Y:#0.##}, {vector.Z:#0.##}, {vector.W:#0.##})"); } /// - [MethodImpl(InliningOptions.ShortMethod)] public override readonly int GetHashCode() => this.PackedValue.GetHashCode(); /// @@ -170,8 +175,8 @@ public override readonly string ToString() /// /// The vector containing the values to pack. /// The containing the packed values. - [MethodImpl(InliningOptions.ShortMethod)] - private static ulong Pack(ref Vector4 vector) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static ulong Pack(Vector4 vector) { ulong num4 = HalfTypeHelper.Pack(vector.X); ulong num3 = (ulong)HalfTypeHelper.Pack(vector.Y) << 0x10; diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/L16.cs b/src/ImageSharp/PixelFormats/PixelImplementations/L16.cs index c6ee8744d9..64a22060c0 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/L16.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/L16.cs @@ -33,7 +33,7 @@ public partial struct L16 : IPixel, IPackedVector /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(L16 left, L16 right) => left.Equals(right); /// @@ -44,134 +44,115 @@ public partial struct L16 : IPixel, IPackedVector /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(L16 left, L16 right) => !left.Equals(right); /// - public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromScaledVector4(Vector4 vector) => this.ConvertFromRgbaScaledVector4(vector); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Rgba32 ToRgba32() + { + byte rgb = ColorNumerics.From16BitTo8Bit(this.PackedValue); + return new(rgb, rgb, rgb); + } /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Vector4 ToScaledVector4() => this.ToVector4(); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromVector4(Vector4 vector) => this.ConvertFromRgbaScaledVector4(vector); - - /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Vector4 ToVector4() { float scaled = this.PackedValue / Max; - return new Vector4(scaled, scaled, scaled, 1F); + return new Vector4(scaled, scaled, scaled, 1f); } + /// + public static PixelTypeInfo GetPixelTypeInfo() + => PixelTypeInfo.Create( + PixelComponentInfo.Create(1, 16), + PixelColorType.Luminance, + PixelAlphaRepresentation.None); + + /// + public static PixelOperations CreatePixelOperations() => new PixelOperations(); + /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromArgb32(Argb32 source) => this.PackedValue = ColorNumerics.Get16BitBT709Luminance( - ColorNumerics.UpscaleFrom8BitTo16Bit(source.R), - ColorNumerics.UpscaleFrom8BitTo16Bit(source.G), - ColorNumerics.UpscaleFrom8BitTo16Bit(source.B)); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static L16 FromScaledVector4(Vector4 source) => FromVector4(source); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static L16 FromVector4(Vector4 source) => new() { PackedValue = Pack(source) }; /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgr24(Bgr24 source) => this.PackedValue = ColorNumerics.Get16BitBT709Luminance( - ColorNumerics.UpscaleFrom8BitTo16Bit(source.R), - ColorNumerics.UpscaleFrom8BitTo16Bit(source.G), - ColorNumerics.UpscaleFrom8BitTo16Bit(source.B)); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static L16 FromAbgr32(Abgr32 source) => new(ColorNumerics.Get16BitBT709Luminance(source.R, source.G, source.B)); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra32(Bgra32 source) => this.PackedValue = ColorNumerics.Get16BitBT709Luminance( - ColorNumerics.UpscaleFrom8BitTo16Bit(source.R), - ColorNumerics.UpscaleFrom8BitTo16Bit(source.G), - ColorNumerics.UpscaleFrom8BitTo16Bit(source.B)); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static L16 FromArgb32(Argb32 source) => new(ColorNumerics.Get16BitBT709Luminance(source.R, source.G, source.B)); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static L16 FromBgra5551(Bgra5551 source) => FromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromAbgr32(Abgr32 source) => this.PackedValue = ColorNumerics.Get16BitBT709Luminance( - ColorNumerics.UpscaleFrom8BitTo16Bit(source.R), - ColorNumerics.UpscaleFrom8BitTo16Bit(source.G), - ColorNumerics.UpscaleFrom8BitTo16Bit(source.B)); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static L16 FromBgr24(Bgr24 source) => new(ColorNumerics.Get16BitBT709Luminance(source.R, source.G, source.B)); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static L16 FromBgra32(Bgra32 source) => new(ColorNumerics.Get16BitBT709Luminance(source.R, source.G, source.B)); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL8(L8 source) => this.PackedValue = ColorNumerics.UpscaleFrom8BitTo16Bit(source.PackedValue); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static L16 FromL8(L8 source) => new(ColorNumerics.From8BitTo16Bit(source.PackedValue)); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL16(L16 source) => this = source; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static L16 FromL16(L16 source) => new(source.PackedValue); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa16(La16 source) => this.PackedValue = ColorNumerics.UpscaleFrom8BitTo16Bit(source.L); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static L16 FromLa16(La16 source) => new(ColorNumerics.From8BitTo16Bit(source.L)); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa32(La32 source) => this.PackedValue = source.L; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static L16 FromLa32(La32 source) => new(source.L); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb24(Rgb24 source) => this.PackedValue = ColorNumerics.Get16BitBT709Luminance( - ColorNumerics.UpscaleFrom8BitTo16Bit(source.R), - ColorNumerics.UpscaleFrom8BitTo16Bit(source.G), - ColorNumerics.UpscaleFrom8BitTo16Bit(source.B)); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static L16 FromRgb24(Rgb24 source) => new(ColorNumerics.Get16BitBT709Luminance(source.R, source.G, source.B)); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba32(Rgba32 source) => this.PackedValue = ColorNumerics.Get16BitBT709Luminance( - ColorNumerics.UpscaleFrom8BitTo16Bit(source.R), - ColorNumerics.UpscaleFrom8BitTo16Bit(source.G), - ColorNumerics.UpscaleFrom8BitTo16Bit(source.B)); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void ToRgba32(ref Rgba32 dest) - { - byte rgb = ColorNumerics.DownScaleFrom16BitTo8Bit(this.PackedValue); - dest.R = rgb; - dest.G = rgb; - dest.B = rgb; - dest.A = byte.MaxValue; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static L16 FromRgba32(Rgba32 source) => new(ColorNumerics.Get16BitBT709Luminance(source.R, source.G, source.B)); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb48(Rgb48 source) => this.PackedValue = ColorNumerics.Get16BitBT709Luminance(source.R, source.G, source.B); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static L16 FromRgb48(Rgb48 source) => new(ColorNumerics.Get16BitBT709Luminance(source.R, source.G, source.B)); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba64(Rgba64 source) => this.PackedValue = ColorNumerics.Get16BitBT709Luminance(source.R, source.G, source.B); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static L16 FromRgba64(Rgba64 source) => new(ColorNumerics.Get16BitBT709Luminance(source.R, source.G, source.B)); /// public override readonly bool Equals(object? obj) => obj is L16 other && this.Equals(other); /// - [MethodImpl(InliningOptions.ShortMethod)] public readonly bool Equals(L16 other) => this.PackedValue.Equals(other.PackedValue); /// public override readonly string ToString() => $"L16({this.PackedValue})"; /// - [MethodImpl(InliningOptions.ShortMethod)] public override readonly int GetHashCode() => this.PackedValue.GetHashCode(); - [MethodImpl(InliningOptions.ShortMethod)] - internal void ConvertFromRgbaScaledVector4(Vector4 vector) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static ushort Pack(Vector4 vector) { vector = Numerics.Clamp(vector, Vector4.Zero, Vector4.One) * Max; - this.PackedValue = ColorNumerics.Get16BitBT709Luminance( - vector.X, - vector.Y, - vector.Z); + return ColorNumerics.Get16BitBT709Luminance(vector.X, vector.Y, vector.Z); } } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/L8.cs b/src/ImageSharp/PixelFormats/PixelImplementations/L8.cs index 383e09b270..cf8646cfa0 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/L8.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/L8.cs @@ -3,6 +3,7 @@ using System.Numerics; using System.Runtime.CompilerServices; +using System.Runtime.Intrinsics; namespace SixLabors.ImageSharp.PixelFormats; @@ -14,8 +15,8 @@ namespace SixLabors.ImageSharp.PixelFormats; /// public partial struct L8 : IPixel, IPackedVector { - private static readonly Vector4 MaxBytes = new(255F); - private static readonly Vector4 Half = new(0.5F); + private static readonly Vector4 MaxBytes = Vector128.Create(255f).AsVector4(); + private static readonly Vector4 Half = Vector128.Create(.5f).AsVector4(); /// /// Initializes a new instance of the struct. @@ -34,7 +35,7 @@ public partial struct L8 : IPixel, IPackedVector /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(L8 left, L8 right) => left.Equals(right); /// @@ -45,122 +46,119 @@ public partial struct L8 : IPixel, IPackedVector /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(L8 left, L8 right) => !left.Equals(right); /// - public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromScaledVector4(Vector4 vector) => this.ConvertFromRgbaScaledVector4(vector); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Rgba32 ToRgba32() + { + byte rgb = this.PackedValue; + return new(rgb, rgb, rgb); + } /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Vector4 ToScaledVector4() => this.ToVector4(); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromVector4(Vector4 vector) => this.ConvertFromRgbaScaledVector4(vector); - - /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Vector4 ToVector4() { - float rgb = this.PackedValue / 255F; - return new Vector4(rgb, rgb, rgb, 1F); + float rgb = this.PackedValue / 255f; + return new Vector4(rgb, rgb, rgb, 1f); } - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromArgb32(Argb32 source) => this.PackedValue = ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B); + /// + public static PixelTypeInfo GetPixelTypeInfo() + => PixelTypeInfo.Create( + PixelComponentInfo.Create(1, 8), + PixelColorType.Luminance, + PixelAlphaRepresentation.None); + + /// + public static PixelOperations CreatePixelOperations() => new PixelOperations(); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgr24(Bgr24 source) => this.PackedValue = ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static L8 FromScaledVector4(Vector4 source) => FromVector4(source); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static L8 FromVector4(Vector4 source) => new() { PackedValue = Pack(source) }; /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra32(Bgra32 source) => this.PackedValue = ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static L8 FromAbgr32(Abgr32 source) => new(ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B)); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromAbgr32(Abgr32 source) => this.PackedValue = ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static L8 FromArgb32(Argb32 source) => new(ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B)); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static L8 FromBgra5551(Bgra5551 source) => FromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static L8 FromBgr24(Bgr24 source) => new(ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B)); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL8(L8 source) => this = source; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static L8 FromBgra32(Bgra32 source) => new(ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B)); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL16(L16 source) => this.PackedValue = ColorNumerics.DownScaleFrom16BitTo8Bit(source.PackedValue); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static L8 FromL8(L8 source) => new(source.PackedValue); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa16(La16 source) => this.PackedValue = source.L; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static L8 FromL16(L16 source) => new(ColorNumerics.From16BitTo8Bit(source.PackedValue)); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa32(La32 source) => this.PackedValue = ColorNumerics.DownScaleFrom16BitTo8Bit(source.L); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static L8 FromLa16(La16 source) => new(source.L); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb24(Rgb24 source) => this.PackedValue = ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static L8 FromLa32(La32 source) => new(ColorNumerics.From16BitTo8Bit(source.L)); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba32(Rgba32 source) => this.PackedValue = ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static L8 FromRgb24(Rgb24 source) => new(ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B)); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void ToRgba32(ref Rgba32 dest) - { - dest.R = this.PackedValue; - dest.G = this.PackedValue; - dest.B = this.PackedValue; - dest.A = byte.MaxValue; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static L8 FromRgba32(Rgba32 source) => new(ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B)); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb48(Rgb48 source) - => this.PackedValue = ColorNumerics.Get8BitBT709Luminance( - ColorNumerics.DownScaleFrom16BitTo8Bit(source.R), - ColorNumerics.DownScaleFrom16BitTo8Bit(source.G), - ColorNumerics.DownScaleFrom16BitTo8Bit(source.B)); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static L8 FromRgb48(Rgb48 source) => new(ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B)); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba64(Rgba64 source) - => this.PackedValue = ColorNumerics.Get8BitBT709Luminance( - ColorNumerics.DownScaleFrom16BitTo8Bit(source.R), - ColorNumerics.DownScaleFrom16BitTo8Bit(source.G), - ColorNumerics.DownScaleFrom16BitTo8Bit(source.B)); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static L8 FromRgba64(Rgba64 source) => new(ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B)); /// public override readonly bool Equals(object? obj) => obj is L8 other && this.Equals(other); /// - [MethodImpl(InliningOptions.ShortMethod)] public readonly bool Equals(L8 other) => this.PackedValue.Equals(other.PackedValue); /// public override readonly string ToString() => $"L8({this.PackedValue})"; /// - [MethodImpl(InliningOptions.ShortMethod)] public override readonly int GetHashCode() => this.PackedValue.GetHashCode(); - [MethodImpl(InliningOptions.ShortMethod)] - internal void ConvertFromRgbaScaledVector4(Vector4 vector) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static byte Pack(Vector4 vector) { vector *= MaxBytes; vector += Half; vector = Numerics.Clamp(vector, Vector4.Zero, MaxBytes); - this.PackedValue = ColorNumerics.Get8BitBT709Luminance((byte)vector.X, (byte)vector.Y, (byte)vector.Z); + + Vector128 result = Vector128.ConvertToInt32(vector.AsVector128()).AsByte(); + return ColorNumerics.Get8BitBT709Luminance(result.GetElement(0), result.GetElement(4), result.GetElement(8)); } } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/La16.cs b/src/ImageSharp/PixelFormats/PixelImplementations/La16.cs index 7597677a26..026d0c299d 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/La16.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/La16.cs @@ -4,6 +4,7 @@ using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; namespace SixLabors.ImageSharp.PixelFormats; @@ -16,8 +17,15 @@ namespace SixLabors.ImageSharp.PixelFormats; [StructLayout(LayoutKind.Explicit)] public partial struct La16 : IPixel, IPackedVector { - private static readonly Vector4 MaxBytes = new(255F); - private static readonly Vector4 Half = new(0.5F); + /// + /// The maximum byte value. + /// + private static readonly Vector4 MaxBytes = Vector128.Create(255f).AsVector4(); + + /// + /// The half vector value. + /// + private static readonly Vector4 Half = Vector128.Create(.5f).AsVector4(); /// /// Gets or sets the luminance component. @@ -45,7 +53,7 @@ public La16(byte l, byte a) /// public ushort PackedValue { - readonly get => Unsafe.As(ref Unsafe.AsRef(this)); + readonly get => Unsafe.As(ref Unsafe.AsRef(in this)); set => Unsafe.As(ref this) = value; } @@ -57,7 +65,7 @@ public ushort PackedValue /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(La16 left, La16 right) => left.Equals(right); /// @@ -68,167 +76,118 @@ public ushort PackedValue /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(La16 left, La16 right) => !left.Equals(right); - /// - public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public readonly bool Equals(La16 other) => this.PackedValue.Equals(other.PackedValue); - - /// - public override readonly bool Equals(object? obj) => obj is La16 other && this.Equals(other); - /// - public override readonly string ToString() => $"La16({this.L}, {this.A})"; - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public override readonly int GetHashCode() => this.PackedValue.GetHashCode(); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Rgba32 ToRgba32() => new(this.L, this.L, this.L, this.A); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromArgb32(Argb32 source) - { - this.L = ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B); - this.A = source.A; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Vector4 ToScaledVector4() => this.ToVector4(); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgr24(Bgr24 source) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Vector4 ToVector4() { - this.L = ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B); - this.A = byte.MaxValue; + const float max = 255f; + float rgb = this.L / max; + return new Vector4(rgb, rgb, rgb, this.A / max); } + /// + public static PixelTypeInfo GetPixelTypeInfo() + => PixelTypeInfo.Create( + PixelComponentInfo.Create(2, 8, 8), + PixelColorType.Luminance | PixelColorType.Alpha, + PixelAlphaRepresentation.Unassociated); + /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra32(Bgra32 source) - { - this.L = ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B); - this.A = source.A; - } + public static PixelOperations CreatePixelOperations() => new PixelOperations(); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromAbgr32(Abgr32 source) - { - this.L = ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B); - this.A = source.A; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static La16 FromScaledVector4(Vector4 source) => Pack(source); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static La16 FromVector4(Vector4 source) => Pack(source); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL16(L16 source) - { - this.L = ColorNumerics.DownScaleFrom16BitTo8Bit(source.PackedValue); - this.A = byte.MaxValue; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static La16 FromAbgr32(Abgr32 source) => new(ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B), source.A); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL8(L8 source) - { - this.L = source.PackedValue; - this.A = byte.MaxValue; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static La16 FromArgb32(Argb32 source) => new(ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B), source.A); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static La16 FromBgra5551(Bgra5551 source) => FromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa16(La16 source) => this = source; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static La16 FromBgr24(Bgr24 source) => new(ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B), byte.MaxValue); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa32(La32 source) - { - this.L = ColorNumerics.DownScaleFrom16BitTo8Bit(source.L); - this.A = ColorNumerics.DownScaleFrom16BitTo8Bit(source.A); - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static La16 FromBgra32(Bgra32 source) => new(ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B), source.A); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb24(Rgb24 source) - { - this.L = ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B); - this.A = byte.MaxValue; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static La16 FromL16(L16 source) => new(ColorNumerics.From16BitTo8Bit(source.PackedValue), byte.MaxValue); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb48(Rgb48 source) - { - this.L = ColorNumerics.Get8BitBT709Luminance( - ColorNumerics.DownScaleFrom16BitTo8Bit(source.R), - ColorNumerics.DownScaleFrom16BitTo8Bit(source.G), - ColorNumerics.DownScaleFrom16BitTo8Bit(source.B)); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static La16 FromL8(L8 source) => new(source.PackedValue, byte.MaxValue); - this.A = byte.MaxValue; - } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static La16 FromLa16(La16 source) => new(source.L, source.A); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba32(Rgba32 source) - { - this.L = ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B); - this.A = source.A; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static La16 FromLa32(La32 source) => new(ColorNumerics.From16BitTo8Bit(source.L), ColorNumerics.From16BitTo8Bit(source.A)); /// - public void FromRgba64(Rgba64 source) - { - this.L = ColorNumerics.Get8BitBT709Luminance( - ColorNumerics.DownScaleFrom16BitTo8Bit(source.R), - ColorNumerics.DownScaleFrom16BitTo8Bit(source.G), - ColorNumerics.DownScaleFrom16BitTo8Bit(source.B)); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static La16 FromRgb24(Rgb24 source) => new(ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B), byte.MaxValue); - this.A = ColorNumerics.DownScaleFrom16BitTo8Bit(source.A); - } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static La16 FromRgba32(Rgba32 source) => new(ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B), source.A); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromScaledVector4(Vector4 vector) => this.ConvertFromRgbaScaledVector4(vector); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static La16 FromRgb48(Rgb48 source) => new(ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B), byte.MaxValue); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromVector4(Vector4 vector) => this.ConvertFromRgbaScaledVector4(vector); + public static La16 FromRgba64(Rgba64 source) => new(ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B), ColorNumerics.From16BitTo8Bit(source.A)); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void ToRgba32(ref Rgba32 dest) - { - dest.R = this.L; - dest.G = this.L; - dest.B = this.L; - dest.A = this.A; - } + public override readonly bool Equals(object? obj) => obj is La16 other && this.Equals(other); /// - [MethodImpl(InliningOptions.ShortMethod)] - public readonly Vector4 ToScaledVector4() => this.ToVector4(); + public readonly bool Equals(La16 other) => this.PackedValue.Equals(other.PackedValue); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public readonly Vector4 ToVector4() - { - const float Max = 255F; - float rgb = this.L / Max; - return new Vector4(rgb, rgb, rgb, this.A / Max); - } + /// + public override readonly string ToString() => $"La16({this.L}, {this.A})"; - [MethodImpl(InliningOptions.ShortMethod)] - internal void ConvertFromRgbaScaledVector4(Vector4 vector) + /// + public override readonly int GetHashCode() => this.PackedValue.GetHashCode(); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static La16 Pack(Vector4 vector) { vector *= MaxBytes; vector += Half; vector = Numerics.Clamp(vector, Vector4.Zero, MaxBytes); - this.L = ColorNumerics.Get8BitBT709Luminance((byte)vector.X, (byte)vector.Y, (byte)vector.Z); - this.A = (byte)vector.W; + + Vector128 result = Vector128.ConvertToInt32(vector.AsVector128()).AsByte(); + byte l = ColorNumerics.Get8BitBT709Luminance(result.GetElement(0), result.GetElement(4), result.GetElement(8)); + byte a = result.GetElement(12); + + return new(l, a); } } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/La32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/La32.cs index cb8fad228d..0ddcf16a1f 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/La32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/La32.cs @@ -44,10 +44,10 @@ public La32(ushort l, ushort a) /// public uint PackedValue { - [MethodImpl(InliningOptions.ShortMethod)] - readonly get => Unsafe.As(ref Unsafe.AsRef(this)); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + readonly get => Unsafe.As(ref Unsafe.AsRef(in this)); - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] set => Unsafe.As(ref this) = value; } @@ -59,7 +59,7 @@ public uint PackedValue /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(La32 left, La32 right) => left.Equals(right); /// @@ -70,186 +70,146 @@ public uint PackedValue /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(La32 left, La32 right) => !left.Equals(right); /// - public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Rgba32 ToRgba32() + { + byte rgb = ColorNumerics.From16BitTo8Bit(this.L); + return new(rgb, rgb, rgb, ColorNumerics.From16BitTo8Bit(this.A)); + } /// - [MethodImpl(InliningOptions.ShortMethod)] - public readonly bool Equals(La32 other) => this.PackedValue.Equals(other.PackedValue); - - /// - public override readonly bool Equals(object? obj) => obj is La32 other && this.Equals(other); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Vector4 ToScaledVector4() => this.ToVector4(); - /// - public override readonly string ToString() => $"La32({this.L}, {this.A})"; + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Vector4 ToVector4() + { + float rgb = this.L / Max; + return new Vector4(rgb, rgb, rgb, this.A / Max); + } /// - [MethodImpl(InliningOptions.ShortMethod)] - public override readonly int GetHashCode() => this.PackedValue.GetHashCode(); + public static PixelTypeInfo GetPixelTypeInfo() + => PixelTypeInfo.Create( + PixelComponentInfo.Create(2, 16, 16), + PixelColorType.Luminance | PixelColorType.Alpha, + PixelAlphaRepresentation.Unassociated); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromArgb32(Argb32 source) - { - this.L = ColorNumerics.Get16BitBT709Luminance( - ColorNumerics.UpscaleFrom8BitTo16Bit(source.R), - ColorNumerics.UpscaleFrom8BitTo16Bit(source.G), - ColorNumerics.UpscaleFrom8BitTo16Bit(source.B)); - - this.A = ColorNumerics.UpscaleFrom8BitTo16Bit(source.A); - } + public static PixelOperations CreatePixelOperations() => new PixelOperations(); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgr24(Bgr24 source) - { - this.L = ColorNumerics.Get16BitBT709Luminance( - ColorNumerics.UpscaleFrom8BitTo16Bit(source.R), - ColorNumerics.UpscaleFrom8BitTo16Bit(source.G), - ColorNumerics.UpscaleFrom8BitTo16Bit(source.B)); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static La32 FromScaledVector4(Vector4 source) => Pack(source); - this.A = ushort.MaxValue; - } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static La32 FromVector4(Vector4 source) => Pack(source); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra32(Bgra32 source) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static La32 FromAbgr32(Abgr32 source) { - this.L = ColorNumerics.Get16BitBT709Luminance( - ColorNumerics.UpscaleFrom8BitTo16Bit(source.R), - ColorNumerics.UpscaleFrom8BitTo16Bit(source.G), - ColorNumerics.UpscaleFrom8BitTo16Bit(source.B)); - - this.A = ColorNumerics.UpscaleFrom8BitTo16Bit(source.A); + ushort l = ColorNumerics.Get16BitBT709Luminance(source.R, source.G, source.B); + ushort a = ColorNumerics.From8BitTo16Bit(source.A); + return new(l, a); } /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromAbgr32(Abgr32 source) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static La32 FromArgb32(Argb32 source) { - this.L = ColorNumerics.Get16BitBT709Luminance( - ColorNumerics.UpscaleFrom8BitTo16Bit(source.R), - ColorNumerics.UpscaleFrom8BitTo16Bit(source.G), - ColorNumerics.UpscaleFrom8BitTo16Bit(source.B)); - - this.A = ColorNumerics.UpscaleFrom8BitTo16Bit(source.A); + ushort l = ColorNumerics.Get16BitBT709Luminance(source.R, source.G, source.B); + ushort a = ColorNumerics.From8BitTo16Bit(source.A); + return new(l, a); } - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static La32 FromBgra5551(Bgra5551 source) => FromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL16(L16 source) - { - this.L = source.PackedValue; - this.A = ushort.MaxValue; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static La32 FromBgr24(Bgr24 source) => new(ColorNumerics.Get16BitBT709Luminance(source.R, source.G, source.B), ushort.MaxValue); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL8(L8 source) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static La32 FromBgra32(Bgra32 source) { - this.L = ColorNumerics.UpscaleFrom8BitTo16Bit(source.PackedValue); - this.A = ushort.MaxValue; + ushort l = ColorNumerics.Get16BitBT709Luminance(source.R, source.G, source.B); + ushort a = ColorNumerics.From8BitTo16Bit(source.A); + return new(l, a); } /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa16(La16 source) - { - this.L = ColorNumerics.UpscaleFrom8BitTo16Bit(source.L); - this.A = ColorNumerics.UpscaleFrom8BitTo16Bit(source.A); - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static La32 FromL16(L16 source) => new(source.PackedValue, ushort.MaxValue); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa32(La32 source) => this = source; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static La32 FromL8(L8 source) => new(ColorNumerics.From8BitTo16Bit(source.PackedValue), ushort.MaxValue); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb24(Rgb24 source) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static La32 FromLa16(La16 source) { - this.L = ColorNumerics.Get16BitBT709Luminance( - ColorNumerics.UpscaleFrom8BitTo16Bit(source.R), - ColorNumerics.UpscaleFrom8BitTo16Bit(source.G), - ColorNumerics.UpscaleFrom8BitTo16Bit(source.B)); - - this.A = ushort.MaxValue; + ushort l = ColorNumerics.From8BitTo16Bit(source.L); + ushort a = ColorNumerics.From8BitTo16Bit(source.A); + return new(l, a); } /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb48(Rgb48 source) - { - this.L = ColorNumerics.Get16BitBT709Luminance(source.R, source.G, source.B); - this.A = ushort.MaxValue; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static La32 FromLa32(La32 source) => new(source.L, source.A); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba32(Rgba32 source) - { - this.L = ColorNumerics.Get16BitBT709Luminance( - ColorNumerics.UpscaleFrom8BitTo16Bit(source.R), - ColorNumerics.UpscaleFrom8BitTo16Bit(source.G), - ColorNumerics.UpscaleFrom8BitTo16Bit(source.B)); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static La32 FromRgb24(Rgb24 source) => new(ColorNumerics.Get16BitBT709Luminance(source.R, source.G, source.B), ushort.MaxValue); - this.A = ColorNumerics.UpscaleFrom8BitTo16Bit(source.A); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static La32 FromRgb48(Rgb48 source) + { + ushort l = ColorNumerics.Get16BitBT709Luminance(source.R, source.G, source.B); + return new(l, ushort.MaxValue); } /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba64(Rgba64 source) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static La32 FromRgba32(Rgba32 source) { - this.L = ColorNumerics.Get16BitBT709Luminance(source.R, source.G, source.B); - this.A = source.A; + ushort l = ColorNumerics.Get16BitBT709Luminance(source.R, source.G, source.B); + ushort a = ColorNumerics.From8BitTo16Bit(source.A); + return new(l, a); } /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromScaledVector4(Vector4 vector) => this.ConvertFromRgbaScaledVector4(vector); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static La32 FromRgba64(Rgba64 source) => new(ColorNumerics.Get16BitBT709Luminance(source.R, source.G, source.B), source.A); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromVector4(Vector4 vector) => this.ConvertFromRgbaScaledVector4(vector); + /// + public override readonly bool Equals(object? obj) => obj is La32 other && this.Equals(other); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void ToRgba32(ref Rgba32 dest) - { - byte rgb = ColorNumerics.DownScaleFrom16BitTo8Bit(this.L); - dest.R = rgb; - dest.G = rgb; - dest.B = rgb; - dest.A = ColorNumerics.DownScaleFrom16BitTo8Bit(this.A); - } + public readonly bool Equals(La32 other) => this.PackedValue.Equals(other.PackedValue); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public readonly Vector4 ToScaledVector4() => this.ToVector4(); + /// + public override readonly string ToString() => $"La32({this.L}, {this.A})"; - /// - [MethodImpl(InliningOptions.ShortMethod)] - public readonly Vector4 ToVector4() - { - float scaled = this.L / Max; - return new Vector4(scaled, scaled, scaled, this.A / Max); - } + /// + public override readonly int GetHashCode() => this.PackedValue.GetHashCode(); - [MethodImpl(InliningOptions.ShortMethod)] - internal void ConvertFromRgbaScaledVector4(Vector4 vector) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static La32 Pack(Vector4 vector) { vector = Numerics.Clamp(vector, Vector4.Zero, Vector4.One) * Max; - this.L = ColorNumerics.Get16BitBT709Luminance( - vector.X, - vector.Y, - vector.Z); - - this.A = (ushort)MathF.Round(vector.W); + ushort l = ColorNumerics.Get16BitBT709Luminance(vector.X, vector.Y, vector.Z); + ushort a = (ushort)MathF.Round(vector.W); + return new(l, a); } } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte2.cs b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte2.cs index 92b9e6148a..9551d7242f 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte2.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte2.cs @@ -14,10 +14,9 @@ namespace SixLabors.ImageSharp.PixelFormats; /// public partial struct NormalizedByte2 : IPixel, IPackedVector { - private const float MaxPos = 127F; - + private const float MaxPos = 127f; private static readonly Vector2 Half = new(MaxPos); - private static readonly Vector2 MinusOne = new(-1F); + private static readonly Vector2 MinusOne = new(-1f); /// /// Initializes a new instance of the struct. @@ -46,7 +45,7 @@ public NormalizedByte2(float x, float y) /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(NormalizedByte2 left, NormalizedByte2 right) => left.Equals(right); /// @@ -57,105 +56,108 @@ public NormalizedByte2(float x, float y) /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(NormalizedByte2 left, NormalizedByte2 right) => !left.Equals(right); /// - public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Rgba32 ToRgba32() => Rgba32.FromScaledVector4(this.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromScaledVector4(Vector4 vector) - { - Vector2 scaled = new Vector2(vector.X, vector.Y) * 2F; - scaled -= Vector2.One; - this.PackedValue = Pack(scaled); - } - - /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Vector4 ToScaledVector4() { - var scaled = this.ToVector2(); + Vector2 scaled = this.ToVector2(); scaled += Vector2.One; - scaled /= 2F; - return new Vector4(scaled, 0F, 1F); + scaled /= 2f; + return new Vector4(scaled, 0f, 1f); } /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromVector4(Vector4 vector) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Vector4 ToVector4() => new(this.ToVector2(), 0f, 1f); + + /// + public static PixelTypeInfo GetPixelTypeInfo() + => PixelTypeInfo.Create( + PixelComponentInfo.Create(2, 8, 8), + PixelColorType.Red | PixelColorType.Green, + PixelAlphaRepresentation.None); + + /// + public static PixelOperations CreatePixelOperations() => new PixelOperations(); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedByte2 FromScaledVector4(Vector4 source) { - var vector2 = new Vector2(vector.X, vector.Y); - this.PackedValue = Pack(vector2); + Vector2 scaled = new Vector2(source.X, source.Y) * 2f; + scaled -= Vector2.One; + return new() { PackedValue = Pack(scaled) }; } /// - [MethodImpl(InliningOptions.ShortMethod)] - public readonly Vector4 ToVector4() => new(this.ToVector2(), 0F, 1F); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedByte2 FromVector4(Vector4 source) => new() { PackedValue = Pack(new Vector2(source.X, source.Y)) }; /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromArgb32(Argb32 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedByte2 FromAbgr32(Abgr32 source) => FromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgr24(Bgr24 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedByte2 FromArgb32(Argb32 source) => FromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedByte2 FromBgra5551(Bgra5551 source) => FromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromAbgr32(Abgr32 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedByte2 FromBgr24(Bgr24 source) => FromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedByte2 FromBgra32(Bgra32 source) => FromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void ToRgba32(ref Rgba32 dest) => dest.FromScaledVector4(this.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedByte2 FromL8(L8 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL8(L8 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL16(L16 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedByte2 FromL16(L16 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa16(La16 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedByte2 FromLa16(La16 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa32(La32 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedByte2 FromLa32(La32 source) => FromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb24(Rgb24 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedByte2 FromRgb24(Rgb24 source) => FromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba32(Rgba32 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedByte2 FromRgba32(Rgba32 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb48(Rgb48 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedByte2 FromRgb48(Rgb48 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedByte2 FromRgba64(Rgba64 source) => FromScaledVector4(source.ToScaledVector4()); /// /// Expands the packed representation into a . /// The vector components are typically expanded in least to greatest significance order. /// /// The . - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Vector2 ToVector2() => new( (sbyte)((this.PackedValue >> 0) & 0xFF) / MaxPos, (sbyte)((this.PackedValue >> 8) & 0xFF) / MaxPos); @@ -164,21 +166,19 @@ public void FromVector4(Vector4 vector) public override readonly bool Equals(object? obj) => obj is NormalizedByte2 other && this.Equals(other); /// - [MethodImpl(InliningOptions.ShortMethod)] public readonly bool Equals(NormalizedByte2 other) => this.PackedValue.Equals(other.PackedValue); /// - [MethodImpl(InliningOptions.ShortMethod)] public override readonly int GetHashCode() => this.PackedValue.GetHashCode(); /// public override readonly string ToString() { - var vector = this.ToVector2(); + Vector2 vector = this.ToVector2(); return FormattableString.Invariant($"NormalizedByte2({vector.X:#0.##}, {vector.Y:#0.##})"); } - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] private static ushort Pack(Vector2 vector) { vector = Vector2.Clamp(vector, MinusOne, Vector2.One) * Half; diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte4.cs index f87bb5a602..1fb386725a 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte4.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte4.cs @@ -3,6 +3,7 @@ using System.Numerics; using System.Runtime.CompilerServices; +using System.Runtime.Intrinsics; namespace SixLabors.ImageSharp.PixelFormats; @@ -14,10 +15,9 @@ namespace SixLabors.ImageSharp.PixelFormats; /// public partial struct NormalizedByte4 : IPixel, IPackedVector { - private const float MaxPos = 127F; - - private static readonly Vector4 Half = new(MaxPos); - private static readonly Vector4 MinusOne = new(-1F); + private const float MaxPos = 127f; + private static readonly Vector4 Half = Vector128.Create(MaxPos).AsVector4(); + private static readonly Vector4 MinusOne = Vector128.Create(-1f).AsVector4(); /// /// Initializes a new instance of the struct. @@ -35,7 +35,7 @@ public NormalizedByte4(float x, float y, float z, float w) /// Initializes a new instance of the struct. /// /// The vector containing the component values. - public NormalizedByte4(Vector4 vector) => this.PackedValue = Pack(ref vector); + public NormalizedByte4(Vector4 vector) => this.PackedValue = Pack(vector); /// public uint PackedValue { get; set; } @@ -48,7 +48,7 @@ public NormalizedByte4(float x, float y, float z, float w) /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(NormalizedByte4 left, NormalizedByte4 right) => left.Equals(right); /// @@ -59,37 +59,25 @@ public NormalizedByte4(float x, float y, float z, float w) /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(NormalizedByte4 left, NormalizedByte4 right) => !left.Equals(right); /// - public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromScaledVector4(Vector4 vector) - { - vector *= 2F; - vector -= Vector4.One; - this.FromVector4(vector); - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Rgba32 ToRgba32() => Rgba32.FromScaledVector4(this.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Vector4 ToScaledVector4() { - var scaled = this.ToVector4(); + Vector4 scaled = this.ToVector4(); scaled += Vector4.One; - scaled /= 2F; + scaled /= 2f; return scaled; } /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector); - - /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Vector4 ToVector4() => new( (sbyte)((this.PackedValue >> 0) & 0xFF) / MaxPos, (sbyte)((this.PackedValue >> 8) & 0xFF) / MaxPos, @@ -97,81 +85,98 @@ public readonly Vector4 ToScaledVector4() (sbyte)((this.PackedValue >> 24) & 0xFF) / MaxPos); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromArgb32(Argb32 source) => this.FromScaledVector4(source.ToScaledVector4()); + public static PixelTypeInfo GetPixelTypeInfo() + => PixelTypeInfo.Create( + PixelComponentInfo.Create(4, 8, 8, 8, 8), + PixelColorType.RGB | PixelColorType.Alpha, + PixelAlphaRepresentation.Unassociated); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgr24(Bgr24 source) => this.FromScaledVector4(source.ToScaledVector4()); + public static PixelOperations CreatePixelOperations() => new PixelOperations(); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedByte4 FromScaledVector4(Vector4 source) + { + source *= 2f; + source -= Vector4.One; + return FromVector4(source); + } /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedByte4 FromAbgr32(Abgr32 source) => FromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromAbgr32(Abgr32 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedByte4 FromArgb32(Argb32 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedByte4 FromBgra5551(Bgra5551 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL8(L8 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedByte4 FromBgr24(Bgr24 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL16(L16 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedByte4 FromBgra32(Bgra32 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa16(La16 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedByte4 FromL8(L8 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa32(La32 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedByte4 FromL16(L16 source) => FromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb24(Rgb24 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedByte4 FromLa16(La16 source) => FromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba32(Rgba32 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedByte4 FromLa32(La32 source) => FromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void ToRgba32(ref Rgba32 dest) => dest.FromScaledVector4(this.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedByte4 FromRgb24(Rgb24 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb48(Rgb48 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedByte4 FromRgba32(Rgba32 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedByte4 FromRgb48(Rgb48 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedByte4 FromRgba64(Rgba64 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedByte4 FromVector4(Vector4 source) => new() { PackedValue = Pack(source) }; /// public override readonly bool Equals(object? obj) => obj is NormalizedByte4 other && this.Equals(other); /// - [MethodImpl(InliningOptions.ShortMethod)] public readonly bool Equals(NormalizedByte4 other) => this.PackedValue.Equals(other.PackedValue); /// - [MethodImpl(InliningOptions.ShortMethod)] public override readonly int GetHashCode() => this.PackedValue.GetHashCode(); /// public override readonly string ToString() { - var vector = this.ToVector4(); + Vector4 vector = this.ToVector4(); return FormattableString.Invariant($"NormalizedByte4({vector.X:#0.##}, {vector.Y:#0.##}, {vector.Z:#0.##}, {vector.W:#0.##})"); } - [MethodImpl(InliningOptions.ShortMethod)] - private static uint Pack(ref Vector4 vector) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static uint Pack(Vector4 vector) { vector = Numerics.Clamp(vector, MinusOne, Vector4.One) * Half; diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort2.cs b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort2.cs index f77dd69b71..a17868f6df 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort2.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort2.cs @@ -47,7 +47,7 @@ public NormalizedShort2(float x, float y) /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(NormalizedShort2 left, NormalizedShort2 right) => left.Equals(right); /// @@ -58,105 +58,108 @@ public NormalizedShort2(float x, float y) /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(NormalizedShort2 left, NormalizedShort2 right) => !left.Equals(right); /// - public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Rgba32 ToRgba32() => Rgba32.FromScaledVector4(this.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromScaledVector4(Vector4 vector) - { - Vector2 scaled = new Vector2(vector.X, vector.Y) * 2F; - scaled -= Vector2.One; - this.PackedValue = Pack(scaled); - } - - /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Vector4 ToScaledVector4() { - var scaled = this.ToVector2(); + Vector2 scaled = this.ToVector2(); scaled += Vector2.One; - scaled /= 2F; - return new Vector4(scaled, 0F, 1F); + scaled /= 2f; + return new Vector4(scaled, 0f, 1f); } /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromVector4(Vector4 vector) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Vector4 ToVector4() => new(this.ToVector2(), 0f, 1f); + + /// + public static PixelTypeInfo GetPixelTypeInfo() + => PixelTypeInfo.Create( + PixelComponentInfo.Create(2, 16, 16), + PixelColorType.Red | PixelColorType.Green, + PixelAlphaRepresentation.None); + + /// + public static PixelOperations CreatePixelOperations() => new PixelOperations(); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedShort2 FromScaledVector4(Vector4 source) { - var vector2 = new Vector2(vector.X, vector.Y); - this.PackedValue = Pack(vector2); + Vector2 scaled = new Vector2(source.X, source.Y) * 2f; + scaled -= Vector2.One; + return new() { PackedValue = Pack(scaled) }; } /// - [MethodImpl(InliningOptions.ShortMethod)] - public readonly Vector4 ToVector4() => new Vector4(this.ToVector2(), 0, 1); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedShort2 FromVector4(Vector4 source) => new() { PackedValue = Pack(new Vector2(source.X, source.Y)) }; /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromArgb32(Argb32 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedShort2 FromAbgr32(Abgr32 source) => FromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgr24(Bgr24 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedShort2 FromArgb32(Argb32 source) => FromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedShort2 FromBgra5551(Bgra5551 source) => FromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromAbgr32(Abgr32 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedShort2 FromBgr24(Bgr24 source) => FromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedShort2 FromBgra32(Bgra32 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL8(L8 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL16(L16 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedShort2 FromL8(L8 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa16(La16 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedShort2 FromL16(L16 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa32(La32 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedShort2 FromLa16(La16 source) => FromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb24(Rgb24 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedShort2 FromLa32(La32 source) => FromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba32(Rgba32 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedShort2 FromRgb24(Rgb24 source) => FromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void ToRgba32(ref Rgba32 dest) => dest.FromScaledVector4(this.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedShort2 FromRgba32(Rgba32 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb48(Rgb48 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedShort2 FromRgb48(Rgb48 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedShort2 FromRgba64(Rgba64 source) => FromScaledVector4(source.ToScaledVector4()); /// /// Expands the packed representation into a . /// The vector components are typically expanded in least to greatest significance order. /// /// The . - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Vector2 ToVector2() => new( (short)(this.PackedValue & 0xFFFF) / MaxPos, (short)(this.PackedValue >> 0x10) / MaxPos); @@ -165,21 +168,19 @@ public void FromVector4(Vector4 vector) public override readonly bool Equals(object? obj) => obj is NormalizedShort2 other && this.Equals(other); /// - [MethodImpl(InliningOptions.ShortMethod)] public readonly bool Equals(NormalizedShort2 other) => this.PackedValue.Equals(other.PackedValue); /// - [MethodImpl(InliningOptions.ShortMethod)] public override readonly int GetHashCode() => this.PackedValue.GetHashCode(); /// public override readonly string ToString() { - var vector = this.ToVector2(); + Vector2 vector = this.ToVector2(); return FormattableString.Invariant($"NormalizedShort2({vector.X:#0.##}, {vector.Y:#0.##})"); } - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] private static uint Pack(Vector2 vector) { vector *= Max; diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort4.cs index 989edbd2ba..2b33fec27a 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort4.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort4.cs @@ -3,6 +3,7 @@ using System.Numerics; using System.Runtime.CompilerServices; +using System.Runtime.Intrinsics; namespace SixLabors.ImageSharp.PixelFormats; @@ -16,8 +17,7 @@ public partial struct NormalizedShort4 : IPixel, IPackedVector { // Largest two byte positive number 0xFFFF >> 1; private const float MaxPos = 0x7FFF; - - private static readonly Vector4 Max = new(MaxPos); + private static readonly Vector4 Max = Vector128.Create(MaxPos).AsVector4(); private static readonly Vector4 Min = Vector4.Negate(Max); /// @@ -36,7 +36,7 @@ public NormalizedShort4(float x, float y, float z, float w) /// Initializes a new instance of the struct. /// /// The vector containing the component values. - public NormalizedShort4(Vector4 vector) => this.PackedValue = Pack(ref vector); + public NormalizedShort4(Vector4 vector) => this.PackedValue = Pack(vector); /// public ulong PackedValue { get; set; } @@ -49,7 +49,7 @@ public NormalizedShort4(float x, float y, float z, float w) /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(NormalizedShort4 left, NormalizedShort4 right) => left.Equals(right); /// @@ -60,37 +60,25 @@ public NormalizedShort4(float x, float y, float z, float w) /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(NormalizedShort4 left, NormalizedShort4 right) => !left.Equals(right); /// - public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Rgba32 ToRgba32() => Rgba32.FromScaledVector4(this.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromScaledVector4(Vector4 vector) - { - vector *= 2F; - vector -= Vector4.One; - this.FromVector4(vector); - } - - /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Vector4 ToScaledVector4() { - var scaled = this.ToVector4(); + Vector4 scaled = this.ToVector4(); scaled += Vector4.One; - scaled /= 2F; + scaled /= 2f; return scaled; } /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector); - - /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Vector4 ToVector4() => new( (short)((this.PackedValue >> 0x00) & 0xFFFF) / MaxPos, (short)((this.PackedValue >> 0x10) & 0xFFFF) / MaxPos, @@ -98,81 +86,98 @@ public readonly Vector4 ToScaledVector4() (short)((this.PackedValue >> 0x30) & 0xFFFF) / MaxPos); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromArgb32(Argb32 source) => this.FromScaledVector4(source.ToScaledVector4()); + public static PixelTypeInfo GetPixelTypeInfo() + => PixelTypeInfo.Create( + PixelComponentInfo.Create(4, 16, 16, 16, 16), + PixelColorType.RGB | PixelColorType.Alpha, + PixelAlphaRepresentation.Unassociated); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgr24(Bgr24 source) => this.FromScaledVector4(source.ToScaledVector4()); + public static PixelOperations CreatePixelOperations() => new PixelOperations(); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedShort4 FromScaledVector4(Vector4 source) + { + source *= 2f; + source -= Vector4.One; + return FromVector4(source); + } /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedShort4 FromVector4(Vector4 source) => new() { PackedValue = Pack(source) }; /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromAbgr32(Abgr32 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedShort4 FromAbgr32(Abgr32 source) => FromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedShort4 FromArgb32(Argb32 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL8(L8 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedShort4 FromBgra5551(Bgra5551 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL16(L16 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedShort4 FromBgr24(Bgr24 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa16(La16 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedShort4 FromBgra32(Bgra32 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa32(La32 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedShort4 FromL8(L8 source) => FromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb24(Rgb24 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedShort4 FromL16(L16 source) => FromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba32(Rgba32 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedShort4 FromLa16(La16 source) => FromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void ToRgba32(ref Rgba32 dest) => dest.FromScaledVector4(this.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedShort4 FromLa32(La32 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb48(Rgb48 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedShort4 FromRgb24(Rgb24 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedShort4 FromRgba32(Rgba32 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedShort4 FromRgb48(Rgb48 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedShort4 FromRgba64(Rgba64 source) => FromScaledVector4(source.ToScaledVector4()); /// public override readonly bool Equals(object? obj) => obj is NormalizedShort4 other && this.Equals(other); /// - [MethodImpl(InliningOptions.ShortMethod)] public readonly bool Equals(NormalizedShort4 other) => this.PackedValue.Equals(other.PackedValue); /// - [MethodImpl(InliningOptions.ShortMethod)] public override readonly int GetHashCode() => this.PackedValue.GetHashCode(); /// public override readonly string ToString() { - var vector = this.ToVector4(); + Vector4 vector = this.ToVector4(); return FormattableString.Invariant($"NormalizedShort4({vector.X:#0.##}, {vector.Y:#0.##}, {vector.Z:#0.##}, {vector.W:#0.##})"); } - [MethodImpl(InliningOptions.ShortMethod)] - private static ulong Pack(ref Vector4 vector) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static ulong Pack(Vector4 vector) { vector *= Max; vector = Numerics.Clamp(vector, Min, Max); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/A8.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/A8.PixelOperations.cs index a7b4b5df00..da0e6ec609 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/A8.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/A8.PixelOperations.cs @@ -1,8 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.Formats; - namespace SixLabors.ImageSharp.PixelFormats; /// @@ -13,12 +11,5 @@ public partial struct A8 /// /// Provides optimized overrides for bulk operations. /// - internal class PixelOperations : PixelOperations - { - private static readonly Lazy LazyInfo = - new Lazy(() => PixelTypeInfo.Create(PixelAlphaRepresentation.Unassociated), true); - - /// - public override PixelTypeInfo GetPixelTypeInfo() => LazyInfo.Value; - } + internal class PixelOperations : PixelOperations; } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Abgr32.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Abgr32.PixelOperations.cs index 66f3ecb245..d459fc4d6c 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Abgr32.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Abgr32.PixelOperations.cs @@ -1,8 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.Formats; - namespace SixLabors.ImageSharp.PixelFormats; /// @@ -13,12 +11,5 @@ public partial struct Abgr32 /// /// Provides optimized overrides for bulk operations. /// - internal partial class PixelOperations : PixelOperations - { - private static readonly Lazy LazyInfo = - new Lazy(() => PixelTypeInfo.Create(PixelAlphaRepresentation.Unassociated), true); - - /// - public override PixelTypeInfo GetPixelTypeInfo() => LazyInfo.Value; - } + internal partial class PixelOperations : PixelOperations; } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Argb32.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Argb32.PixelOperations.cs index 894e92963e..608d618d48 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Argb32.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Argb32.PixelOperations.cs @@ -1,8 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.Formats; - namespace SixLabors.ImageSharp.PixelFormats; /// @@ -13,12 +11,5 @@ public partial struct Argb32 /// /// Provides optimized overrides for bulk operations. /// - internal partial class PixelOperations : PixelOperations - { - private static readonly Lazy LazyInfo = - new Lazy(() => PixelTypeInfo.Create(PixelAlphaRepresentation.Unassociated), true); - - /// - public override PixelTypeInfo GetPixelTypeInfo() => LazyInfo.Value; - } + internal partial class PixelOperations : PixelOperations; } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Bgr24.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Bgr24.PixelOperations.cs index a8f6ab1556..36ffff7147 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Bgr24.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Bgr24.PixelOperations.cs @@ -1,8 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.Formats; - namespace SixLabors.ImageSharp.PixelFormats; /// @@ -13,12 +11,5 @@ public partial struct Bgr24 /// /// Provides optimized overrides for bulk operations. /// - internal partial class PixelOperations : PixelOperations - { - private static readonly Lazy LazyInfo = - new Lazy(() => PixelTypeInfo.Create(PixelAlphaRepresentation.None), true); - - /// - public override PixelTypeInfo GetPixelTypeInfo() => LazyInfo.Value; - } + internal partial class PixelOperations : PixelOperations; } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Bgr565.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Bgr565.PixelOperations.cs index de96903256..87175fe21c 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Bgr565.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Bgr565.PixelOperations.cs @@ -1,8 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.Formats; - namespace SixLabors.ImageSharp.PixelFormats; /// @@ -13,12 +11,5 @@ public partial struct Bgr565 /// /// Provides optimized overrides for bulk operations. /// - internal class PixelOperations : PixelOperations - { - private static readonly Lazy LazyInfo = - new Lazy(() => PixelTypeInfo.Create(PixelAlphaRepresentation.None), true); - - /// - public override PixelTypeInfo GetPixelTypeInfo() => LazyInfo.Value; - } + internal class PixelOperations : PixelOperations; } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Bgra32.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Bgra32.PixelOperations.cs index 1a62b0809c..d2c2b2db74 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Bgra32.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Bgra32.PixelOperations.cs @@ -1,8 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.Formats; - namespace SixLabors.ImageSharp.PixelFormats; /// @@ -13,12 +11,5 @@ public partial struct Bgra32 /// /// Provides optimized overrides for bulk operations. /// - internal partial class PixelOperations : PixelOperations - { - private static readonly Lazy LazyInfo = - new Lazy(() => PixelTypeInfo.Create(PixelAlphaRepresentation.Unassociated), true); - - /// - public override PixelTypeInfo GetPixelTypeInfo() => LazyInfo.Value; - } + internal partial class PixelOperations : PixelOperations; } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Bgra4444.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Bgra4444.PixelOperations.cs index 8ffdaf6cb5..1a0be8b6ff 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Bgra4444.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Bgra4444.PixelOperations.cs @@ -1,8 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.Formats; - namespace SixLabors.ImageSharp.PixelFormats; /// @@ -13,12 +11,5 @@ public partial struct Bgra4444 /// /// Provides optimized overrides for bulk operations. /// - internal class PixelOperations : PixelOperations - { - private static readonly Lazy LazyInfo = - new Lazy(() => PixelTypeInfo.Create(PixelAlphaRepresentation.Unassociated), true); - - /// - public override PixelTypeInfo GetPixelTypeInfo() => LazyInfo.Value; - } + internal class PixelOperations : PixelOperations; } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Bgra5551.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Bgra5551.PixelOperations.cs index 97f5d805e6..3a2856125e 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Bgra5551.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Bgra5551.PixelOperations.cs @@ -1,8 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.Formats; - namespace SixLabors.ImageSharp.PixelFormats; /// @@ -13,12 +11,5 @@ public partial struct Bgra5551 /// /// Provides optimized overrides for bulk operations. /// - internal partial class PixelOperations : PixelOperations - { - private static readonly Lazy LazyInfo = - new Lazy(() => PixelTypeInfo.Create(PixelAlphaRepresentation.Unassociated), true); - - /// - public override PixelTypeInfo GetPixelTypeInfo() => LazyInfo.Value; - } + internal partial class PixelOperations : PixelOperations; } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Byte4.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Byte4.PixelOperations.cs index f6e0b833c2..c012547c95 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Byte4.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Byte4.PixelOperations.cs @@ -1,8 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.Formats; - namespace SixLabors.ImageSharp.PixelFormats; /// @@ -13,12 +11,5 @@ public partial struct Byte4 /// /// Provides optimized overrides for bulk operations. /// - internal class PixelOperations : PixelOperations - { - private static readonly Lazy LazyInfo = - new Lazy(() => PixelTypeInfo.Create(PixelAlphaRepresentation.Unassociated), true); - - /// - public override PixelTypeInfo GetPixelTypeInfo() => LazyInfo.Value; - } + internal class PixelOperations : PixelOperations; } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Abgr32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Abgr32.PixelOperations.Generated.cs index f24ed6fae8..a5e4e3048b 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Abgr32.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Abgr32.PixelOperations.Generated.cs @@ -21,337 +21,316 @@ public partial struct Abgr32 internal partial class PixelOperations : PixelOperations { /// - public override void FromAbgr32(Configuration configuration, ReadOnlySpan source, Span destinationPixels) + public override void FromAbgr32(Configuration configuration, ReadOnlySpan source, Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(source, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - source.CopyTo(destinationPixels.Slice(0, source.Length)); + source.CopyTo(destination.Slice(0, source.Length)); } /// - public override void ToAbgr32(Configuration configuration, ReadOnlySpan sourcePixels, Span destinationPixels) + public override void ToAbgr32(Configuration configuration, ReadOnlySpan source, Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - sourcePixels.CopyTo(destinationPixels.Slice(0, sourcePixels.Length)); + source.CopyTo(destination.Slice(0, source.Length)); } /// public override void FromVector4Destructive( Configuration configuration, Span sourceVectors, - Span destinationPixels, + Span destination, PixelConversionModifiers modifiers) { - Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destinationPixels, modifiers.Remove(PixelConversionModifiers.Scale)); + Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destination, modifiers.Remove(PixelConversionModifiers.Scale)); } /// public override void ToVector4( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destVectors, + ReadOnlySpan source, + Span destination, PixelConversionModifiers modifiers) { - Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, modifiers.Remove(PixelConversionModifiers.Scale)); + Vector4Converters.RgbaCompatible.ToVector4(configuration, this, source, destination, modifiers.Remove(PixelConversionModifiers.Scale)); } /// public override void ToRgba32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromAbgr32.ToRgba32(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromAbgr32.ToRgba32(sourceBytes, destinationBytes); } /// public override void FromRgba32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromRgba32.ToAbgr32(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromRgba32.ToAbgr32(sourceBytes, destinationBytes); } /// public override void ToArgb32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromAbgr32.ToArgb32(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromAbgr32.ToArgb32(sourceBytes, destinationBytes); } /// public override void FromArgb32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromArgb32.ToAbgr32(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromArgb32.ToAbgr32(sourceBytes, destinationBytes); } /// public override void ToBgra32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromAbgr32.ToBgra32(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromAbgr32.ToBgra32(sourceBytes, destinationBytes); } /// public override void FromBgra32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromBgra32.ToAbgr32(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromBgra32.ToAbgr32(sourceBytes, destinationBytes); } /// public override void ToRgb24( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromAbgr32.ToRgb24(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromAbgr32.ToRgb24(sourceBytes, destinationBytes); } /// public override void FromRgb24( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromRgb24.ToAbgr32(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromRgb24.ToAbgr32(sourceBytes, destinationBytes); } /// public override void ToBgr24( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromAbgr32.ToBgr24(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromAbgr32.ToBgr24(sourceBytes, destinationBytes); } /// public override void FromBgr24( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromBgr24.ToAbgr32(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromBgr24.ToAbgr32(sourceBytes, destinationBytes); } /// public override void ToL8( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Abgr32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref L8 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Abgr32 sourceBase = ref MemoryMarshal.GetReference(source); + ref L8 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Abgr32 sp = ref Unsafe.Add(ref sourceRef, i); - ref L8 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromAbgr32(sp); + Unsafe.Add(ref destinationBase, i) = L8.FromAbgr32(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToL16( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Abgr32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref L16 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Abgr32 sourceBase = ref MemoryMarshal.GetReference(source); + ref L16 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Abgr32 sp = ref Unsafe.Add(ref sourceRef, i); - ref L16 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromAbgr32(sp); + Unsafe.Add(ref destinationBase, i) = L16.FromAbgr32(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToLa16( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Abgr32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref La16 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Abgr32 sourceBase = ref MemoryMarshal.GetReference(source); + ref La16 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Abgr32 sp = ref Unsafe.Add(ref sourceRef, i); - ref La16 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromAbgr32(sp); + Unsafe.Add(ref destinationBase, i) = La16.FromAbgr32(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToLa32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Abgr32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref La32 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Abgr32 sourceBase = ref MemoryMarshal.GetReference(source); + ref La32 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Abgr32 sp = ref Unsafe.Add(ref sourceRef, i); - ref La32 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromAbgr32(sp); + Unsafe.Add(ref destinationBase, i) = La32.FromAbgr32(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToRgb48( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Abgr32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgb48 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Abgr32 sourceBase = ref MemoryMarshal.GetReference(source); + ref Rgb48 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Abgr32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromAbgr32(sp); + Unsafe.Add(ref destinationBase, i) = Rgb48.FromAbgr32(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToRgba64( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Abgr32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgba64 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Abgr32 sourceBase = ref MemoryMarshal.GetReference(source); + ref Rgba64 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Abgr32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromAbgr32(sp); + Unsafe.Add(ref destinationBase, i) = Rgba64.FromAbgr32(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToBgra5551( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Abgr32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Bgra5551 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Abgr32 sourceBase = ref MemoryMarshal.GetReference(source); + ref Bgra5551 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Abgr32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Bgra5551 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromAbgr32(sp); + Unsafe.Add(ref destinationBase, i) = Bgra5551.FromAbgr32(Unsafe.Add(ref sourceBase, i)); } } /// public override void From( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { - PixelOperations.Instance.ToAbgr32(configuration, sourcePixels, destinationPixels.Slice(0, sourcePixels.Length)); + PixelOperations.Instance.ToAbgr32(configuration, source, destination.Slice(0, source.Length)); } } } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Argb32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Argb32.PixelOperations.Generated.cs index 37ac39a851..30fed8d1c1 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Argb32.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Argb32.PixelOperations.Generated.cs @@ -21,337 +21,316 @@ public partial struct Argb32 internal partial class PixelOperations : PixelOperations { /// - public override void FromArgb32(Configuration configuration, ReadOnlySpan source, Span destinationPixels) + public override void FromArgb32(Configuration configuration, ReadOnlySpan source, Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(source, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - source.CopyTo(destinationPixels.Slice(0, source.Length)); + source.CopyTo(destination.Slice(0, source.Length)); } /// - public override void ToArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destinationPixels) + public override void ToArgb32(Configuration configuration, ReadOnlySpan source, Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - sourcePixels.CopyTo(destinationPixels.Slice(0, sourcePixels.Length)); + source.CopyTo(destination.Slice(0, source.Length)); } /// public override void FromVector4Destructive( Configuration configuration, Span sourceVectors, - Span destinationPixels, + Span destination, PixelConversionModifiers modifiers) { - Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destinationPixels, modifiers.Remove(PixelConversionModifiers.Scale)); + Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destination, modifiers.Remove(PixelConversionModifiers.Scale)); } /// public override void ToVector4( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destVectors, + ReadOnlySpan source, + Span destination, PixelConversionModifiers modifiers) { - Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, modifiers.Remove(PixelConversionModifiers.Scale)); + Vector4Converters.RgbaCompatible.ToVector4(configuration, this, source, destination, modifiers.Remove(PixelConversionModifiers.Scale)); } /// public override void ToRgba32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromArgb32.ToRgba32(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromArgb32.ToRgba32(sourceBytes, destinationBytes); } /// public override void FromRgba32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromRgba32.ToArgb32(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromRgba32.ToArgb32(sourceBytes, destinationBytes); } /// public override void ToAbgr32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromArgb32.ToAbgr32(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromArgb32.ToAbgr32(sourceBytes, destinationBytes); } /// public override void FromAbgr32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromAbgr32.ToArgb32(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromAbgr32.ToArgb32(sourceBytes, destinationBytes); } /// public override void ToBgra32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromArgb32.ToBgra32(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromArgb32.ToBgra32(sourceBytes, destinationBytes); } /// public override void FromBgra32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromBgra32.ToArgb32(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromBgra32.ToArgb32(sourceBytes, destinationBytes); } /// public override void ToRgb24( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromArgb32.ToRgb24(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromArgb32.ToRgb24(sourceBytes, destinationBytes); } /// public override void FromRgb24( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromRgb24.ToArgb32(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromRgb24.ToArgb32(sourceBytes, destinationBytes); } /// public override void ToBgr24( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromArgb32.ToBgr24(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromArgb32.ToBgr24(sourceBytes, destinationBytes); } /// public override void FromBgr24( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromBgr24.ToArgb32(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromBgr24.ToArgb32(sourceBytes, destinationBytes); } /// public override void ToL8( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref L8 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Argb32 sourceBase = ref MemoryMarshal.GetReference(source); + ref L8 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); - ref L8 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromArgb32(sp); + Unsafe.Add(ref destinationBase, i) = L8.FromArgb32(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToL16( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref L16 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Argb32 sourceBase = ref MemoryMarshal.GetReference(source); + ref L16 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); - ref L16 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromArgb32(sp); + Unsafe.Add(ref destinationBase, i) = L16.FromArgb32(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToLa16( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref La16 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Argb32 sourceBase = ref MemoryMarshal.GetReference(source); + ref La16 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); - ref La16 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromArgb32(sp); + Unsafe.Add(ref destinationBase, i) = La16.FromArgb32(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToLa32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref La32 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Argb32 sourceBase = ref MemoryMarshal.GetReference(source); + ref La32 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); - ref La32 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromArgb32(sp); + Unsafe.Add(ref destinationBase, i) = La32.FromArgb32(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToRgb48( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgb48 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Argb32 sourceBase = ref MemoryMarshal.GetReference(source); + ref Rgb48 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromArgb32(sp); + Unsafe.Add(ref destinationBase, i) = Rgb48.FromArgb32(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToRgba64( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgba64 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Argb32 sourceBase = ref MemoryMarshal.GetReference(source); + ref Rgba64 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromArgb32(sp); + Unsafe.Add(ref destinationBase, i) = Rgba64.FromArgb32(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToBgra5551( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Bgra5551 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Argb32 sourceBase = ref MemoryMarshal.GetReference(source); + ref Bgra5551 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Bgra5551 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromArgb32(sp); + Unsafe.Add(ref destinationBase, i) = Bgra5551.FromArgb32(Unsafe.Add(ref sourceBase, i)); } } /// public override void From( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { - PixelOperations.Instance.ToArgb32(configuration, sourcePixels, destinationPixels.Slice(0, sourcePixels.Length)); + PixelOperations.Instance.ToArgb32(configuration, source, destination.Slice(0, source.Length)); } } } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Bgr24.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Bgr24.PixelOperations.Generated.cs index f604d6f970..e3ff3a7fea 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Bgr24.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Bgr24.PixelOperations.Generated.cs @@ -21,337 +21,316 @@ public partial struct Bgr24 internal partial class PixelOperations : PixelOperations { /// - public override void FromBgr24(Configuration configuration, ReadOnlySpan source, Span destinationPixels) + public override void FromBgr24(Configuration configuration, ReadOnlySpan source, Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(source, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - source.CopyTo(destinationPixels.Slice(0, source.Length)); + source.CopyTo(destination.Slice(0, source.Length)); } /// - public override void ToBgr24(Configuration configuration, ReadOnlySpan sourcePixels, Span destinationPixels) + public override void ToBgr24(Configuration configuration, ReadOnlySpan source, Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - sourcePixels.CopyTo(destinationPixels.Slice(0, sourcePixels.Length)); + source.CopyTo(destination.Slice(0, source.Length)); } /// public override void FromVector4Destructive( Configuration configuration, Span sourceVectors, - Span destinationPixels, + Span destination, PixelConversionModifiers modifiers) { - Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destinationPixels, modifiers.Remove(PixelConversionModifiers.Scale | PixelConversionModifiers.Premultiply)); + Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destination, modifiers.Remove(PixelConversionModifiers.Scale | PixelConversionModifiers.Premultiply)); } /// public override void ToVector4( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destVectors, + ReadOnlySpan source, + Span destination, PixelConversionModifiers modifiers) { - Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, modifiers.Remove(PixelConversionModifiers.Scale | PixelConversionModifiers.Premultiply)); + Vector4Converters.RgbaCompatible.ToVector4(configuration, this, source, destination, modifiers.Remove(PixelConversionModifiers.Scale | PixelConversionModifiers.Premultiply)); } /// public override void ToRgba32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromBgr24.ToRgba32(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromBgr24.ToRgba32(sourceBytes, destinationBytes); } /// public override void FromRgba32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromRgba32.ToBgr24(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromRgba32.ToBgr24(sourceBytes, destinationBytes); } /// public override void ToArgb32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromBgr24.ToArgb32(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromBgr24.ToArgb32(sourceBytes, destinationBytes); } /// public override void FromArgb32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromArgb32.ToBgr24(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromArgb32.ToBgr24(sourceBytes, destinationBytes); } /// public override void ToAbgr32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromBgr24.ToAbgr32(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromBgr24.ToAbgr32(sourceBytes, destinationBytes); } /// public override void FromAbgr32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromAbgr32.ToBgr24(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromAbgr32.ToBgr24(sourceBytes, destinationBytes); } /// public override void ToBgra32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromBgr24.ToBgra32(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromBgr24.ToBgra32(sourceBytes, destinationBytes); } /// public override void FromBgra32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromBgra32.ToBgr24(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromBgra32.ToBgr24(sourceBytes, destinationBytes); } /// public override void ToRgb24( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromBgr24.ToRgb24(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromBgr24.ToRgb24(sourceBytes, destinationBytes); } /// public override void FromRgb24( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromRgb24.ToBgr24(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromRgb24.ToBgr24(sourceBytes, destinationBytes); } /// public override void ToL8( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref L8 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Bgr24 sourceBase = ref MemoryMarshal.GetReference(source); + ref L8 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); - ref L8 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromBgr24(sp); + Unsafe.Add(ref destinationBase, i) = L8.FromBgr24(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToL16( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref L16 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Bgr24 sourceBase = ref MemoryMarshal.GetReference(source); + ref L16 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); - ref L16 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromBgr24(sp); + Unsafe.Add(ref destinationBase, i) = L16.FromBgr24(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToLa16( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref La16 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Bgr24 sourceBase = ref MemoryMarshal.GetReference(source); + ref La16 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); - ref La16 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromBgr24(sp); + Unsafe.Add(ref destinationBase, i) = La16.FromBgr24(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToLa32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref La32 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Bgr24 sourceBase = ref MemoryMarshal.GetReference(source); + ref La32 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); - ref La32 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromBgr24(sp); + Unsafe.Add(ref destinationBase, i) = La32.FromBgr24(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToRgb48( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgb48 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Bgr24 sourceBase = ref MemoryMarshal.GetReference(source); + ref Rgb48 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromBgr24(sp); + Unsafe.Add(ref destinationBase, i) = Rgb48.FromBgr24(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToRgba64( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgba64 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Bgr24 sourceBase = ref MemoryMarshal.GetReference(source); + ref Rgba64 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromBgr24(sp); + Unsafe.Add(ref destinationBase, i) = Rgba64.FromBgr24(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToBgra5551( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Bgra5551 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Bgr24 sourceBase = ref MemoryMarshal.GetReference(source); + ref Bgra5551 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); - ref Bgra5551 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromBgr24(sp); + Unsafe.Add(ref destinationBase, i) = Bgra5551.FromBgr24(Unsafe.Add(ref sourceBase, i)); } } /// public override void From( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { - PixelOperations.Instance.ToBgr24(configuration, sourcePixels, destinationPixels.Slice(0, sourcePixels.Length)); + PixelOperations.Instance.ToBgr24(configuration, source, destination.Slice(0, source.Length)); } } } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Bgra32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Bgra32.PixelOperations.Generated.cs index b9f7a49e11..ae6be44012 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Bgra32.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Bgra32.PixelOperations.Generated.cs @@ -21,337 +21,316 @@ public partial struct Bgra32 internal partial class PixelOperations : PixelOperations { /// - public override void FromBgra32(Configuration configuration, ReadOnlySpan source, Span destinationPixels) + public override void FromBgra32(Configuration configuration, ReadOnlySpan source, Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(source, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - source.CopyTo(destinationPixels.Slice(0, source.Length)); + source.CopyTo(destination.Slice(0, source.Length)); } /// - public override void ToBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destinationPixels) + public override void ToBgra32(Configuration configuration, ReadOnlySpan source, Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - sourcePixels.CopyTo(destinationPixels.Slice(0, sourcePixels.Length)); + source.CopyTo(destination.Slice(0, source.Length)); } /// public override void FromVector4Destructive( Configuration configuration, Span sourceVectors, - Span destinationPixels, + Span destination, PixelConversionModifiers modifiers) { - Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destinationPixels, modifiers.Remove(PixelConversionModifiers.Scale)); + Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destination, modifiers.Remove(PixelConversionModifiers.Scale)); } /// public override void ToVector4( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destVectors, + ReadOnlySpan source, + Span destination, PixelConversionModifiers modifiers) { - Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, modifiers.Remove(PixelConversionModifiers.Scale)); + Vector4Converters.RgbaCompatible.ToVector4(configuration, this, source, destination, modifiers.Remove(PixelConversionModifiers.Scale)); } /// public override void ToRgba32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromBgra32.ToRgba32(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromBgra32.ToRgba32(sourceBytes, destinationBytes); } /// public override void FromRgba32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromRgba32.ToBgra32(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromRgba32.ToBgra32(sourceBytes, destinationBytes); } /// public override void ToArgb32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromBgra32.ToArgb32(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromBgra32.ToArgb32(sourceBytes, destinationBytes); } /// public override void FromArgb32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromArgb32.ToBgra32(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromArgb32.ToBgra32(sourceBytes, destinationBytes); } /// public override void ToAbgr32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromBgra32.ToAbgr32(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromBgra32.ToAbgr32(sourceBytes, destinationBytes); } /// public override void FromAbgr32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromAbgr32.ToBgra32(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromAbgr32.ToBgra32(sourceBytes, destinationBytes); } /// public override void ToRgb24( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromBgra32.ToRgb24(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromBgra32.ToRgb24(sourceBytes, destinationBytes); } /// public override void FromRgb24( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromRgb24.ToBgra32(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromRgb24.ToBgra32(sourceBytes, destinationBytes); } /// public override void ToBgr24( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromBgra32.ToBgr24(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromBgra32.ToBgr24(sourceBytes, destinationBytes); } /// public override void FromBgr24( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromBgr24.ToBgra32(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromBgr24.ToBgra32(sourceBytes, destinationBytes); } /// public override void ToL8( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref L8 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Bgra32 sourceBase = ref MemoryMarshal.GetReference(source); + ref L8 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); - ref L8 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromBgra32(sp); + Unsafe.Add(ref destinationBase, i) = L8.FromBgra32(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToL16( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref L16 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Bgra32 sourceBase = ref MemoryMarshal.GetReference(source); + ref L16 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); - ref L16 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromBgra32(sp); + Unsafe.Add(ref destinationBase, i) = L16.FromBgra32(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToLa16( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref La16 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Bgra32 sourceBase = ref MemoryMarshal.GetReference(source); + ref La16 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); - ref La16 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromBgra32(sp); + Unsafe.Add(ref destinationBase, i) = La16.FromBgra32(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToLa32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref La32 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Bgra32 sourceBase = ref MemoryMarshal.GetReference(source); + ref La32 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); - ref La32 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromBgra32(sp); + Unsafe.Add(ref destinationBase, i) = La32.FromBgra32(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToRgb48( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgb48 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Bgra32 sourceBase = ref MemoryMarshal.GetReference(source); + ref Rgb48 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromBgra32(sp); + Unsafe.Add(ref destinationBase, i) = Rgb48.FromBgra32(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToRgba64( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgba64 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Bgra32 sourceBase = ref MemoryMarshal.GetReference(source); + ref Rgba64 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromBgra32(sp); + Unsafe.Add(ref destinationBase, i) = Rgba64.FromBgra32(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToBgra5551( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Bgra5551 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Bgra32 sourceBase = ref MemoryMarshal.GetReference(source); + ref Bgra5551 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Bgra5551 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromBgra32(sp); + Unsafe.Add(ref destinationBase, i) = Bgra5551.FromBgra32(Unsafe.Add(ref sourceBase, i)); } } /// public override void From( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { - PixelOperations.Instance.ToBgra32(configuration, sourcePixels, destinationPixels.Slice(0, sourcePixels.Length)); + PixelOperations.Instance.ToBgra32(configuration, source, destination.Slice(0, source.Length)); } } } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Bgra5551.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Bgra5551.PixelOperations.Generated.cs index c1ba4f0618..9e877cb9de 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Bgra5551.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Bgra5551.PixelOperations.Generated.cs @@ -21,282 +21,246 @@ public partial struct Bgra5551 internal partial class PixelOperations : PixelOperations { /// - public override void FromBgra5551(Configuration configuration, ReadOnlySpan source, Span destinationPixels) + public override void FromBgra5551(Configuration configuration, ReadOnlySpan source, Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(source, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - source.CopyTo(destinationPixels.Slice(0, source.Length)); + source.CopyTo(destination.Slice(0, source.Length)); } /// - public override void ToBgra5551(Configuration configuration, ReadOnlySpan sourcePixels, Span destinationPixels) + public override void ToBgra5551(Configuration configuration, ReadOnlySpan source, Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - sourcePixels.CopyTo(destinationPixels.Slice(0, sourcePixels.Length)); + source.CopyTo(destination.Slice(0, source.Length)); } /// public override void ToArgb32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Bgra5551 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Argb32 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Bgra5551 sourceBase = ref MemoryMarshal.GetReference(source); + ref Argb32 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Bgra5551 sp = ref Unsafe.Add(ref sourceRef, i); - ref Argb32 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromBgra5551(sp); + Unsafe.Add(ref destinationBase, i) = Argb32.FromBgra5551(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToAbgr32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Bgra5551 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Abgr32 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Bgra5551 sourceBase = ref MemoryMarshal.GetReference(source); + ref Abgr32 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Bgra5551 sp = ref Unsafe.Add(ref sourceRef, i); - ref Abgr32 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromBgra5551(sp); + Unsafe.Add(ref destinationBase, i) = Abgr32.FromBgra5551(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToBgr24( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Bgra5551 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Bgr24 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Bgra5551 sourceBase = ref MemoryMarshal.GetReference(source); + ref Bgr24 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Bgra5551 sp = ref Unsafe.Add(ref sourceRef, i); - ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromBgra5551(sp); + Unsafe.Add(ref destinationBase, i) = Bgr24.FromBgra5551(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToBgra32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Bgra5551 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Bgra32 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Bgra5551 sourceBase = ref MemoryMarshal.GetReference(source); + ref Bgra32 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Bgra5551 sp = ref Unsafe.Add(ref sourceRef, i); - ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromBgra5551(sp); + Unsafe.Add(ref destinationBase, i) = Bgra32.FromBgra5551(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToL8( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Bgra5551 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref L8 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Bgra5551 sourceBase = ref MemoryMarshal.GetReference(source); + ref L8 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Bgra5551 sp = ref Unsafe.Add(ref sourceRef, i); - ref L8 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromBgra5551(sp); + Unsafe.Add(ref destinationBase, i) = L8.FromBgra5551(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToL16( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Bgra5551 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref L16 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Bgra5551 sourceBase = ref MemoryMarshal.GetReference(source); + ref L16 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Bgra5551 sp = ref Unsafe.Add(ref sourceRef, i); - ref L16 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromBgra5551(sp); + Unsafe.Add(ref destinationBase, i) = L16.FromBgra5551(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToLa16( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Bgra5551 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref La16 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Bgra5551 sourceBase = ref MemoryMarshal.GetReference(source); + ref La16 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Bgra5551 sp = ref Unsafe.Add(ref sourceRef, i); - ref La16 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromBgra5551(sp); + Unsafe.Add(ref destinationBase, i) = La16.FromBgra5551(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToLa32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Bgra5551 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref La32 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Bgra5551 sourceBase = ref MemoryMarshal.GetReference(source); + ref La32 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Bgra5551 sp = ref Unsafe.Add(ref sourceRef, i); - ref La32 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromBgra5551(sp); + Unsafe.Add(ref destinationBase, i) = La32.FromBgra5551(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToRgb24( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Bgra5551 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgb24 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Bgra5551 sourceBase = ref MemoryMarshal.GetReference(source); + ref Rgb24 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Bgra5551 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromBgra5551(sp); + Unsafe.Add(ref destinationBase, i) = Rgb24.FromBgra5551(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToRgba32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Bgra5551 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgba32 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Bgra5551 sourceBase = ref MemoryMarshal.GetReference(source); + ref Rgba32 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Bgra5551 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromBgra5551(sp); + Unsafe.Add(ref destinationBase, i) = Rgba32.FromBgra5551(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToRgb48( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Bgra5551 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgb48 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Bgra5551 sourceBase = ref MemoryMarshal.GetReference(source); + ref Rgb48 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Bgra5551 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromBgra5551(sp); + Unsafe.Add(ref destinationBase, i) = Rgb48.FromBgra5551(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToRgba64( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Bgra5551 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgba64 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Bgra5551 sourceBase = ref MemoryMarshal.GetReference(source); + ref Rgba64 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Bgra5551 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromBgra5551(sp); + Unsafe.Add(ref destinationBase, i) = Rgba64.FromBgra5551(Unsafe.Add(ref sourceBase, i)); } } /// public override void From( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { - PixelOperations.Instance.ToBgra5551(configuration, sourcePixels, destinationPixels.Slice(0, sourcePixels.Length)); + PixelOperations.Instance.ToBgra5551(configuration, source, destination.Slice(0, source.Length)); } } } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/L16.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/L16.PixelOperations.Generated.cs index c38d752ea6..21c7824560 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/L16.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/L16.PixelOperations.Generated.cs @@ -21,282 +21,246 @@ public partial struct L16 internal partial class PixelOperations : PixelOperations { /// - public override void FromL16(Configuration configuration, ReadOnlySpan source, Span destinationPixels) + public override void FromL16(Configuration configuration, ReadOnlySpan source, Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(source, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - source.CopyTo(destinationPixels.Slice(0, source.Length)); + source.CopyTo(destination.Slice(0, source.Length)); } /// - public override void ToL16(Configuration configuration, ReadOnlySpan sourcePixels, Span destinationPixels) + public override void ToL16(Configuration configuration, ReadOnlySpan source, Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - sourcePixels.CopyTo(destinationPixels.Slice(0, sourcePixels.Length)); + source.CopyTo(destination.Slice(0, source.Length)); } /// public override void ToArgb32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref L16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Argb32 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref L16 sourceBase = ref MemoryMarshal.GetReference(source); + ref Argb32 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref L16 sp = ref Unsafe.Add(ref sourceRef, i); - ref Argb32 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromL16(sp); + Unsafe.Add(ref destinationBase, i) = Argb32.FromL16(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToAbgr32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref L16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Abgr32 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref L16 sourceBase = ref MemoryMarshal.GetReference(source); + ref Abgr32 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref L16 sp = ref Unsafe.Add(ref sourceRef, i); - ref Abgr32 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromL16(sp); + Unsafe.Add(ref destinationBase, i) = Abgr32.FromL16(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToBgr24( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref L16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Bgr24 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref L16 sourceBase = ref MemoryMarshal.GetReference(source); + ref Bgr24 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref L16 sp = ref Unsafe.Add(ref sourceRef, i); - ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromL16(sp); + Unsafe.Add(ref destinationBase, i) = Bgr24.FromL16(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToBgra32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref L16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Bgra32 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref L16 sourceBase = ref MemoryMarshal.GetReference(source); + ref Bgra32 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref L16 sp = ref Unsafe.Add(ref sourceRef, i); - ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromL16(sp); + Unsafe.Add(ref destinationBase, i) = Bgra32.FromL16(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToL8( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref L16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref L8 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref L16 sourceBase = ref MemoryMarshal.GetReference(source); + ref L8 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref L16 sp = ref Unsafe.Add(ref sourceRef, i); - ref L8 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromL16(sp); + Unsafe.Add(ref destinationBase, i) = L8.FromL16(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToLa16( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref L16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref La16 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref L16 sourceBase = ref MemoryMarshal.GetReference(source); + ref La16 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref L16 sp = ref Unsafe.Add(ref sourceRef, i); - ref La16 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromL16(sp); + Unsafe.Add(ref destinationBase, i) = La16.FromL16(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToLa32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref L16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref La32 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref L16 sourceBase = ref MemoryMarshal.GetReference(source); + ref La32 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref L16 sp = ref Unsafe.Add(ref sourceRef, i); - ref La32 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromL16(sp); + Unsafe.Add(ref destinationBase, i) = La32.FromL16(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToRgb24( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref L16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgb24 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref L16 sourceBase = ref MemoryMarshal.GetReference(source); + ref Rgb24 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref L16 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromL16(sp); + Unsafe.Add(ref destinationBase, i) = Rgb24.FromL16(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToRgba32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref L16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgba32 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref L16 sourceBase = ref MemoryMarshal.GetReference(source); + ref Rgba32 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref L16 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromL16(sp); + Unsafe.Add(ref destinationBase, i) = Rgba32.FromL16(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToRgb48( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref L16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgb48 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref L16 sourceBase = ref MemoryMarshal.GetReference(source); + ref Rgb48 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref L16 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromL16(sp); + Unsafe.Add(ref destinationBase, i) = Rgb48.FromL16(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToRgba64( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref L16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgba64 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref L16 sourceBase = ref MemoryMarshal.GetReference(source); + ref Rgba64 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref L16 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromL16(sp); + Unsafe.Add(ref destinationBase, i) = Rgba64.FromL16(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToBgra5551( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref L16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Bgra5551 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref L16 sourceBase = ref MemoryMarshal.GetReference(source); + ref Bgra5551 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref L16 sp = ref Unsafe.Add(ref sourceRef, i); - ref Bgra5551 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromL16(sp); + Unsafe.Add(ref destinationBase, i) = Bgra5551.FromL16(Unsafe.Add(ref sourceBase, i)); } } /// public override void From( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { - PixelOperations.Instance.ToL16(configuration, sourcePixels, destinationPixels.Slice(0, sourcePixels.Length)); + PixelOperations.Instance.ToL16(configuration, source, destination.Slice(0, source.Length)); } } } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/L8.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/L8.PixelOperations.Generated.cs index 656a0546ba..6a7c458001 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/L8.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/L8.PixelOperations.Generated.cs @@ -21,282 +21,246 @@ public partial struct L8 internal partial class PixelOperations : PixelOperations { /// - public override void FromL8(Configuration configuration, ReadOnlySpan source, Span destinationPixels) + public override void FromL8(Configuration configuration, ReadOnlySpan source, Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(source, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - source.CopyTo(destinationPixels.Slice(0, source.Length)); + source.CopyTo(destination.Slice(0, source.Length)); } /// - public override void ToL8(Configuration configuration, ReadOnlySpan sourcePixels, Span destinationPixels) + public override void ToL8(Configuration configuration, ReadOnlySpan source, Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - sourcePixels.CopyTo(destinationPixels.Slice(0, sourcePixels.Length)); + source.CopyTo(destination.Slice(0, source.Length)); } /// public override void ToArgb32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref L8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Argb32 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref L8 sourceBase = ref MemoryMarshal.GetReference(source); + ref Argb32 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref L8 sp = ref Unsafe.Add(ref sourceRef, i); - ref Argb32 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromL8(sp); + Unsafe.Add(ref destinationBase, i) = Argb32.FromL8(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToAbgr32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref L8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Abgr32 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref L8 sourceBase = ref MemoryMarshal.GetReference(source); + ref Abgr32 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref L8 sp = ref Unsafe.Add(ref sourceRef, i); - ref Abgr32 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromL8(sp); + Unsafe.Add(ref destinationBase, i) = Abgr32.FromL8(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToBgr24( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref L8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Bgr24 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref L8 sourceBase = ref MemoryMarshal.GetReference(source); + ref Bgr24 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref L8 sp = ref Unsafe.Add(ref sourceRef, i); - ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromL8(sp); + Unsafe.Add(ref destinationBase, i) = Bgr24.FromL8(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToBgra32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref L8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Bgra32 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref L8 sourceBase = ref MemoryMarshal.GetReference(source); + ref Bgra32 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref L8 sp = ref Unsafe.Add(ref sourceRef, i); - ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromL8(sp); + Unsafe.Add(ref destinationBase, i) = Bgra32.FromL8(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToL16( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref L8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref L16 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref L8 sourceBase = ref MemoryMarshal.GetReference(source); + ref L16 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref L8 sp = ref Unsafe.Add(ref sourceRef, i); - ref L16 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromL8(sp); + Unsafe.Add(ref destinationBase, i) = L16.FromL8(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToLa16( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref L8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref La16 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref L8 sourceBase = ref MemoryMarshal.GetReference(source); + ref La16 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref L8 sp = ref Unsafe.Add(ref sourceRef, i); - ref La16 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromL8(sp); + Unsafe.Add(ref destinationBase, i) = La16.FromL8(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToLa32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref L8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref La32 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref L8 sourceBase = ref MemoryMarshal.GetReference(source); + ref La32 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref L8 sp = ref Unsafe.Add(ref sourceRef, i); - ref La32 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromL8(sp); + Unsafe.Add(ref destinationBase, i) = La32.FromL8(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToRgb24( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref L8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgb24 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref L8 sourceBase = ref MemoryMarshal.GetReference(source); + ref Rgb24 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref L8 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromL8(sp); + Unsafe.Add(ref destinationBase, i) = Rgb24.FromL8(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToRgba32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref L8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgba32 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref L8 sourceBase = ref MemoryMarshal.GetReference(source); + ref Rgba32 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref L8 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromL8(sp); + Unsafe.Add(ref destinationBase, i) = Rgba32.FromL8(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToRgb48( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref L8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgb48 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref L8 sourceBase = ref MemoryMarshal.GetReference(source); + ref Rgb48 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref L8 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromL8(sp); + Unsafe.Add(ref destinationBase, i) = Rgb48.FromL8(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToRgba64( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref L8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgba64 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref L8 sourceBase = ref MemoryMarshal.GetReference(source); + ref Rgba64 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref L8 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromL8(sp); + Unsafe.Add(ref destinationBase, i) = Rgba64.FromL8(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToBgra5551( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref L8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Bgra5551 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref L8 sourceBase = ref MemoryMarshal.GetReference(source); + ref Bgra5551 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref L8 sp = ref Unsafe.Add(ref sourceRef, i); - ref Bgra5551 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromL8(sp); + Unsafe.Add(ref destinationBase, i) = Bgra5551.FromL8(Unsafe.Add(ref sourceBase, i)); } } /// public override void From( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { - PixelOperations.Instance.ToL8(configuration, sourcePixels, destinationPixels.Slice(0, sourcePixels.Length)); + PixelOperations.Instance.ToL8(configuration, source, destination.Slice(0, source.Length)); } } } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/La16.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/La16.PixelOperations.Generated.cs index 82be1323cd..2346f32e1b 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/La16.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/La16.PixelOperations.Generated.cs @@ -21,282 +21,246 @@ public partial struct La16 internal partial class PixelOperations : PixelOperations { /// - public override void FromLa16(Configuration configuration, ReadOnlySpan source, Span destinationPixels) + public override void FromLa16(Configuration configuration, ReadOnlySpan source, Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(source, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - source.CopyTo(destinationPixels.Slice(0, source.Length)); + source.CopyTo(destination.Slice(0, source.Length)); } /// - public override void ToLa16(Configuration configuration, ReadOnlySpan sourcePixels, Span destinationPixels) + public override void ToLa16(Configuration configuration, ReadOnlySpan source, Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - sourcePixels.CopyTo(destinationPixels.Slice(0, sourcePixels.Length)); + source.CopyTo(destination.Slice(0, source.Length)); } /// public override void ToArgb32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref La16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Argb32 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref La16 sourceBase = ref MemoryMarshal.GetReference(source); + ref Argb32 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref La16 sp = ref Unsafe.Add(ref sourceRef, i); - ref Argb32 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromLa16(sp); + Unsafe.Add(ref destinationBase, i) = Argb32.FromLa16(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToAbgr32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref La16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Abgr32 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref La16 sourceBase = ref MemoryMarshal.GetReference(source); + ref Abgr32 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref La16 sp = ref Unsafe.Add(ref sourceRef, i); - ref Abgr32 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromLa16(sp); + Unsafe.Add(ref destinationBase, i) = Abgr32.FromLa16(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToBgr24( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref La16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Bgr24 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref La16 sourceBase = ref MemoryMarshal.GetReference(source); + ref Bgr24 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref La16 sp = ref Unsafe.Add(ref sourceRef, i); - ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromLa16(sp); + Unsafe.Add(ref destinationBase, i) = Bgr24.FromLa16(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToBgra32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref La16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Bgra32 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref La16 sourceBase = ref MemoryMarshal.GetReference(source); + ref Bgra32 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref La16 sp = ref Unsafe.Add(ref sourceRef, i); - ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromLa16(sp); + Unsafe.Add(ref destinationBase, i) = Bgra32.FromLa16(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToL8( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref La16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref L8 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref La16 sourceBase = ref MemoryMarshal.GetReference(source); + ref L8 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref La16 sp = ref Unsafe.Add(ref sourceRef, i); - ref L8 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromLa16(sp); + Unsafe.Add(ref destinationBase, i) = L8.FromLa16(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToL16( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref La16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref L16 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref La16 sourceBase = ref MemoryMarshal.GetReference(source); + ref L16 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref La16 sp = ref Unsafe.Add(ref sourceRef, i); - ref L16 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromLa16(sp); + Unsafe.Add(ref destinationBase, i) = L16.FromLa16(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToLa32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref La16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref La32 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref La16 sourceBase = ref MemoryMarshal.GetReference(source); + ref La32 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref La16 sp = ref Unsafe.Add(ref sourceRef, i); - ref La32 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromLa16(sp); + Unsafe.Add(ref destinationBase, i) = La32.FromLa16(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToRgb24( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref La16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgb24 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref La16 sourceBase = ref MemoryMarshal.GetReference(source); + ref Rgb24 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref La16 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromLa16(sp); + Unsafe.Add(ref destinationBase, i) = Rgb24.FromLa16(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToRgba32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref La16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgba32 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref La16 sourceBase = ref MemoryMarshal.GetReference(source); + ref Rgba32 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref La16 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromLa16(sp); + Unsafe.Add(ref destinationBase, i) = Rgba32.FromLa16(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToRgb48( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref La16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgb48 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref La16 sourceBase = ref MemoryMarshal.GetReference(source); + ref Rgb48 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref La16 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromLa16(sp); + Unsafe.Add(ref destinationBase, i) = Rgb48.FromLa16(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToRgba64( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref La16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgba64 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref La16 sourceBase = ref MemoryMarshal.GetReference(source); + ref Rgba64 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref La16 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromLa16(sp); + Unsafe.Add(ref destinationBase, i) = Rgba64.FromLa16(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToBgra5551( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref La16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Bgra5551 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref La16 sourceBase = ref MemoryMarshal.GetReference(source); + ref Bgra5551 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref La16 sp = ref Unsafe.Add(ref sourceRef, i); - ref Bgra5551 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromLa16(sp); + Unsafe.Add(ref destinationBase, i) = Bgra5551.FromLa16(Unsafe.Add(ref sourceBase, i)); } } /// public override void From( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { - PixelOperations.Instance.ToLa16(configuration, sourcePixels, destinationPixels.Slice(0, sourcePixels.Length)); + PixelOperations.Instance.ToLa16(configuration, source, destination.Slice(0, source.Length)); } } } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/La32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/La32.PixelOperations.Generated.cs index a9ee9d6b78..d949d61e0d 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/La32.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/La32.PixelOperations.Generated.cs @@ -21,282 +21,246 @@ public partial struct La32 internal partial class PixelOperations : PixelOperations { /// - public override void FromLa32(Configuration configuration, ReadOnlySpan source, Span destinationPixels) + public override void FromLa32(Configuration configuration, ReadOnlySpan source, Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(source, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - source.CopyTo(destinationPixels.Slice(0, source.Length)); + source.CopyTo(destination.Slice(0, source.Length)); } /// - public override void ToLa32(Configuration configuration, ReadOnlySpan sourcePixels, Span destinationPixels) + public override void ToLa32(Configuration configuration, ReadOnlySpan source, Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - sourcePixels.CopyTo(destinationPixels.Slice(0, sourcePixels.Length)); + source.CopyTo(destination.Slice(0, source.Length)); } /// public override void ToArgb32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref La32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Argb32 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref La32 sourceBase = ref MemoryMarshal.GetReference(source); + ref Argb32 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref La32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Argb32 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromLa32(sp); + Unsafe.Add(ref destinationBase, i) = Argb32.FromLa32(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToAbgr32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref La32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Abgr32 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref La32 sourceBase = ref MemoryMarshal.GetReference(source); + ref Abgr32 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref La32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Abgr32 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromLa32(sp); + Unsafe.Add(ref destinationBase, i) = Abgr32.FromLa32(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToBgr24( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref La32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Bgr24 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref La32 sourceBase = ref MemoryMarshal.GetReference(source); + ref Bgr24 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref La32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromLa32(sp); + Unsafe.Add(ref destinationBase, i) = Bgr24.FromLa32(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToBgra32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref La32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Bgra32 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref La32 sourceBase = ref MemoryMarshal.GetReference(source); + ref Bgra32 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref La32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromLa32(sp); + Unsafe.Add(ref destinationBase, i) = Bgra32.FromLa32(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToL8( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref La32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref L8 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref La32 sourceBase = ref MemoryMarshal.GetReference(source); + ref L8 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref La32 sp = ref Unsafe.Add(ref sourceRef, i); - ref L8 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromLa32(sp); + Unsafe.Add(ref destinationBase, i) = L8.FromLa32(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToL16( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref La32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref L16 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref La32 sourceBase = ref MemoryMarshal.GetReference(source); + ref L16 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref La32 sp = ref Unsafe.Add(ref sourceRef, i); - ref L16 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromLa32(sp); + Unsafe.Add(ref destinationBase, i) = L16.FromLa32(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToLa16( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref La32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref La16 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref La32 sourceBase = ref MemoryMarshal.GetReference(source); + ref La16 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref La32 sp = ref Unsafe.Add(ref sourceRef, i); - ref La16 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromLa32(sp); + Unsafe.Add(ref destinationBase, i) = La16.FromLa32(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToRgb24( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref La32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgb24 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref La32 sourceBase = ref MemoryMarshal.GetReference(source); + ref Rgb24 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref La32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromLa32(sp); + Unsafe.Add(ref destinationBase, i) = Rgb24.FromLa32(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToRgba32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref La32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgba32 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref La32 sourceBase = ref MemoryMarshal.GetReference(source); + ref Rgba32 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref La32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromLa32(sp); + Unsafe.Add(ref destinationBase, i) = Rgba32.FromLa32(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToRgb48( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref La32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgb48 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref La32 sourceBase = ref MemoryMarshal.GetReference(source); + ref Rgb48 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref La32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromLa32(sp); + Unsafe.Add(ref destinationBase, i) = Rgb48.FromLa32(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToRgba64( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref La32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgba64 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref La32 sourceBase = ref MemoryMarshal.GetReference(source); + ref Rgba64 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref La32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromLa32(sp); + Unsafe.Add(ref destinationBase, i) = Rgba64.FromLa32(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToBgra5551( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref La32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Bgra5551 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref La32 sourceBase = ref MemoryMarshal.GetReference(source); + ref Bgra5551 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref La32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Bgra5551 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromLa32(sp); + Unsafe.Add(ref destinationBase, i) = Bgra5551.FromLa32(Unsafe.Add(ref sourceBase, i)); } } /// public override void From( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { - PixelOperations.Instance.ToLa32(configuration, sourcePixels, destinationPixels.Slice(0, sourcePixels.Length)); + PixelOperations.Instance.ToLa32(configuration, source, destination.Slice(0, source.Length)); } } } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Rgb24.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Rgb24.PixelOperations.Generated.cs index 1d87121e92..fd6465a22f 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Rgb24.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Rgb24.PixelOperations.Generated.cs @@ -21,337 +21,316 @@ public partial struct Rgb24 internal partial class PixelOperations : PixelOperations { /// - public override void FromRgb24(Configuration configuration, ReadOnlySpan source, Span destinationPixels) + public override void FromRgb24(Configuration configuration, ReadOnlySpan source, Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(source, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - source.CopyTo(destinationPixels.Slice(0, source.Length)); + source.CopyTo(destination.Slice(0, source.Length)); } /// - public override void ToRgb24(Configuration configuration, ReadOnlySpan sourcePixels, Span destinationPixels) + public override void ToRgb24(Configuration configuration, ReadOnlySpan source, Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - sourcePixels.CopyTo(destinationPixels.Slice(0, sourcePixels.Length)); + source.CopyTo(destination.Slice(0, source.Length)); } /// public override void FromVector4Destructive( Configuration configuration, Span sourceVectors, - Span destinationPixels, + Span destination, PixelConversionModifiers modifiers) { - Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destinationPixels, modifiers.Remove(PixelConversionModifiers.Scale | PixelConversionModifiers.Premultiply)); + Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destination, modifiers.Remove(PixelConversionModifiers.Scale | PixelConversionModifiers.Premultiply)); } /// public override void ToVector4( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destVectors, + ReadOnlySpan source, + Span destination, PixelConversionModifiers modifiers) { - Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, modifiers.Remove(PixelConversionModifiers.Scale | PixelConversionModifiers.Premultiply)); + Vector4Converters.RgbaCompatible.ToVector4(configuration, this, source, destination, modifiers.Remove(PixelConversionModifiers.Scale | PixelConversionModifiers.Premultiply)); } /// public override void ToRgba32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromRgb24.ToRgba32(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromRgb24.ToRgba32(sourceBytes, destinationBytes); } /// public override void FromRgba32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromRgba32.ToRgb24(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromRgba32.ToRgb24(sourceBytes, destinationBytes); } /// public override void ToArgb32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromRgb24.ToArgb32(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromRgb24.ToArgb32(sourceBytes, destinationBytes); } /// public override void FromArgb32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromArgb32.ToRgb24(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromArgb32.ToRgb24(sourceBytes, destinationBytes); } /// public override void ToAbgr32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromRgb24.ToAbgr32(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromRgb24.ToAbgr32(sourceBytes, destinationBytes); } /// public override void FromAbgr32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromAbgr32.ToRgb24(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromAbgr32.ToRgb24(sourceBytes, destinationBytes); } /// public override void ToBgra32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromRgb24.ToBgra32(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromRgb24.ToBgra32(sourceBytes, destinationBytes); } /// public override void FromBgra32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromBgra32.ToRgb24(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromBgra32.ToRgb24(sourceBytes, destinationBytes); } /// public override void ToBgr24( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromRgb24.ToBgr24(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromRgb24.ToBgr24(sourceBytes, destinationBytes); } /// public override void FromBgr24( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromBgr24.ToRgb24(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromBgr24.ToRgb24(sourceBytes, destinationBytes); } /// public override void ToL8( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref L8 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Rgb24 sourceBase = ref MemoryMarshal.GetReference(source); + ref L8 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); - ref L8 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromRgb24(sp); + Unsafe.Add(ref destinationBase, i) = L8.FromRgb24(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToL16( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref L16 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Rgb24 sourceBase = ref MemoryMarshal.GetReference(source); + ref L16 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); - ref L16 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromRgb24(sp); + Unsafe.Add(ref destinationBase, i) = L16.FromRgb24(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToLa16( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref La16 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Rgb24 sourceBase = ref MemoryMarshal.GetReference(source); + ref La16 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); - ref La16 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromRgb24(sp); + Unsafe.Add(ref destinationBase, i) = La16.FromRgb24(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToLa32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref La32 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Rgb24 sourceBase = ref MemoryMarshal.GetReference(source); + ref La32 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); - ref La32 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromRgb24(sp); + Unsafe.Add(ref destinationBase, i) = La32.FromRgb24(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToRgb48( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgb48 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Rgb24 sourceBase = ref MemoryMarshal.GetReference(source); + ref Rgb48 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromRgb24(sp); + Unsafe.Add(ref destinationBase, i) = Rgb48.FromRgb24(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToRgba64( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgba64 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Rgb24 sourceBase = ref MemoryMarshal.GetReference(source); + ref Rgba64 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromRgb24(sp); + Unsafe.Add(ref destinationBase, i) = Rgba64.FromRgb24(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToBgra5551( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Bgra5551 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Rgb24 sourceBase = ref MemoryMarshal.GetReference(source); + ref Bgra5551 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); - ref Bgra5551 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromRgb24(sp); + Unsafe.Add(ref destinationBase, i) = Bgra5551.FromRgb24(Unsafe.Add(ref sourceBase, i)); } } /// public override void From( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { - PixelOperations.Instance.ToRgb24(configuration, sourcePixels, destinationPixels.Slice(0, sourcePixels.Length)); + PixelOperations.Instance.ToRgb24(configuration, source, destination.Slice(0, source.Length)); } } } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Rgb48.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Rgb48.PixelOperations.Generated.cs index 60cfdad4b6..69e06da219 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Rgb48.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Rgb48.PixelOperations.Generated.cs @@ -21,282 +21,246 @@ public partial struct Rgb48 internal partial class PixelOperations : PixelOperations { /// - public override void FromRgb48(Configuration configuration, ReadOnlySpan source, Span destinationPixels) + public override void FromRgb48(Configuration configuration, ReadOnlySpan source, Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(source, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - source.CopyTo(destinationPixels.Slice(0, source.Length)); + source.CopyTo(destination.Slice(0, source.Length)); } /// - public override void ToRgb48(Configuration configuration, ReadOnlySpan sourcePixels, Span destinationPixels) + public override void ToRgb48(Configuration configuration, ReadOnlySpan source, Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - sourcePixels.CopyTo(destinationPixels.Slice(0, sourcePixels.Length)); + source.CopyTo(destination.Slice(0, source.Length)); } /// public override void ToArgb32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Argb32 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Rgb48 sourceBase = ref MemoryMarshal.GetReference(source); + ref Argb32 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); - ref Argb32 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromRgb48(sp); + Unsafe.Add(ref destinationBase, i) = Argb32.FromRgb48(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToAbgr32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Abgr32 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Rgb48 sourceBase = ref MemoryMarshal.GetReference(source); + ref Abgr32 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); - ref Abgr32 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromRgb48(sp); + Unsafe.Add(ref destinationBase, i) = Abgr32.FromRgb48(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToBgr24( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Bgr24 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Rgb48 sourceBase = ref MemoryMarshal.GetReference(source); + ref Bgr24 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); - ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromRgb48(sp); + Unsafe.Add(ref destinationBase, i) = Bgr24.FromRgb48(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToBgra32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Bgra32 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Rgb48 sourceBase = ref MemoryMarshal.GetReference(source); + ref Bgra32 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); - ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromRgb48(sp); + Unsafe.Add(ref destinationBase, i) = Bgra32.FromRgb48(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToL8( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref L8 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Rgb48 sourceBase = ref MemoryMarshal.GetReference(source); + ref L8 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); - ref L8 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromRgb48(sp); + Unsafe.Add(ref destinationBase, i) = L8.FromRgb48(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToL16( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref L16 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Rgb48 sourceBase = ref MemoryMarshal.GetReference(source); + ref L16 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); - ref L16 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromRgb48(sp); + Unsafe.Add(ref destinationBase, i) = L16.FromRgb48(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToLa16( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref La16 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Rgb48 sourceBase = ref MemoryMarshal.GetReference(source); + ref La16 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); - ref La16 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromRgb48(sp); + Unsafe.Add(ref destinationBase, i) = La16.FromRgb48(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToLa32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref La32 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Rgb48 sourceBase = ref MemoryMarshal.GetReference(source); + ref La32 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); - ref La32 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromRgb48(sp); + Unsafe.Add(ref destinationBase, i) = La32.FromRgb48(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToRgb24( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgb24 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Rgb48 sourceBase = ref MemoryMarshal.GetReference(source); + ref Rgb24 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromRgb48(sp); + Unsafe.Add(ref destinationBase, i) = Rgb24.FromRgb48(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToRgba32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgba32 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Rgb48 sourceBase = ref MemoryMarshal.GetReference(source); + ref Rgba32 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromRgb48(sp); + Unsafe.Add(ref destinationBase, i) = Rgba32.FromRgb48(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToRgba64( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgba64 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Rgb48 sourceBase = ref MemoryMarshal.GetReference(source); + ref Rgba64 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromRgb48(sp); + Unsafe.Add(ref destinationBase, i) = Rgba64.FromRgb48(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToBgra5551( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Bgra5551 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Rgb48 sourceBase = ref MemoryMarshal.GetReference(source); + ref Bgra5551 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); - ref Bgra5551 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromRgb48(sp); + Unsafe.Add(ref destinationBase, i) = Bgra5551.FromRgb48(Unsafe.Add(ref sourceBase, i)); } } /// public override void From( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { - PixelOperations.Instance.ToRgb48(configuration, sourcePixels, destinationPixels.Slice(0, sourcePixels.Length)); + PixelOperations.Instance.ToRgb48(configuration, source, destination.Slice(0, source.Length)); } } } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Rgba32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Rgba32.PixelOperations.Generated.cs index da7c9a6c91..8a98521f0b 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Rgba32.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Rgba32.PixelOperations.Generated.cs @@ -21,317 +21,296 @@ public partial struct Rgba32 internal partial class PixelOperations : PixelOperations { /// - public override void FromRgba32(Configuration configuration, ReadOnlySpan source, Span destinationPixels) + public override void FromRgba32(Configuration configuration, ReadOnlySpan source, Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(source, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - source.CopyTo(destinationPixels.Slice(0, source.Length)); + source.CopyTo(destination.Slice(0, source.Length)); } /// - public override void ToRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destinationPixels) + public override void ToRgba32(Configuration configuration, ReadOnlySpan source, Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - sourcePixels.CopyTo(destinationPixels.Slice(0, sourcePixels.Length)); + source.CopyTo(destination.Slice(0, source.Length)); } /// public override void ToArgb32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromRgba32.ToArgb32(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromRgba32.ToArgb32(sourceBytes, destinationBytes); } /// public override void FromArgb32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromArgb32.ToRgba32(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromArgb32.ToRgba32(sourceBytes, destinationBytes); } /// public override void ToAbgr32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromRgba32.ToAbgr32(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromRgba32.ToAbgr32(sourceBytes, destinationBytes); } /// public override void FromAbgr32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromAbgr32.ToRgba32(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromAbgr32.ToRgba32(sourceBytes, destinationBytes); } /// public override void ToBgra32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromRgba32.ToBgra32(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromRgba32.ToBgra32(sourceBytes, destinationBytes); } /// public override void FromBgra32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromBgra32.ToRgba32(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromBgra32.ToRgba32(sourceBytes, destinationBytes); } /// public override void ToRgb24( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromRgba32.ToRgb24(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromRgba32.ToRgb24(sourceBytes, destinationBytes); } /// public override void FromRgb24( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromRgb24.ToRgba32(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromRgb24.ToRgba32(sourceBytes, destinationBytes); } /// public override void ToBgr24( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromRgba32.ToBgr24(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromRgba32.ToBgr24(sourceBytes, destinationBytes); } /// public override void FromBgr24( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromBgr24.ToRgba32(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromBgr24.ToRgba32(sourceBytes, destinationBytes); } /// public override void ToL8( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref L8 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Rgba32 sourceBase = ref MemoryMarshal.GetReference(source); + ref L8 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); - ref L8 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromRgba32(sp); + Unsafe.Add(ref destinationBase, i) = L8.FromRgba32(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToL16( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref L16 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Rgba32 sourceBase = ref MemoryMarshal.GetReference(source); + ref L16 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); - ref L16 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromRgba32(sp); + Unsafe.Add(ref destinationBase, i) = L16.FromRgba32(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToLa16( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref La16 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Rgba32 sourceBase = ref MemoryMarshal.GetReference(source); + ref La16 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); - ref La16 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromRgba32(sp); + Unsafe.Add(ref destinationBase, i) = La16.FromRgba32(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToLa32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref La32 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Rgba32 sourceBase = ref MemoryMarshal.GetReference(source); + ref La32 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); - ref La32 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromRgba32(sp); + Unsafe.Add(ref destinationBase, i) = La32.FromRgba32(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToRgb48( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgb48 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Rgba32 sourceBase = ref MemoryMarshal.GetReference(source); + ref Rgb48 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromRgba32(sp); + Unsafe.Add(ref destinationBase, i) = Rgb48.FromRgba32(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToRgba64( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgba64 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Rgba32 sourceBase = ref MemoryMarshal.GetReference(source); + ref Rgba64 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromRgba32(sp); + Unsafe.Add(ref destinationBase, i) = Rgba64.FromRgba32(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToBgra5551( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Bgra5551 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Rgba32 sourceBase = ref MemoryMarshal.GetReference(source); + ref Bgra5551 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Bgra5551 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromRgba32(sp); + Unsafe.Add(ref destinationBase, i) = Bgra5551.FromRgba32(Unsafe.Add(ref sourceBase, i)); } } /// public override void From( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { - PixelOperations.Instance.ToRgba32(configuration, sourcePixels, destinationPixels.Slice(0, sourcePixels.Length)); + PixelOperations.Instance.ToRgba32(configuration, source, destination.Slice(0, source.Length)); } } } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Rgba64.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Rgba64.PixelOperations.Generated.cs index b6236f8a66..4679e950e5 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Rgba64.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Rgba64.PixelOperations.Generated.cs @@ -21,282 +21,246 @@ public partial struct Rgba64 internal partial class PixelOperations : PixelOperations { /// - public override void FromRgba64(Configuration configuration, ReadOnlySpan source, Span destinationPixels) + public override void FromRgba64(Configuration configuration, ReadOnlySpan source, Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(source, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - source.CopyTo(destinationPixels.Slice(0, source.Length)); + source.CopyTo(destination.Slice(0, source.Length)); } /// - public override void ToRgba64(Configuration configuration, ReadOnlySpan sourcePixels, Span destinationPixels) + public override void ToRgba64(Configuration configuration, ReadOnlySpan source, Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - sourcePixels.CopyTo(destinationPixels.Slice(0, sourcePixels.Length)); + source.CopyTo(destination.Slice(0, source.Length)); } /// public override void ToArgb32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Argb32 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Rgba64 sourceBase = ref MemoryMarshal.GetReference(source); + ref Argb32 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); - ref Argb32 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromRgba64(sp); + Unsafe.Add(ref destinationBase, i) = Argb32.FromRgba64(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToAbgr32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Abgr32 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Rgba64 sourceBase = ref MemoryMarshal.GetReference(source); + ref Abgr32 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); - ref Abgr32 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromRgba64(sp); + Unsafe.Add(ref destinationBase, i) = Abgr32.FromRgba64(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToBgr24( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Bgr24 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Rgba64 sourceBase = ref MemoryMarshal.GetReference(source); + ref Bgr24 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); - ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromRgba64(sp); + Unsafe.Add(ref destinationBase, i) = Bgr24.FromRgba64(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToBgra32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Bgra32 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Rgba64 sourceBase = ref MemoryMarshal.GetReference(source); + ref Bgra32 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); - ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromRgba64(sp); + Unsafe.Add(ref destinationBase, i) = Bgra32.FromRgba64(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToL8( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref L8 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Rgba64 sourceBase = ref MemoryMarshal.GetReference(source); + ref L8 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); - ref L8 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromRgba64(sp); + Unsafe.Add(ref destinationBase, i) = L8.FromRgba64(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToL16( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref L16 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Rgba64 sourceBase = ref MemoryMarshal.GetReference(source); + ref L16 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); - ref L16 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromRgba64(sp); + Unsafe.Add(ref destinationBase, i) = L16.FromRgba64(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToLa16( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref La16 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Rgba64 sourceBase = ref MemoryMarshal.GetReference(source); + ref La16 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); - ref La16 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromRgba64(sp); + Unsafe.Add(ref destinationBase, i) = La16.FromRgba64(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToLa32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref La32 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Rgba64 sourceBase = ref MemoryMarshal.GetReference(source); + ref La32 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); - ref La32 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromRgba64(sp); + Unsafe.Add(ref destinationBase, i) = La32.FromRgba64(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToRgb24( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgb24 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Rgba64 sourceBase = ref MemoryMarshal.GetReference(source); + ref Rgb24 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromRgba64(sp); + Unsafe.Add(ref destinationBase, i) = Rgb24.FromRgba64(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToRgba32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgba32 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Rgba64 sourceBase = ref MemoryMarshal.GetReference(source); + ref Rgba32 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromRgba64(sp); + Unsafe.Add(ref destinationBase, i) = Rgba32.FromRgba64(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToRgb48( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgb48 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Rgba64 sourceBase = ref MemoryMarshal.GetReference(source); + ref Rgb48 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromRgba64(sp); + Unsafe.Add(ref destinationBase, i) = Rgb48.FromRgba64(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToBgra5551( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Bgra5551 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Rgba64 sourceBase = ref MemoryMarshal.GetReference(source); + ref Bgra5551 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); - ref Bgra5551 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromRgba64(sp); + Unsafe.Add(ref destinationBase, i) = Bgra5551.FromRgba64(Unsafe.Add(ref sourceBase, i)); } } /// public override void From( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { - PixelOperations.Instance.ToRgba64(configuration, sourcePixels, destinationPixels.Slice(0, sourcePixels.Length)); + PixelOperations.Instance.ToRgba64(configuration, source, destination.Slice(0, source.Length)); } } } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/_Common.ttinclude b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/_Common.ttinclude index f7e178d7f2..c4d5a6b95d 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/_Common.ttinclude +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/_Common.ttinclude @@ -57,10 +57,10 @@ using SixLabors.ImageSharp.PixelFormats.Utils; /// public override void From( Configuration configuration, - ReadOnlySpan sourcePixels, - Span<<#=pixelType#>> destinationPixels) + ReadOnlySpan source, + Span<<#=pixelType#>> destination) { - PixelOperations.Instance.To<#=pixelType#>(configuration, sourcePixels, destinationPixels.Slice(0, sourcePixels.Length)); + PixelOperations.Instance.To<#=pixelType#>(configuration, source, destination.Slice(0, source.Length)); } <#+ } @@ -68,21 +68,21 @@ using SixLabors.ImageSharp.PixelFormats.Utils; void GenerateDefaultSelfConversionMethods(string pixelType) { #>/// - public override void From<#=pixelType#>(Configuration configuration, ReadOnlySpan<<#=pixelType#>> source, Span<<#=pixelType#>> destinationPixels) + public override void From<#=pixelType#>(Configuration configuration, ReadOnlySpan<<#=pixelType#>> source, Span<<#=pixelType#>> destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(source, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - source.CopyTo(destinationPixels.Slice(0, source.Length)); + source.CopyTo(destination.Slice(0, source.Length)); } /// - public override void To<#=pixelType#>(Configuration configuration, ReadOnlySpan<<#=pixelType#>> sourcePixels, Span<<#=pixelType#>> destinationPixels) + public override void To<#=pixelType#>(Configuration configuration, ReadOnlySpan<<#=pixelType#>> source, Span<<#=pixelType#>> destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - sourcePixels.CopyTo(destinationPixels.Slice(0, sourcePixels.Length)); + source.CopyTo(destination.Slice(0, source.Length)); } <#+ } @@ -94,21 +94,18 @@ using SixLabors.ImageSharp.PixelFormats.Utils; /// public override void To<#=toPixelType#>( Configuration configuration, - ReadOnlySpan<<#=fromPixelType#>> sourcePixels, - Span<<#=toPixelType#>> destinationPixels) + ReadOnlySpan<<#=fromPixelType#>> source, + Span<<#=toPixelType#>> destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref <#=fromPixelType#> sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref <#=toPixelType#> destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref <#=fromPixelType#> sourceBase = ref MemoryMarshal.GetReference(source); + ref <#=toPixelType#> destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref <#=fromPixelType#> sp = ref Unsafe.Add(ref sourceRef, i); - ref <#=toPixelType#> dp = ref Unsafe.Add(ref destRef, i); - - dp.From<#=fromPixelType#>(sp); + Unsafe.Add(ref destinationBase, i) = <#=toPixelType#>.From<#=fromPixelType#>(Unsafe.Add(ref sourceBase, i)); } } <#+ @@ -121,29 +118,29 @@ using SixLabors.ImageSharp.PixelFormats.Utils; /// public override void To<#=otherPixelType#>( Configuration configuration, - ReadOnlySpan<<#=thisPixelType#>> sourcePixels, - Span<<#=otherPixelType#>> destinationPixels) + ReadOnlySpan<<#=thisPixelType#>> source, + Span<<#=otherPixelType#>> destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast<<#=thisPixelType#>, byte>(sourcePixels); - Span dest = MemoryMarshal.Cast<<#=otherPixelType#>, byte>(destinationPixels); - PixelConverter.From<#=thisPixelType#>.To<#=otherPixelType#>(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast<<#=thisPixelType#>, byte>(source); + Span destinationBytes = MemoryMarshal.Cast<<#=otherPixelType#>, byte>(destination); + PixelConverter.From<#=thisPixelType#>.To<#=otherPixelType#>(sourceBytes, destinationBytes); } /// public override void From<#=otherPixelType#>( Configuration configuration, - ReadOnlySpan<<#=otherPixelType#>> sourcePixels, - Span<<#=thisPixelType#>> destinationPixels) + ReadOnlySpan<<#=otherPixelType#>> source, + Span<<#=thisPixelType#>> destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast<<#=otherPixelType#>, byte>(sourcePixels); - Span dest = MemoryMarshal.Cast<<#=thisPixelType#>, byte>(destinationPixels); - PixelConverter.From<#=otherPixelType#>.To<#=thisPixelType#>(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast<<#=otherPixelType#>, byte>(source); + Span destinationBytes = MemoryMarshal.Cast<<#=thisPixelType#>, byte>(destination); + PixelConverter.From<#=otherPixelType#>.To<#=thisPixelType#>(sourceBytes, destinationBytes); } <#+ } @@ -161,20 +158,20 @@ using SixLabors.ImageSharp.PixelFormats.Utils; public override void FromVector4Destructive( Configuration configuration, Span sourceVectors, - Span<<#=pixelType#>> destinationPixels, + Span<<#=pixelType#>> destination, PixelConversionModifiers modifiers) { - Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destinationPixels, modifiers.Remove(<#=removeTheseModifiers#>)); + Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destination, modifiers.Remove(<#=removeTheseModifiers#>)); } /// public override void ToVector4( Configuration configuration, - ReadOnlySpan<<#=pixelType#>> sourcePixels, - Span destVectors, + ReadOnlySpan<<#=pixelType#>> source, + Span destination, PixelConversionModifiers modifiers) { - Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, modifiers.Remove(<#=removeTheseModifiers#>)); + Vector4Converters.RgbaCompatible.ToVector4(configuration, this, source, destination, modifiers.Remove(<#=removeTheseModifiers#>)); } <#+ } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/HalfSingle.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/HalfSingle.PixelOperations.cs index c8c4110c73..770f3a1de8 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/HalfSingle.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/HalfSingle.PixelOperations.cs @@ -1,8 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.Formats; - namespace SixLabors.ImageSharp.PixelFormats; /// @@ -13,12 +11,5 @@ public partial struct HalfSingle /// /// Provides optimized overrides for bulk operations. /// - internal class PixelOperations : PixelOperations - { - private static readonly Lazy LazyInfo = - new Lazy(() => PixelTypeInfo.Create(PixelAlphaRepresentation.None), true); - - /// - public override PixelTypeInfo GetPixelTypeInfo() => LazyInfo.Value; - } + internal class PixelOperations : PixelOperations; } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/HalfVector2.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/HalfVector2.PixelOperations.cs index bdf58145fd..160ab9bd0f 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/HalfVector2.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/HalfVector2.PixelOperations.cs @@ -1,8 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.Formats; - namespace SixLabors.ImageSharp.PixelFormats; /// @@ -13,12 +11,5 @@ public partial struct HalfVector2 /// /// Provides optimized overrides for bulk operations. /// - internal class PixelOperations : PixelOperations - { - private static readonly Lazy LazyInfo = - new Lazy(() => PixelTypeInfo.Create(PixelAlphaRepresentation.None), true); - - /// - public override PixelTypeInfo GetPixelTypeInfo() => LazyInfo.Value; - } + internal class PixelOperations : PixelOperations; } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/HalfVector4.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/HalfVector4.PixelOperations.cs index c3fe598045..703138454e 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/HalfVector4.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/HalfVector4.PixelOperations.cs @@ -1,8 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.Formats; - namespace SixLabors.ImageSharp.PixelFormats; /// @@ -13,12 +11,5 @@ public partial struct HalfVector4 /// /// Provides optimized overrides for bulk operations. /// - internal class PixelOperations : PixelOperations - { - private static readonly Lazy LazyInfo = - new Lazy(() => PixelTypeInfo.Create(PixelAlphaRepresentation.Unassociated), true); - - /// - public override PixelTypeInfo GetPixelTypeInfo() => LazyInfo.Value; - } + internal class PixelOperations : PixelOperations; } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/L16.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/L16.PixelOperations.cs index 7495cee53d..c9714c2170 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/L16.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/L16.PixelOperations.cs @@ -1,8 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.Formats; - namespace SixLabors.ImageSharp.PixelFormats; /// @@ -13,12 +11,5 @@ public partial struct L16 /// /// Provides optimized overrides for bulk operations. /// - internal partial class PixelOperations : PixelOperations - { - private static readonly Lazy LazyInfo = - new Lazy(() => PixelTypeInfo.Create(PixelAlphaRepresentation.None), true); - - /// - public override PixelTypeInfo GetPixelTypeInfo() => LazyInfo.Value; - } + internal partial class PixelOperations : PixelOperations; } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/L8.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/L8.PixelOperations.cs index 5dd98c3a66..e7b463fe08 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/L8.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/L8.PixelOperations.cs @@ -1,8 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.Formats; - namespace SixLabors.ImageSharp.PixelFormats; /// @@ -13,12 +11,5 @@ public partial struct L8 /// /// Provides optimized overrides for bulk operations. /// - internal partial class PixelOperations : PixelOperations - { - private static readonly Lazy LazyInfo = - new Lazy(() => PixelTypeInfo.Create(PixelAlphaRepresentation.None), true); - - /// - public override PixelTypeInfo GetPixelTypeInfo() => LazyInfo.Value; - } + internal partial class PixelOperations : PixelOperations; } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/La16.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/La16.PixelOperations.cs index d9bda3e0fc..316c965650 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/La16.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/La16.PixelOperations.cs @@ -1,8 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.Formats; - namespace SixLabors.ImageSharp.PixelFormats; /// @@ -13,12 +11,5 @@ public partial struct La16 /// /// Provides optimized overrides for bulk operations. /// - internal partial class PixelOperations : PixelOperations - { - private static readonly Lazy LazyInfo = - new Lazy(() => PixelTypeInfo.Create(PixelAlphaRepresentation.Unassociated), true); - - /// - public override PixelTypeInfo GetPixelTypeInfo() => LazyInfo.Value; - } + internal partial class PixelOperations : PixelOperations; } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/La32.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/La32.PixelOperations.cs index 1fb5adfc8f..34a8655338 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/La32.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/La32.PixelOperations.cs @@ -1,8 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.Formats; - namespace SixLabors.ImageSharp.PixelFormats; /// @@ -13,12 +11,5 @@ public partial struct La32 /// /// Provides optimized overrides for bulk operations. /// - internal partial class PixelOperations : PixelOperations - { - private static readonly Lazy LazyInfo = - new Lazy(() => PixelTypeInfo.Create(PixelAlphaRepresentation.Unassociated), true); - - /// - public override PixelTypeInfo GetPixelTypeInfo() => LazyInfo.Value; - } + internal partial class PixelOperations : PixelOperations; } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/NormalizedByte2.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/NormalizedByte2.PixelOperations.cs index 7176295869..36f4a0bf55 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/NormalizedByte2.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/NormalizedByte2.PixelOperations.cs @@ -1,8 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.Formats; - namespace SixLabors.ImageSharp.PixelFormats; /// @@ -13,12 +11,5 @@ public partial struct NormalizedByte2 /// /// Provides optimized overrides for bulk operations. /// - internal class PixelOperations : PixelOperations - { - private static readonly Lazy LazyInfo = - new Lazy(() => PixelTypeInfo.Create(PixelAlphaRepresentation.None), true); - - /// - public override PixelTypeInfo GetPixelTypeInfo() => LazyInfo.Value; - } + internal class PixelOperations : PixelOperations; } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/NormalizedByte4.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/NormalizedByte4.PixelOperations.cs index 9bb48f5924..e67321e4f4 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/NormalizedByte4.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/NormalizedByte4.PixelOperations.cs @@ -1,8 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.Formats; - namespace SixLabors.ImageSharp.PixelFormats; /// @@ -13,12 +11,5 @@ public partial struct NormalizedByte4 /// /// Provides optimized overrides for bulk operations. /// - internal class PixelOperations : PixelOperations - { - private static readonly Lazy LazyInfo = - new Lazy(() => PixelTypeInfo.Create(PixelAlphaRepresentation.Unassociated), true); - - /// - public override PixelTypeInfo GetPixelTypeInfo() => LazyInfo.Value; - } + internal class PixelOperations : PixelOperations; } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/NormalizedShort2.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/NormalizedShort2.PixelOperations.cs index 3913f64bb5..99636cb376 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/NormalizedShort2.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/NormalizedShort2.PixelOperations.cs @@ -1,8 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.Formats; - namespace SixLabors.ImageSharp.PixelFormats; /// @@ -13,12 +11,5 @@ public partial struct NormalizedShort2 /// /// Provides optimized overrides for bulk operations. /// - internal class PixelOperations : PixelOperations - { - private static readonly Lazy LazyInfo = - new Lazy(() => PixelTypeInfo.Create(PixelAlphaRepresentation.None), true); - - /// - public override PixelTypeInfo GetPixelTypeInfo() => LazyInfo.Value; - } + internal class PixelOperations : PixelOperations; } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/NormalizedShort4.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/NormalizedShort4.PixelOperations.cs index 6334f4e7e4..ad6aa8d8a8 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/NormalizedShort4.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/NormalizedShort4.PixelOperations.cs @@ -1,8 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.Formats; - namespace SixLabors.ImageSharp.PixelFormats; /// @@ -13,12 +11,5 @@ public partial struct NormalizedShort4 /// /// Provides optimized overrides for bulk operations. /// - internal class PixelOperations : PixelOperations - { - private static readonly Lazy LazyInfo = - new Lazy(() => PixelTypeInfo.Create(PixelAlphaRepresentation.Unassociated), true); - - /// - public override PixelTypeInfo GetPixelTypeInfo() => LazyInfo.Value; - } + internal class PixelOperations : PixelOperations; } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rg32.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rg32.PixelOperations.cs index a5b803f768..7bca1c781e 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rg32.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rg32.PixelOperations.cs @@ -1,8 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.Formats; - namespace SixLabors.ImageSharp.PixelFormats; /// @@ -13,12 +11,5 @@ public partial struct Rg32 /// /// Provides optimized overrides for bulk operations. /// - internal class PixelOperations : PixelOperations - { - private static readonly Lazy LazyInfo = - new Lazy(() => PixelTypeInfo.Create(PixelAlphaRepresentation.None), true); - - /// - public override PixelTypeInfo GetPixelTypeInfo() => LazyInfo.Value; - } + internal class PixelOperations : PixelOperations; } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rgb24.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rgb24.PixelOperations.cs index 5473a602f9..435a8c0779 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rgb24.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rgb24.PixelOperations.cs @@ -1,8 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.Formats; - namespace SixLabors.ImageSharp.PixelFormats; /// @@ -15,12 +13,6 @@ public partial struct Rgb24 /// internal partial class PixelOperations : PixelOperations { - private static readonly Lazy LazyInfo = - new(() => PixelTypeInfo.Create(PixelAlphaRepresentation.None), true); - - /// - public override PixelTypeInfo GetPixelTypeInfo() => LazyInfo.Value; - /// internal override void PackFromRgbPlanes( ReadOnlySpan redChannel, diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rgb48.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rgb48.PixelOperations.cs index 56a052a7dd..c9ed730c47 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rgb48.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rgb48.PixelOperations.cs @@ -1,8 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.Formats; - namespace SixLabors.ImageSharp.PixelFormats; /// @@ -13,12 +11,5 @@ public partial struct Rgb48 /// /// Provides optimized overrides for bulk operations. /// - internal partial class PixelOperations : PixelOperations - { - private static readonly Lazy LazyInfo = - new Lazy(() => PixelTypeInfo.Create(PixelAlphaRepresentation.None), true); - - /// - public override PixelTypeInfo GetPixelTypeInfo() => LazyInfo.Value; - } + internal partial class PixelOperations : PixelOperations; } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rgba1010102.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rgba1010102.PixelOperations.cs index f550396275..8dcbb319f9 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rgba1010102.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rgba1010102.PixelOperations.cs @@ -1,8 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.Formats; - namespace SixLabors.ImageSharp.PixelFormats; /// @@ -13,12 +11,5 @@ public partial struct Rgba1010102 /// /// Provides optimized overrides for bulk operations. /// - internal class PixelOperations : PixelOperations - { - private static readonly Lazy LazyInfo = - new Lazy(() => PixelTypeInfo.Create(PixelAlphaRepresentation.Unassociated), true); - - /// - public override PixelTypeInfo GetPixelTypeInfo() => LazyInfo.Value; - } + internal class PixelOperations : PixelOperations; } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rgba32.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rgba32.PixelOperations.cs index a4887b393c..065e34c336 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rgba32.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rgba32.PixelOperations.cs @@ -3,7 +3,6 @@ using System.Numerics; using System.Runtime.InteropServices; -using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.PixelFormats.Utils; namespace SixLabors.ImageSharp.PixelFormats; @@ -18,24 +17,18 @@ public partial struct Rgba32 /// internal partial class PixelOperations : PixelOperations { - private static readonly Lazy LazyInfo = - new(() => PixelTypeInfo.Create(PixelAlphaRepresentation.Unassociated), true); - - /// - public override PixelTypeInfo GetPixelTypeInfo() => LazyInfo.Value; - /// public override void ToVector4( Configuration configuration, - ReadOnlySpan sourcePixels, + ReadOnlySpan source, Span destinationVectors, PixelConversionModifiers modifiers) { - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationVectors, nameof(destinationVectors)); + Guard.DestinationShouldNotBeTooShort(source, destinationVectors, nameof(destinationVectors)); - destinationVectors = destinationVectors[..sourcePixels.Length]; + destinationVectors = destinationVectors[..source.Length]; SimdUtils.ByteToNormalizedFloat( - MemoryMarshal.Cast(sourcePixels), + MemoryMarshal.Cast(source), MemoryMarshal.Cast(destinationVectors)); Vector4Converters.ApplyForwardConversionModifiers(destinationVectors, modifiers); } @@ -44,16 +37,16 @@ public override void ToVector4( public override void FromVector4Destructive( Configuration configuration, Span sourceVectors, - Span destinationPixels, + Span destination, PixelConversionModifiers modifiers) { - Guard.DestinationShouldNotBeTooShort(sourceVectors, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(sourceVectors, destination, nameof(destination)); - destinationPixels = destinationPixels[..sourceVectors.Length]; + destination = destination[..sourceVectors.Length]; Vector4Converters.ApplyBackwardConversionModifiers(sourceVectors, modifiers); SimdUtils.NormalizedFloatToByteSaturate( MemoryMarshal.Cast(sourceVectors), - MemoryMarshal.Cast(destinationPixels)); + MemoryMarshal.Cast(destination)); } /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rgba64.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rgba64.PixelOperations.cs index 56bbc6b25b..6b362d44ec 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rgba64.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rgba64.PixelOperations.cs @@ -1,8 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.Formats; - namespace SixLabors.ImageSharp.PixelFormats; /// @@ -13,12 +11,5 @@ public partial struct Rgba64 /// /// Provides optimized overrides for bulk operations. /// - internal partial class PixelOperations : PixelOperations - { - private static readonly Lazy LazyInfo = - new Lazy(() => PixelTypeInfo.Create(PixelAlphaRepresentation.Unassociated), true); - - /// - public override PixelTypeInfo GetPixelTypeInfo() => LazyInfo.Value; - } + internal partial class PixelOperations : PixelOperations; } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/RgbaVector.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/RgbaVector.PixelOperations.cs index a3833583fc..5f9b51af90 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/RgbaVector.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/RgbaVector.PixelOperations.cs @@ -2,9 +2,7 @@ // Licensed under the Six Labors Split License. using System.Numerics; -using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.PixelFormats.Utils; namespace SixLabors.ImageSharp.PixelFormats; @@ -19,12 +17,6 @@ public partial struct RgbaVector /// internal class PixelOperations : PixelOperations { - private static readonly Lazy LazyInfo = - new(() => PixelTypeInfo.Create(PixelAlphaRepresentation.Unassociated), true); - - /// - public override PixelTypeInfo GetPixelTypeInfo() => LazyInfo.Value; - /// public override void From( Configuration configuration, @@ -61,43 +53,5 @@ public override void ToVector4( MemoryMarshal.Cast(sourcePixels).CopyTo(destinationVectors); Vector4Converters.ApplyForwardConversionModifiers(destinationVectors, modifiers); } - - public override void ToL8( - Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) - { - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); - - ref Vector4 sourceBaseRef = ref Unsafe.As(ref MemoryMarshal.GetReference(sourcePixels)); - ref L8 destBaseRef = ref MemoryMarshal.GetReference(destinationPixels); - - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) - { - ref Vector4 sp = ref Unsafe.Add(ref sourceBaseRef, i); - ref L8 dp = ref Unsafe.Add(ref destBaseRef, i); - - dp.ConvertFromRgbaScaledVector4(sp); - } - } - - public override void ToL16( - Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) - { - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); - - ref Vector4 sourceBaseRef = ref Unsafe.As(ref MemoryMarshal.GetReference(sourcePixels)); - ref L16 destBaseRef = ref MemoryMarshal.GetReference(destinationPixels); - - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) - { - ref Vector4 sp = ref Unsafe.Add(ref sourceBaseRef, i); - ref L16 dp = ref Unsafe.Add(ref destBaseRef, i); - - dp.ConvertFromRgbaScaledVector4(sp); - } - } } } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Short2.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Short2.PixelOperations.cs index 435a521ba7..d8225f18aa 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Short2.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Short2.PixelOperations.cs @@ -1,8 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.Formats; - namespace SixLabors.ImageSharp.PixelFormats; /// @@ -13,12 +11,5 @@ public partial struct Short2 /// /// Provides optimized overrides for bulk operations. /// - internal class PixelOperations : PixelOperations - { - private static readonly Lazy LazyInfo = - new Lazy(() => PixelTypeInfo.Create(PixelAlphaRepresentation.None), true); - - /// - public override PixelTypeInfo GetPixelTypeInfo() => LazyInfo.Value; - } + internal class PixelOperations : PixelOperations; } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Short4.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Short4.PixelOperations.cs index 546da9c57d..3d7043b0c8 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Short4.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Short4.PixelOperations.cs @@ -1,8 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.Formats; - namespace SixLabors.ImageSharp.PixelFormats; /// @@ -13,12 +11,5 @@ public partial struct Short4 /// /// Provides optimized overrides for bulk operations. /// - internal class PixelOperations : PixelOperations - { - private static readonly Lazy LazyInfo = - new Lazy(() => PixelTypeInfo.Create(PixelAlphaRepresentation.Unassociated), true); - - /// - public override PixelTypeInfo GetPixelTypeInfo() => LazyInfo.Value; - } + internal class PixelOperations : PixelOperations; } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rg32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rg32.cs index 0a13a15eda..e7c97269e1 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rg32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rg32.cs @@ -43,7 +43,7 @@ public Rg32(float x, float y) /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Rg32 left, Rg32 right) => left.Equals(right); /// @@ -54,115 +54,121 @@ public Rg32(float x, float y) /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Rg32 left, Rg32 right) => !left.Equals(right); /// - public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Rgba32 ToRgba32() + => new( + ColorNumerics.From16BitTo8Bit((ushort)(this.PackedValue & 0xFFFF)), + ColorNumerics.From16BitTo8Bit((ushort)(this.PackedValue >> 16)), + byte.MinValue, + byte.MaxValue); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector); - - /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Vector4 ToScaledVector4() => this.ToVector4(); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromVector4(Vector4 vector) - { - var vector2 = new Vector2(vector.X, vector.Y); - this.PackedValue = Pack(vector2); - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Vector4 ToVector4() => new(this.ToVector2(), 0f, 1f); + + /// + public static PixelTypeInfo GetPixelTypeInfo() + => PixelTypeInfo.Create( + PixelComponentInfo.Create(2, 16, 16), + PixelColorType.Red | PixelColorType.Green, + PixelAlphaRepresentation.None); /// - [MethodImpl(InliningOptions.ShortMethod)] - public readonly Vector4 ToVector4() => new(this.ToVector2(), 0F, 1F); + public static PixelOperations CreatePixelOperations() => new PixelOperations(); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rg32 FromScaledVector4(Vector4 source) => FromVector4(source); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromArgb32(Argb32 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rg32 FromVector4(Vector4 source) => new() { PackedValue = Pack(new Vector2(source.X, source.Y)) }; /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgr24(Bgr24 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rg32 FromAbgr32(Abgr32 source) => new(ColorNumerics.From8BitTo16Bit(source.R), ColorNumerics.From8BitTo16Bit(source.G)); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rg32 FromArgb32(Argb32 source) => new(ColorNumerics.From8BitTo16Bit(source.R), ColorNumerics.From8BitTo16Bit(source.G)); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromAbgr32(Abgr32 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rg32 FromBgra5551(Bgra5551 source) => FromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rg32 FromBgr24(Bgr24 source) => new(ColorNumerics.From8BitTo16Bit(source.R), ColorNumerics.From8BitTo16Bit(source.G)); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL8(L8 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rg32 FromBgra32(Bgra32 source) => new(ColorNumerics.From8BitTo16Bit(source.R), ColorNumerics.From8BitTo16Bit(source.G)); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL16(L16 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rg32 FromL8(L8 source) => new(ColorNumerics.From8BitTo16Bit(source.PackedValue), ColorNumerics.From8BitTo16Bit(source.PackedValue)); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa16(La16 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rg32 FromL16(L16 source) => new(source.PackedValue, source.PackedValue); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa32(La32 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rg32 FromLa16(La16 source) => new(ColorNumerics.From8BitTo16Bit(source.L), ColorNumerics.From8BitTo16Bit(source.L)); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb24(Rgb24 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rg32 FromLa32(La32 source) => new(source.L, source.L); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba32(Rgba32 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rg32 FromRgb24(Rgb24 source) => new(ColorNumerics.From8BitTo16Bit(source.R), ColorNumerics.From8BitTo16Bit(source.G)); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void ToRgba32(ref Rgba32 dest) => dest.FromScaledVector4(this.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rg32 FromRgba32(Rgba32 source) => new(ColorNumerics.From8BitTo16Bit(source.R), ColorNumerics.From8BitTo16Bit(source.G)); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb48(Rgb48 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rg32 FromRgb48(Rgb48 source) => new(source.R, source.G); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rg32 FromRgba64(Rgba64 source) => new(source.R, source.G); /// /// Expands the packed representation into a . /// The vector components are typically expanded in least to greatest significance order. /// /// The . - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Vector2 ToVector2() => new Vector2(this.PackedValue & 0xFFFF, (this.PackedValue >> 16) & 0xFFFF) / Max; /// public override readonly bool Equals(object? obj) => obj is Rg32 other && this.Equals(other); /// - [MethodImpl(InliningOptions.ShortMethod)] public readonly bool Equals(Rg32 other) => this.PackedValue.Equals(other.PackedValue); /// public override readonly string ToString() { - var vector = this.ToVector2(); + Vector2 vector = this.ToVector2(); return FormattableString.Invariant($"Rg32({vector.X:#0.##}, {vector.Y:#0.##})"); } /// - [MethodImpl(InliningOptions.ShortMethod)] public override readonly int GetHashCode() => this.PackedValue.GetHashCode(); - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] private static uint Pack(Vector2 vector) { vector = Vector2.Clamp(vector, Vector2.Zero, Vector2.One) * Max; diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgb24.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgb24.cs index 105618cd96..0aa7bad237 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgb24.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgb24.cs @@ -4,6 +4,8 @@ using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using SixLabors.ImageSharp.ColorProfiles; namespace SixLabors.ImageSharp.PixelFormats; @@ -35,8 +37,8 @@ public partial struct Rgb24 : IPixel [FieldOffset(2)] public byte B; - private static readonly Vector4 MaxBytes = new(byte.MaxValue); - private static readonly Vector4 Half = new(0.5F); + private static readonly Vector4 MaxBytes = Vector128.Create(255f).AsVector4(); + private static readonly Vector4 Half = Vector128.Create(.5f).AsVector4(); /// /// Initializes a new instance of the struct. @@ -44,7 +46,7 @@ public partial struct Rgb24 : IPixel /// The red component. /// The green component. /// The blue component. - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public Rgb24(byte r, byte g, byte b) { this.R = r; @@ -53,36 +55,13 @@ public Rgb24(byte r, byte g, byte b) } /// - /// Converts an to . - /// - /// The . - /// The . - [MethodImpl(InliningOptions.ShortMethod)] - public static implicit operator Color(Rgb24 source) => new(source); - - /// - /// Converts a to . - /// - /// The . - /// The . - [MethodImpl(InliningOptions.ShortMethod)] - public static implicit operator Rgb24(Color color) => color.ToRgb24(); - - /// - /// Allows the implicit conversion of an instance of to a + /// Allows the implicit conversion of an instance of to a /// . /// - /// The instance of to convert. + /// The instance of to convert. /// An instance of . - [MethodImpl(InliningOptions.ShortMethod)] - public static implicit operator Rgb24(ColorSpaces.Rgb color) - { - var vector = new Vector4(color.ToVector3(), 1F); - - Rgb24 rgb = default; - rgb.FromScaledVector4(vector); - return rgb; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator Rgb24(Rgb color) => FromScaledVector4(new Vector4(color.ToVector3(), 1f)); /// /// Compares two objects for equality. @@ -92,7 +71,7 @@ public static implicit operator Rgb24(ColorSpaces.Rgb color) /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Rgb24 left, Rgb24 right) => left.Equals(right); /// @@ -103,169 +82,128 @@ public static implicit operator Rgb24(ColorSpaces.Rgb color) /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Rgb24 left, Rgb24 right) => !left.Equals(right); - /// - public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Rgba32 ToRgba32() => Rgba32.FromRgb24(this); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Vector4 ToScaledVector4() => this.ToVector4(); /// - [MethodImpl(InliningOptions.ShortMethod)] - public readonly Vector4 ToScaledVector4() => this.ToVector4(); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Vector4 ToVector4() => new Rgba32(this.R, this.G, this.B, byte.MaxValue).ToVector4(); + + /// + public static PixelTypeInfo GetPixelTypeInfo() + => PixelTypeInfo.Create( + PixelComponentInfo.Create(3, 8, 8, 8), + PixelColorType.RGB, + PixelAlphaRepresentation.None); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromVector4(Vector4 vector) => this.Pack(ref vector); + public static PixelOperations CreatePixelOperations() => new PixelOperations(); /// - [MethodImpl(InliningOptions.ShortMethod)] - public readonly Vector4 ToVector4() => new Rgba32(this.R, this.G, this.B, byte.MaxValue).ToVector4(); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgb24 FromScaledVector4(Vector4 source) => FromVector4(source); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromArgb32(Argb32 source) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgb24 FromVector4(Vector4 source) { - this.R = source.R; - this.G = source.G; - this.B = source.B; + source *= MaxBytes; + source += Half; + source = Numerics.Clamp(source, Vector4.Zero, MaxBytes); + + Vector128 result = Vector128.ConvertToInt32(source.AsVector128()).AsByte(); + return new(result.GetElement(0), result.GetElement(4), result.GetElement(8)); } /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgr24(Bgr24 source) - { - this.R = source.R; - this.G = source.G; - this.B = source.B; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgb24 FromAbgr32(Abgr32 source) => new(source.R, source.G, source.B); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra32(Bgra32 source) - { - this.R = source.R; - this.G = source.G; - this.B = source.B; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgb24 FromArgb32(Argb32 source) => new(source.R, source.G, source.B); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgb24 FromBgra5551(Bgra5551 source) => FromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromAbgr32(Abgr32 source) - { - this.R = source.R; - this.G = source.G; - this.B = source.B; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgb24 FromBgr24(Bgr24 source) => new(source.R, source.G, source.B); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL8(L8 source) - { - this.R = source.PackedValue; - this.G = source.PackedValue; - this.B = source.PackedValue; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgb24 FromBgra32(Bgra32 source) => new(source.R, source.G, source.B); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL16(L16 source) - { - byte rgb = ColorNumerics.DownScaleFrom16BitTo8Bit(source.PackedValue); - this.R = rgb; - this.G = rgb; - this.B = rgb; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgb24 FromL8(L8 source) => new(source.PackedValue, source.PackedValue, source.PackedValue); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa16(La16 source) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgb24 FromL16(L16 source) { - this.R = source.L; - this.G = source.L; - this.B = source.L; + byte rgb = ColorNumerics.From16BitTo8Bit(source.PackedValue); + return new(rgb, rgb, rgb); } /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa32(La32 source) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgb24 FromLa16(La16 source) => new(source.L, source.L, source.L); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgb24 FromLa32(La32 source) { - byte rgb = ColorNumerics.DownScaleFrom16BitTo8Bit(source.L); - this.R = rgb; - this.G = rgb; - this.B = rgb; + byte rgb = ColorNumerics.From16BitTo8Bit(source.L); + return new(rgb, rgb, rgb); } - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb24(Rgb24 source) => this = source; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgb24 FromRgb24(Rgb24 source) => new(source.R, source.G, source.B); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba32(Rgba32 source) => this = source.Rgb; - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void ToRgba32(ref Rgba32 dest) - { - dest.R = this.R; - dest.G = this.G; - dest.B = this.B; - dest.A = byte.MaxValue; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgb24 FromRgba32(Rgba32 source) => new(source.R, source.G, source.B); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb48(Rgb48 source) - { - this.R = ColorNumerics.DownScaleFrom16BitTo8Bit(source.R); - this.G = ColorNumerics.DownScaleFrom16BitTo8Bit(source.G); - this.B = ColorNumerics.DownScaleFrom16BitTo8Bit(source.B); - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgb24 FromRgb48(Rgb48 source) + => new() + { + R = ColorNumerics.From16BitTo8Bit(source.R), + G = ColorNumerics.From16BitTo8Bit(source.G), + B = ColorNumerics.From16BitTo8Bit(source.B) + }; /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba64(Rgba64 source) - { - this.R = ColorNumerics.DownScaleFrom16BitTo8Bit(source.R); - this.G = ColorNumerics.DownScaleFrom16BitTo8Bit(source.G); - this.B = ColorNumerics.DownScaleFrom16BitTo8Bit(source.B); - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgb24 FromRgba64(Rgba64 source) + => new() + { + R = ColorNumerics.From16BitTo8Bit(source.R), + G = ColorNumerics.From16BitTo8Bit(source.G), + B = ColorNumerics.From16BitTo8Bit(source.B) + }; /// public override readonly bool Equals(object? obj) => obj is Rgb24 other && this.Equals(other); /// - [MethodImpl(InliningOptions.ShortMethod)] public readonly bool Equals(Rgb24 other) => this.R.Equals(other.R) && this.G.Equals(other.G) && this.B.Equals(other.B); /// - [MethodImpl(InliningOptions.ShortMethod)] public override readonly int GetHashCode() => HashCode.Combine(this.R, this.B, this.G); /// public override readonly string ToString() => $"Rgb24({this.R}, {this.G}, {this.B})"; - - /// - /// Packs a into a color. - /// - /// The vector containing the values to pack. - [MethodImpl(InliningOptions.ShortMethod)] - private void Pack(ref Vector4 vector) - { - vector *= MaxBytes; - vector += Half; - vector = Numerics.Clamp(vector, Vector4.Zero, MaxBytes); - - this.R = (byte)vector.X; - this.G = (byte)vector.Y; - this.B = (byte)vector.Z; - } } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgb48.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgb48.cs index 6bf25717ce..e822d2abc8 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgb48.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgb48.cs @@ -55,7 +55,7 @@ public Rgb48(ushort r, ushort g, ushort b) /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Rgb48 left, Rgb48 right) => left.Equals(right); /// @@ -66,159 +66,118 @@ public Rgb48(ushort r, ushort g, ushort b) /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Rgb48 left, Rgb48 right) => !left.Equals(right); /// - public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Rgba32 ToRgba32() => Rgba32.FromRgb48(this); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector); - - /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Vector4 ToScaledVector4() => this.ToVector4(); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromVector4(Vector4 vector) - { - vector = Numerics.Clamp(vector, Vector4.Zero, Vector4.One) * Max; - this.R = (ushort)MathF.Round(vector.X); - this.G = (ushort)MathF.Round(vector.Y); - this.B = (ushort)MathF.Round(vector.Z); - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Vector4 ToVector4() => new(this.R / Max, this.G / Max, this.B / Max, 1f); /// - [MethodImpl(InliningOptions.ShortMethod)] - public readonly Vector4 ToVector4() => new(this.R / Max, this.G / Max, this.B / Max, 1F); + public static PixelTypeInfo GetPixelTypeInfo() + => PixelTypeInfo.Create( + PixelComponentInfo.Create(3, 16, 16, 16), + PixelColorType.RGB, + PixelAlphaRepresentation.None); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromArgb32(Argb32 source) - { - this.R = ColorNumerics.UpscaleFrom8BitTo16Bit(source.R); - this.G = ColorNumerics.UpscaleFrom8BitTo16Bit(source.G); - this.B = ColorNumerics.UpscaleFrom8BitTo16Bit(source.B); - } + public static PixelOperations CreatePixelOperations() => new PixelOperations(); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgb48 FromScaledVector4(Vector4 source) => FromVector4(source); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgr24(Bgr24 source) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgb48 FromVector4(Vector4 source) { - this.R = ColorNumerics.UpscaleFrom8BitTo16Bit(source.R); - this.G = ColorNumerics.UpscaleFrom8BitTo16Bit(source.G); - this.B = ColorNumerics.UpscaleFrom8BitTo16Bit(source.B); + source = Numerics.Clamp(source, Vector4.Zero, Vector4.One) * Max; + return new((ushort)MathF.Round(source.X), (ushort)MathF.Round(source.Y), (ushort)MathF.Round(source.Z)); } /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra32(Bgra32 source) - { - this.R = ColorNumerics.UpscaleFrom8BitTo16Bit(source.R); - this.G = ColorNumerics.UpscaleFrom8BitTo16Bit(source.G); - this.B = ColorNumerics.UpscaleFrom8BitTo16Bit(source.B); - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgb48 FromAbgr32(Abgr32 source) + => new(ColorNumerics.From8BitTo16Bit(source.R), ColorNumerics.From8BitTo16Bit(source.G), ColorNumerics.From8BitTo16Bit(source.B)); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba64(Rgba64 source) => this = source.Rgb; + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgb48 FromArgb32(Argb32 source) + => new(ColorNumerics.From8BitTo16Bit(source.R), ColorNumerics.From8BitTo16Bit(source.G), ColorNumerics.From8BitTo16Bit(source.B)); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgb48 FromBgra5551(Bgra5551 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL8(L8 source) - { - ushort rgb = ColorNumerics.UpscaleFrom8BitTo16Bit(source.PackedValue); - this.R = rgb; - this.G = rgb; - this.B = rgb; - } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgb48 FromBgr24(Bgr24 source) + => new(ColorNumerics.From8BitTo16Bit(source.R), ColorNumerics.From8BitTo16Bit(source.G), ColorNumerics.From8BitTo16Bit(source.B)); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgb48 FromBgra32(Bgra32 source) + => new(ColorNumerics.From8BitTo16Bit(source.R), ColorNumerics.From8BitTo16Bit(source.G), ColorNumerics.From8BitTo16Bit(source.B)); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL16(L16 source) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgb48 FromL8(L8 source) { - this.R = source.PackedValue; - this.G = source.PackedValue; - this.B = source.PackedValue; + ushort rgb = ColorNumerics.From8BitTo16Bit(source.PackedValue); + return new(rgb, rgb, rgb); } /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa16(La16 source) - { - ushort rgb = ColorNumerics.UpscaleFrom8BitTo16Bit(source.L); - this.R = rgb; - this.G = rgb; - this.B = rgb; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgb48 FromL16(L16 source) => new(source.PackedValue, source.PackedValue, source.PackedValue); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa32(La32 source) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgb48 FromLa16(La16 source) { - this.R = source.L; - this.G = source.L; - this.B = source.L; + ushort rgb = ColorNumerics.From8BitTo16Bit(source.L); + return new(rgb, rgb, rgb); } - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb24(Rgb24 source) - { - this.R = ColorNumerics.UpscaleFrom8BitTo16Bit(source.R); - this.G = ColorNumerics.UpscaleFrom8BitTo16Bit(source.G); - this.B = ColorNumerics.UpscaleFrom8BitTo16Bit(source.B); - } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgb48 FromLa32(La32 source) => new(source.L, source.L, source.L); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba32(Rgba32 source) - { - this.R = ColorNumerics.UpscaleFrom8BitTo16Bit(source.R); - this.G = ColorNumerics.UpscaleFrom8BitTo16Bit(source.G); - this.B = ColorNumerics.UpscaleFrom8BitTo16Bit(source.B); - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgb48 FromRgb24(Rgb24 source) + => new(ColorNumerics.From8BitTo16Bit(source.R), ColorNumerics.From8BitTo16Bit(source.G), ColorNumerics.From8BitTo16Bit(source.B)); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromAbgr32(Abgr32 source) - { - this.R = ColorNumerics.UpscaleFrom8BitTo16Bit(source.R); - this.G = ColorNumerics.UpscaleFrom8BitTo16Bit(source.G); - this.B = ColorNumerics.UpscaleFrom8BitTo16Bit(source.B); - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgb48 FromRgba32(Rgba32 source) + => new(ColorNumerics.From8BitTo16Bit(source.R), ColorNumerics.From8BitTo16Bit(source.G), ColorNumerics.From8BitTo16Bit(source.B)); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void ToRgba32(ref Rgba32 dest) - { - dest.R = ColorNumerics.DownScaleFrom16BitTo8Bit(this.R); - dest.G = ColorNumerics.DownScaleFrom16BitTo8Bit(this.G); - dest.B = ColorNumerics.DownScaleFrom16BitTo8Bit(this.B); - dest.A = byte.MaxValue; - } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgb48 FromRgb48(Rgb48 source) => new(source.R, source.G, source.B); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb48(Rgb48 source) => this = source; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgb48 FromRgba64(Rgba64 source) => new(source.R, source.G, source.B); /// public override readonly bool Equals(object? obj) => obj is Rgb48 rgb48 && this.Equals(rgb48); /// - [MethodImpl(InliningOptions.ShortMethod)] public readonly bool Equals(Rgb48 other) => this.R.Equals(other.R) && this.G.Equals(other.G) && this.B.Equals(other.B); /// public override readonly string ToString() => $"Rgb48({this.R}, {this.G}, {this.B})"; /// - [MethodImpl(InliningOptions.ShortMethod)] public override readonly int GetHashCode() => HashCode.Combine(this.R, this.G, this.B); } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba1010102.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba1010102.cs index 7bac1d9208..cdee22964d 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba1010102.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba1010102.cs @@ -7,7 +7,7 @@ namespace SixLabors.ImageSharp.PixelFormats; /// -/// Packed vector type containing unsigned normalized values ranging from 0 to 1. +/// Packed vector type containing 4 unsigned normalized values ranging from 0 to 1. /// The x, y and z components use 10 bits, and the w component uses 2 bits. /// /// Ranges from [0, 0, 0, 0] to [1, 1, 1, 1] in vector form. @@ -33,7 +33,7 @@ public Rgba1010102(float x, float y, float z, float w) /// Initializes a new instance of the struct. /// /// The vector containing the component values. - public Rgba1010102(Vector4 vector) => this.PackedValue = Pack(ref vector); + public Rgba1010102(Vector4 vector) => this.PackedValue = Pack(vector); /// public uint PackedValue { get; set; } @@ -46,7 +46,7 @@ public Rgba1010102(float x, float y, float z, float w) /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Rgba1010102 left, Rgba1010102 right) => left.Equals(right); /// @@ -57,26 +57,19 @@ public Rgba1010102(float x, float y, float z, float w) /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Rgba1010102 left, Rgba1010102 right) => !left.Equals(right); /// - public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Rgba32 ToRgba32() => Rgba32.FromScaledVector4(this.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector); - - /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Vector4 ToScaledVector4() => this.ToVector4(); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector); - - /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Vector4 ToVector4() => new Vector4( (this.PackedValue >> 0) & 0x03FF, (this.PackedValue >> 10) & 0x03FF, @@ -84,81 +77,93 @@ public Rgba1010102(float x, float y, float z, float w) (this.PackedValue >> 30) & 0x03) / Multiplier; /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromArgb32(Argb32 source) => this.FromScaledVector4(source.ToScaledVector4()); + public static PixelTypeInfo GetPixelTypeInfo() + => PixelTypeInfo.Create( + PixelComponentInfo.Create(4, 10, 10, 10, 2), + PixelColorType.RGB | PixelColorType.Alpha, + PixelAlphaRepresentation.Unassociated); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgr24(Bgr24 source) => this.FromScaledVector4(source.ToScaledVector4()); + public static PixelOperations CreatePixelOperations() => new PixelOperations(); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgba1010102 FromScaledVector4(Vector4 source) => FromVector4(source); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgba1010102 FromVector4(Vector4 source) => new() { PackedValue = Pack(source) }; /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromAbgr32(Abgr32 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgba1010102 FromAbgr32(Abgr32 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgba1010102 FromArgb32(Argb32 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL8(L8 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgba1010102 FromBgra5551(Bgra5551 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL16(L16 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgba1010102 FromBgr24(Bgr24 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa16(La16 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgba1010102 FromBgra32(Bgra32 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa32(La32 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgba1010102 FromL8(L8 source) => FromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb24(Rgb24 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgba1010102 FromL16(L16 source) => FromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba32(Rgba32 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgba1010102 FromLa16(La16 source) => FromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void ToRgba32(ref Rgba32 dest) => dest.FromScaledVector4(this.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgba1010102 FromLa32(La32 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb48(Rgb48 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgba1010102 FromRgb24(Rgb24 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgba1010102 FromRgba32(Rgba32 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgba1010102 FromRgb48(Rgb48 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgba1010102 FromRgba64(Rgba64 source) => FromScaledVector4(source.ToScaledVector4()); /// public override readonly bool Equals(object? obj) => obj is Rgba1010102 other && this.Equals(other); /// - [MethodImpl(InliningOptions.ShortMethod)] public readonly bool Equals(Rgba1010102 other) => this.PackedValue == other.PackedValue; /// public override readonly string ToString() { - var vector = this.ToVector4(); + Vector4 vector = this.ToVector4(); return FormattableString.Invariant($"Rgba1010102({vector.X:#0.##}, {vector.Y:#0.##}, {vector.Z:#0.##}, {vector.W:#0.##})"); } /// - [MethodImpl(InliningOptions.ShortMethod)] public override readonly int GetHashCode() => this.PackedValue.GetHashCode(); - [MethodImpl(InliningOptions.ShortMethod)] - private static uint Pack(ref Vector4 vector) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static uint Pack(Vector4 vector) { vector = Numerics.Clamp(vector, Vector4.Zero, Vector4.One) * Multiplier; diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs index a652c2b339..0491553430 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs @@ -6,6 +6,8 @@ using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using SixLabors.ImageSharp.ColorProfiles; namespace SixLabors.ImageSharp.PixelFormats; @@ -43,8 +45,8 @@ public partial struct Rgba32 : IPixel, IPackedVector /// public byte A; - private static readonly Vector4 MaxBytes = new(byte.MaxValue); - private static readonly Vector4 Half = new(0.5F); + private static readonly Vector4 MaxBytes = Vector128.Create(255f).AsVector4(); + private static readonly Vector4 Half = Vector128.Create(.5f).AsVector4(); /// /// Initializes a new instance of the struct. @@ -52,7 +54,7 @@ public partial struct Rgba32 : IPixel, IPackedVector /// The red component. /// The green component. /// The blue component. - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public Rgba32(byte r, byte g, byte b) { this.R = r; @@ -68,7 +70,7 @@ public Rgba32(byte r, byte g, byte b) /// The green component. /// The blue component. /// The alpha component. - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public Rgba32(byte r, byte g, byte b, byte a) { this.R = r; @@ -84,9 +86,11 @@ public Rgba32(byte r, byte g, byte b, byte a) /// The green component. /// The blue component. /// The alpha component. - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public Rgba32(float r, float g, float b, float a = 1) - : this() => this.Pack(r, g, b, a); + : this(new Vector4(r, g, b, a)) + { + } /// /// Initializes a new instance of the struct. @@ -94,9 +98,11 @@ public Rgba32(float r, float g, float b, float a = 1) /// /// The vector containing the components for the packed vector. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public Rgba32(Vector3 vector) - : this() => this.Pack(ref vector); + : this(new Vector4(vector, 1f)) + { + } /// /// Initializes a new instance of the struct. @@ -104,9 +110,9 @@ public Rgba32(Vector3 vector) /// /// The vector containing the components for the packed vector. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public Rgba32(Vector4 vector) - : this() => this = PackNew(ref vector); + : this() => this = Pack(vector); /// /// Initializes a new instance of the struct. @@ -114,7 +120,7 @@ public Rgba32(Vector4 vector) /// /// The packed value. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public Rgba32(uint packed) : this() => this.Rgba = packed; @@ -123,10 +129,10 @@ public Rgba32(uint packed) /// public uint Rgba { - [MethodImpl(InliningOptions.ShortMethod)] - readonly get => Unsafe.As(ref Unsafe.AsRef(this)); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + readonly get => Unsafe.As(ref Unsafe.AsRef(in this)); - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] set => Unsafe.As(ref this) = value; } @@ -135,10 +141,10 @@ public uint Rgba /// public Rgb24 Rgb { - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get => new(this.R, this.G, this.B); - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] set { this.R = value.R; @@ -152,10 +158,10 @@ public Rgb24 Rgb /// public Bgr24 Bgr { - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get => new(this.R, this.G, this.B); - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] set { this.R = value.R; @@ -167,44 +173,21 @@ public Bgr24 Bgr /// public uint PackedValue { - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get => this.Rgba; - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] set => this.Rgba = value; } /// - /// Converts an to . - /// - /// The . - /// The . - [MethodImpl(InliningOptions.ShortMethod)] - public static implicit operator Color(Rgba32 source) => new(source); - - /// - /// Converts a to . - /// - /// The . - /// The . - [MethodImpl(InliningOptions.ShortMethod)] - public static implicit operator Rgba32(Color color) => color.ToRgba32(); - - /// - /// Allows the implicit conversion of an instance of to a + /// Allows the implicit conversion of an instance of to a /// . /// - /// The instance of to convert. + /// The instance of to convert. /// An instance of . - [MethodImpl(InliningOptions.ShortMethod)] - public static implicit operator Rgba32(ColorSpaces.Rgb color) - { - var vector = new Vector4(color.ToVector3(), 1F); - - Rgba32 rgba = default; - rgba.FromScaledVector4(vector); - return rgba; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator Rgba32(Rgb color) => FromScaledVector4(new Vector4(color.ToVector3(), 1F)); /// /// Compares two objects for equality. @@ -214,7 +197,7 @@ public static implicit operator Rgba32(ColorSpaces.Rgb color) /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Rgba32 left, Rgba32 right) => left.Equals(right); /// @@ -225,7 +208,7 @@ public static implicit operator Rgba32(ColorSpaces.Rgb color) /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Rgba32 left, Rgba32 right) => !left.Equals(right); /// @@ -240,7 +223,7 @@ public static implicit operator Rgba32(ColorSpaces.Rgb color) /// The . /// /// Hexadecimal string is not in the correct format. - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Rgba32 ParseHex(string hex) { Guard.NotNull(hex, nameof(hex)); @@ -265,7 +248,7 @@ public static Rgba32 ParseHex(string hex) /// /// The . /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool TryParseHex(string? hex, out Rgba32 result) { result = default; @@ -287,143 +270,108 @@ public static bool TryParseHex(string? hex, out Rgba32 result) } /// - public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Rgba32 ToRgba32() => this; /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Vector4 ToScaledVector4() => this.ToVector4(); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromVector4(Vector4 vector) => this.Pack(ref vector); - - /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Vector4 ToVector4() => new Vector4(this.R, this.G, this.B, this.A) / MaxBytes; + /// + public static PixelTypeInfo GetPixelTypeInfo() + => PixelTypeInfo.Create( + PixelComponentInfo.Create(4, 8, 8, 8, 8), + PixelColorType.RGB | PixelColorType.Alpha, + PixelAlphaRepresentation.Unassociated); + + /// + public static PixelOperations CreatePixelOperations() => new PixelOperations(); + /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromArgb32(Argb32 source) - { - this.R = source.R; - this.G = source.G; - this.B = source.B; - this.A = source.A; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgba32 FromScaledVector4(Vector4 source) => FromVector4(source); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgr24(Bgr24 source) - { - this.Bgr = source; - this.A = byte.MaxValue; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgba32 FromVector4(Vector4 source) => Pack(source); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra32(Bgra32 source) - { - this.R = source.R; - this.G = source.G; - this.B = source.B; - this.A = source.A; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgba32 FromAbgr32(Abgr32 source) => new(source.R, source.G, source.B, source.A); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromAbgr32(Abgr32 source) - { - this.R = source.R; - this.G = source.G; - this.B = source.B; - this.A = source.A; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgba32 FromArgb32(Argb32 source) => new(source.R, source.G, source.B, source.A); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgba32 FromBgra5551(Bgra5551 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgba32 FromBgr24(Bgr24 source) => new(source.R, source.G, source.B); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgba32 FromBgra32(Bgra32 source) => new(source.R, source.G, source.B, source.A); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL8(L8 source) - { - this.R = source.PackedValue; - this.G = source.PackedValue; - this.B = source.PackedValue; - this.A = byte.MaxValue; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgba32 FromL8(L8 source) => new(source.PackedValue, source.PackedValue, source.PackedValue); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL16(L16 source) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgba32 FromL16(L16 source) { - byte rgb = ColorNumerics.DownScaleFrom16BitTo8Bit(source.PackedValue); - this.R = rgb; - this.G = rgb; - this.B = rgb; - this.A = byte.MaxValue; + byte rgb = ColorNumerics.From16BitTo8Bit(source.PackedValue); + return new(rgb, rgb, rgb); } /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa16(La16 source) - { - this.R = source.L; - this.G = source.L; - this.B = source.L; - this.A = source.A; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgba32 FromLa16(La16 source) => new(source.L, source.L, source.L, source.A); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa32(La32 source) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgba32 FromLa32(La32 source) { - byte rgb = ColorNumerics.DownScaleFrom16BitTo8Bit(source.L); - this.R = rgb; - this.G = rgb; - this.B = rgb; - this.A = ColorNumerics.DownScaleFrom16BitTo8Bit(source.A); + byte rgb = ColorNumerics.From16BitTo8Bit(source.L); + return new(rgb, rgb, rgb, ColorNumerics.From16BitTo8Bit(source.A)); } /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb24(Rgb24 source) - { - this.Rgb = source; - this.A = byte.MaxValue; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgba32 FromRgb24(Rgb24 source) => new(source.R, source.G, source.B); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba32(Rgba32 source) => this = source; - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void ToRgba32(ref Rgba32 dest) => dest = this; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgba32 FromRgba32(Rgba32 source) => new() { PackedValue = source.PackedValue }; /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb48(Rgb48 source) - { - this.R = ColorNumerics.DownScaleFrom16BitTo8Bit(source.R); - this.G = ColorNumerics.DownScaleFrom16BitTo8Bit(source.G); - this.B = ColorNumerics.DownScaleFrom16BitTo8Bit(source.B); - this.A = byte.MaxValue; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgba32 FromRgb48(Rgb48 source) + => new() + { + R = ColorNumerics.From16BitTo8Bit(source.R), + G = ColorNumerics.From16BitTo8Bit(source.G), + B = ColorNumerics.From16BitTo8Bit(source.B), + A = byte.MaxValue + }; /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba64(Rgba64 source) - { - this.R = ColorNumerics.DownScaleFrom16BitTo8Bit(source.R); - this.G = ColorNumerics.DownScaleFrom16BitTo8Bit(source.G); - this.B = ColorNumerics.DownScaleFrom16BitTo8Bit(source.B); - this.A = ColorNumerics.DownScaleFrom16BitTo8Bit(source.A); - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgba32 FromRgba64(Rgba64 source) + => new() + { + R = ColorNumerics.From16BitTo8Bit(source.R), + G = ColorNumerics.From16BitTo8Bit(source.G), + B = ColorNumerics.From16BitTo8Bit(source.B), + A = ColorNumerics.From16BitTo8Bit(source.A) + }; /// /// Converts the value of this instance to a hexadecimal string. @@ -439,71 +387,27 @@ public readonly string ToHex() public override readonly bool Equals(object? obj) => obj is Rgba32 rgba32 && this.Equals(rgba32); /// - [MethodImpl(InliningOptions.ShortMethod)] public readonly bool Equals(Rgba32 other) => this.Rgba.Equals(other.Rgba); /// public override readonly string ToString() => $"Rgba32({this.R}, {this.G}, {this.B}, {this.A})"; /// - [MethodImpl(InliningOptions.ShortMethod)] public override readonly int GetHashCode() => this.Rgba.GetHashCode(); - /// - /// Packs a into a color returning a new instance as a result. - /// - /// The vector containing the values to pack. - /// The - [MethodImpl(InliningOptions.ShortMethod)] - private static Rgba32 PackNew(ref Vector4 vector) - { - vector *= MaxBytes; - vector += Half; - vector = Numerics.Clamp(vector, Vector4.Zero, MaxBytes); - - return new Rgba32((byte)vector.X, (byte)vector.Y, (byte)vector.Z, (byte)vector.W); - } - - /// - /// Packs the four floats into a color. - /// - /// The x-component - /// The y-component - /// The z-component - /// The w-component - [MethodImpl(InliningOptions.ShortMethod)] - private void Pack(float x, float y, float z, float w) - { - var value = new Vector4(x, y, z, w); - this.Pack(ref value); - } - - /// - /// Packs a into a uint. - /// - /// The vector containing the values to pack. - [MethodImpl(InliningOptions.ShortMethod)] - private void Pack(ref Vector3 vector) - { - var value = new Vector4(vector, 1F); - this.Pack(ref value); - } - /// /// Packs a into a color. /// /// The vector containing the values to pack. - [MethodImpl(InliningOptions.ShortMethod)] - private void Pack(ref Vector4 vector) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static Rgba32 Pack(Vector4 vector) { vector *= MaxBytes; vector += Half; vector = Numerics.Clamp(vector, Vector4.Zero, MaxBytes); - this.R = (byte)vector.X; - this.G = (byte)vector.Y; - this.B = (byte)vector.Z; - this.A = (byte)vector.W; + Vector128 result = Vector128.ConvertToInt32(vector.AsVector128()).AsByte(); + return new(result.GetElement(0), result.GetElement(4), result.GetElement(8), result.GetElement(12)); } /// @@ -535,10 +439,10 @@ private void Pack(ref Vector4 vector) return null; } - char r = hex[0]; - char g = hex[1]; - char b = hex[2]; char a = hex.Length == 3 ? 'F' : hex[3]; + char b = hex[2]; + char g = hex[1]; + char r = hex[0]; return new string(new[] { r, r, g, g, b, b, a, a }); } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs index 81c9591480..27c4752e10 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs @@ -45,7 +45,7 @@ public partial struct Rgba64 : IPixel, IPackedVector /// The green component. /// The blue component. /// The alpha component. - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public Rgba64(ushort r, ushort g, ushort b, ushort a) { this.R = r; @@ -58,64 +58,64 @@ public Rgba64(ushort r, ushort g, ushort b, ushort a) /// Initializes a new instance of the struct. /// /// A structure of 4 bytes in RGBA byte order. - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public Rgba64(Rgba32 source) { - this.R = ColorNumerics.UpscaleFrom8BitTo16Bit(source.R); - this.G = ColorNumerics.UpscaleFrom8BitTo16Bit(source.G); - this.B = ColorNumerics.UpscaleFrom8BitTo16Bit(source.B); - this.A = ColorNumerics.UpscaleFrom8BitTo16Bit(source.A); + this.R = ColorNumerics.From8BitTo16Bit(source.R); + this.G = ColorNumerics.From8BitTo16Bit(source.G); + this.B = ColorNumerics.From8BitTo16Bit(source.B); + this.A = ColorNumerics.From8BitTo16Bit(source.A); } /// /// Initializes a new instance of the struct. /// /// A structure of 4 bytes in BGRA byte order. - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public Rgba64(Bgra32 source) { - this.R = ColorNumerics.UpscaleFrom8BitTo16Bit(source.R); - this.G = ColorNumerics.UpscaleFrom8BitTo16Bit(source.G); - this.B = ColorNumerics.UpscaleFrom8BitTo16Bit(source.B); - this.A = ColorNumerics.UpscaleFrom8BitTo16Bit(source.A); + this.R = ColorNumerics.From8BitTo16Bit(source.R); + this.G = ColorNumerics.From8BitTo16Bit(source.G); + this.B = ColorNumerics.From8BitTo16Bit(source.B); + this.A = ColorNumerics.From8BitTo16Bit(source.A); } /// /// Initializes a new instance of the struct. /// /// A structure of 4 bytes in ARGB byte order. - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public Rgba64(Argb32 source) { - this.R = ColorNumerics.UpscaleFrom8BitTo16Bit(source.R); - this.G = ColorNumerics.UpscaleFrom8BitTo16Bit(source.G); - this.B = ColorNumerics.UpscaleFrom8BitTo16Bit(source.B); - this.A = ColorNumerics.UpscaleFrom8BitTo16Bit(source.A); + this.R = ColorNumerics.From8BitTo16Bit(source.R); + this.G = ColorNumerics.From8BitTo16Bit(source.G); + this.B = ColorNumerics.From8BitTo16Bit(source.B); + this.A = ColorNumerics.From8BitTo16Bit(source.A); } /// /// Initializes a new instance of the struct. /// /// A structure of 4 bytes in ABGR byte order. - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public Rgba64(Abgr32 source) { - this.R = ColorNumerics.UpscaleFrom8BitTo16Bit(source.R); - this.G = ColorNumerics.UpscaleFrom8BitTo16Bit(source.G); - this.B = ColorNumerics.UpscaleFrom8BitTo16Bit(source.B); - this.A = ColorNumerics.UpscaleFrom8BitTo16Bit(source.A); + this.R = ColorNumerics.From8BitTo16Bit(source.R); + this.G = ColorNumerics.From8BitTo16Bit(source.G); + this.B = ColorNumerics.From8BitTo16Bit(source.B); + this.A = ColorNumerics.From8BitTo16Bit(source.A); } /// /// Initializes a new instance of the struct. /// /// A structure of 3 bytes in RGB byte order. - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public Rgba64(Rgb24 source) { - this.R = ColorNumerics.UpscaleFrom8BitTo16Bit(source.R); - this.G = ColorNumerics.UpscaleFrom8BitTo16Bit(source.G); - this.B = ColorNumerics.UpscaleFrom8BitTo16Bit(source.B); + this.R = ColorNumerics.From8BitTo16Bit(source.R); + this.G = ColorNumerics.From8BitTo16Bit(source.G); + this.B = ColorNumerics.From8BitTo16Bit(source.B); this.A = ushort.MaxValue; } @@ -123,12 +123,12 @@ public Rgba64(Rgb24 source) /// Initializes a new instance of the struct. /// /// A structure of 3 bytes in BGR byte order. - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public Rgba64(Bgr24 source) { - this.R = ColorNumerics.UpscaleFrom8BitTo16Bit(source.R); - this.G = ColorNumerics.UpscaleFrom8BitTo16Bit(source.G); - this.B = ColorNumerics.UpscaleFrom8BitTo16Bit(source.B); + this.R = ColorNumerics.From8BitTo16Bit(source.R); + this.G = ColorNumerics.From8BitTo16Bit(source.G); + this.B = ColorNumerics.From8BitTo16Bit(source.B); this.A = ushort.MaxValue; } @@ -136,7 +136,7 @@ public Rgba64(Bgr24 source) /// Initializes a new instance of the struct. /// /// The . - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public Rgba64(Vector4 vector) { vector = Numerics.Clamp(vector, Vector4.Zero, Vector4.One) * Max; @@ -151,39 +151,23 @@ public Rgba64(Vector4 vector) /// public Rgb48 Rgb { - [MethodImpl(InliningOptions.ShortMethod)] - readonly get => Unsafe.As(ref Unsafe.AsRef(this)); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + readonly get => Unsafe.As(ref Unsafe.AsRef(in this)); - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] set => Unsafe.As(ref this) = value; } /// public ulong PackedValue { - [MethodImpl(InliningOptions.ShortMethod)] - readonly get => Unsafe.As(ref Unsafe.AsRef(this)); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + readonly get => Unsafe.As(ref Unsafe.AsRef(in this)); - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] set => Unsafe.As(ref this) = value; } - /// - /// Converts an to . - /// - /// The . - /// The . - [MethodImpl(InliningOptions.ShortMethod)] - public static implicit operator Color(Rgba64 source) => new(source); - - /// - /// Converts a to . - /// - /// The . - /// The . - [MethodImpl(InliningOptions.ShortMethod)] - public static implicit operator Rgba64(Color color) => color.ToPixel(); - /// /// Compares two objects for equality. /// @@ -192,7 +176,7 @@ public ulong PackedValue /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Rgba64 left, Rgba64 right) => left.PackedValue == right.PackedValue; /// @@ -203,256 +187,143 @@ public ulong PackedValue /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Rgba64 left, Rgba64 right) => left.PackedValue != right.PackedValue; /// - public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Rgba32 ToRgba32() => Rgba32.FromRgba64(this); /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Vector4 ToScaledVector4() => this.ToVector4(); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromVector4(Vector4 vector) - { - vector = Numerics.Clamp(vector, Vector4.Zero, Vector4.One) * Max; - this.R = (ushort)MathF.Round(vector.X); - this.G = (ushort)MathF.Round(vector.Y); - this.B = (ushort)MathF.Round(vector.Z); - this.A = (ushort)MathF.Round(vector.W); - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Vector4 ToVector4() => new Vector4(this.R, this.G, this.B, this.A) / Max; /// - [MethodImpl(InliningOptions.ShortMethod)] - public readonly Vector4 ToVector4() => new Vector4(this.R, this.G, this.B, this.A) / Max; + public static PixelTypeInfo GetPixelTypeInfo() + => PixelTypeInfo.Create( + PixelComponentInfo.Create(4, 16, 16, 16, 16), + PixelColorType.RGB | PixelColorType.Alpha, + PixelAlphaRepresentation.Unassociated); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromArgb32(Argb32 source) - { - this.R = ColorNumerics.UpscaleFrom8BitTo16Bit(source.R); - this.G = ColorNumerics.UpscaleFrom8BitTo16Bit(source.G); - this.B = ColorNumerics.UpscaleFrom8BitTo16Bit(source.B); - this.A = ColorNumerics.UpscaleFrom8BitTo16Bit(source.A); - } + public static PixelOperations CreatePixelOperations() => new PixelOperations(); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgba64 FromScaledVector4(Vector4 source) => FromVector4(source); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgr24(Bgr24 source) - { - this.R = ColorNumerics.UpscaleFrom8BitTo16Bit(source.R); - this.G = ColorNumerics.UpscaleFrom8BitTo16Bit(source.G); - this.B = ColorNumerics.UpscaleFrom8BitTo16Bit(source.B); - this.A = ushort.MaxValue; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgba64 FromVector4(Vector4 source) => new(source); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra32(Bgra32 source) - { - this.R = ColorNumerics.UpscaleFrom8BitTo16Bit(source.R); - this.G = ColorNumerics.UpscaleFrom8BitTo16Bit(source.G); - this.B = ColorNumerics.UpscaleFrom8BitTo16Bit(source.B); - this.A = ColorNumerics.UpscaleFrom8BitTo16Bit(source.A); - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgba64 FromAbgr32(Abgr32 source) => new(source); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromAbgr32(Abgr32 source) - { - this.R = ColorNumerics.UpscaleFrom8BitTo16Bit(source.R); - this.G = ColorNumerics.UpscaleFrom8BitTo16Bit(source.G); - this.B = ColorNumerics.UpscaleFrom8BitTo16Bit(source.B); - this.A = ColorNumerics.UpscaleFrom8BitTo16Bit(source.A); - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgba64 FromArgb32(Argb32 source) => new(source); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgba64 FromBgra5551(Bgra5551 source) => FromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL8(L8 source) - { - ushort rgb = ColorNumerics.UpscaleFrom8BitTo16Bit(source.PackedValue); - this.R = rgb; - this.G = rgb; - this.B = rgb; - this.A = ushort.MaxValue; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgba64 FromBgr24(Bgr24 source) => new(source); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL16(L16 source) - { - this.R = source.PackedValue; - this.G = source.PackedValue; - this.B = source.PackedValue; - this.A = ushort.MaxValue; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgba64 FromBgra32(Bgra32 source) => new(source); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa16(La16 source) + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgba64 FromL8(L8 source) { - ushort rgb = ColorNumerics.UpscaleFrom8BitTo16Bit(source.L); - this.R = rgb; - this.G = rgb; - this.B = rgb; - this.A = ColorNumerics.UpscaleFrom8BitTo16Bit(source.A); + ushort rgb = ColorNumerics.From8BitTo16Bit(source.PackedValue); + return new(rgb, rgb, rgb, ushort.MaxValue); } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgba64 FromL16(L16 source) => new(source.PackedValue, source.PackedValue, source.PackedValue, ushort.MaxValue); + /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa32(La32 source) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgba64 FromLa16(La16 source) { - this.R = source.L; - this.G = source.L; - this.B = source.L; - this.A = source.A; + ushort rgb = ColorNumerics.From8BitTo16Bit(source.L); + return new(rgb, rgb, rgb, ColorNumerics.From8BitTo16Bit(source.A)); } - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb24(Rgb24 source) - { - this.R = ColorNumerics.UpscaleFrom8BitTo16Bit(source.R); - this.G = ColorNumerics.UpscaleFrom8BitTo16Bit(source.G); - this.B = ColorNumerics.UpscaleFrom8BitTo16Bit(source.B); - this.A = ushort.MaxValue; - } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgba64 FromLa32(La32 source) => new(source.L, source.L, source.L, source.A); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba32(Rgba32 source) - { - this.R = ColorNumerics.UpscaleFrom8BitTo16Bit(source.R); - this.G = ColorNumerics.UpscaleFrom8BitTo16Bit(source.G); - this.B = ColorNumerics.UpscaleFrom8BitTo16Bit(source.B); - this.A = ColorNumerics.UpscaleFrom8BitTo16Bit(source.A); - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgba64 FromRgb24(Rgb24 source) => new(source); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void ToRgba32(ref Rgba32 dest) - { - dest.R = ColorNumerics.DownScaleFrom16BitTo8Bit(this.R); - dest.G = ColorNumerics.DownScaleFrom16BitTo8Bit(this.G); - dest.B = ColorNumerics.DownScaleFrom16BitTo8Bit(this.B); - dest.A = ColorNumerics.DownScaleFrom16BitTo8Bit(this.A); - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgba64 FromRgba32(Rgba32 source) => new(source); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb48(Rgb48 source) - { - this.Rgb = source; - this.A = ushort.MaxValue; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgba64 FromRgb48(Rgb48 source) => new(source.R, source.G, source.B, ushort.MaxValue); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba64(Rgba64 source) => this = source; - - /// - /// Convert to . - /// - /// The . - [MethodImpl(InliningOptions.ShortMethod)] - public readonly Rgba32 ToRgba32() - { - byte r = ColorNumerics.DownScaleFrom16BitTo8Bit(this.R); - byte g = ColorNumerics.DownScaleFrom16BitTo8Bit(this.G); - byte b = ColorNumerics.DownScaleFrom16BitTo8Bit(this.B); - byte a = ColorNumerics.DownScaleFrom16BitTo8Bit(this.A); - return new Rgba32(r, g, b, a); - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgba64 FromRgba64(Rgba64 source) => new(source.R, source.G, source.B, source.A); /// /// Convert to . /// /// The . - [MethodImpl(InliningOptions.ShortMethod)] - public readonly Bgra32 ToBgra32() - { - byte r = ColorNumerics.DownScaleFrom16BitTo8Bit(this.R); - byte g = ColorNumerics.DownScaleFrom16BitTo8Bit(this.G); - byte b = ColorNumerics.DownScaleFrom16BitTo8Bit(this.B); - byte a = ColorNumerics.DownScaleFrom16BitTo8Bit(this.A); - return new Bgra32(r, g, b, a); - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Bgra32 ToBgra32() => Bgra32.FromRgba64(this); /// /// Convert to . /// /// The . - [MethodImpl(InliningOptions.ShortMethod)] - public readonly Argb32 ToArgb32() - { - byte r = ColorNumerics.DownScaleFrom16BitTo8Bit(this.R); - byte g = ColorNumerics.DownScaleFrom16BitTo8Bit(this.G); - byte b = ColorNumerics.DownScaleFrom16BitTo8Bit(this.B); - byte a = ColorNumerics.DownScaleFrom16BitTo8Bit(this.A); - return new Argb32(r, g, b, a); - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Argb32 ToArgb32() => Argb32.FromRgba64(this); /// /// Convert to . /// /// The . - [MethodImpl(InliningOptions.ShortMethod)] - public readonly Abgr32 ToAbgr32() - { - byte r = ColorNumerics.DownScaleFrom16BitTo8Bit(this.R); - byte g = ColorNumerics.DownScaleFrom16BitTo8Bit(this.G); - byte b = ColorNumerics.DownScaleFrom16BitTo8Bit(this.B); - byte a = ColorNumerics.DownScaleFrom16BitTo8Bit(this.A); - return new Abgr32(r, g, b, a); - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Abgr32 ToAbgr32() => Abgr32.FromRgba64(this); /// /// Convert to . /// /// The . - [MethodImpl(InliningOptions.ShortMethod)] - public readonly Rgb24 ToRgb24() - { - byte r = ColorNumerics.DownScaleFrom16BitTo8Bit(this.R); - byte g = ColorNumerics.DownScaleFrom16BitTo8Bit(this.G); - byte b = ColorNumerics.DownScaleFrom16BitTo8Bit(this.B); - return new Rgb24(r, g, b); - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Rgb24 ToRgb24() => Rgb24.FromRgba64(this); /// /// Convert to . /// /// The . - [MethodImpl(InliningOptions.ShortMethod)] - public readonly Bgr24 ToBgr24() - { - byte r = ColorNumerics.DownScaleFrom16BitTo8Bit(this.R); - byte g = ColorNumerics.DownScaleFrom16BitTo8Bit(this.G); - byte b = ColorNumerics.DownScaleFrom16BitTo8Bit(this.B); - return new Bgr24(r, g, b); - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Bgr24 ToBgr24() => Bgr24.FromRgba64(this); /// public override readonly bool Equals(object? obj) => obj is Rgba64 rgba64 && this.Equals(rgba64); /// - [MethodImpl(InliningOptions.ShortMethod)] public readonly bool Equals(Rgba64 other) => this.PackedValue.Equals(other.PackedValue); /// public override readonly string ToString() => $"Rgba64({this.R}, {this.G}, {this.B}, {this.A})"; /// - [MethodImpl(InliningOptions.ShortMethod)] public override readonly int GetHashCode() => this.PackedValue.GetHashCode(); } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.cs b/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.cs index 899987b712..a27cffad83 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.cs @@ -53,7 +53,7 @@ public partial struct RgbaVector : IPixel /// The green component. /// The blue component. /// The alpha component. - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public RgbaVector(float r, float g, float b, float a = 1) { this.R = r; @@ -70,7 +70,7 @@ public RgbaVector(float r, float g, float b, float a = 1) /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(RgbaVector left, RgbaVector right) => left.Equals(right); /// @@ -81,102 +81,106 @@ public RgbaVector(float r, float g, float b, float a = 1) /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(RgbaVector left, RgbaVector right) => !left.Equals(right); - /// - /// Creates a new instance of the struct. - /// - /// - /// The hexadecimal representation of the combined color components arranged - /// in rgb, rgba, rrggbb, or rrggbbaa format to match web syntax. - /// - /// - /// The . - /// - public static RgbaVector FromHex(string hex) => Color.ParseHex(hex).ToPixel(); - /// - public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Rgba32 ToRgba32() => Rgba32.FromScaledVector4(this.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Vector4 ToScaledVector4() => this.ToVector4(); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromVector4(Vector4 vector) - { - vector = Numerics.Clamp(vector, Vector4.Zero, Vector4.One); - this.R = vector.X; - this.G = vector.Y; - this.B = vector.Z; - this.A = vector.W; - } - - /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Vector4 ToVector4() => new(this.R, this.G, this.B, this.A); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromArgb32(Argb32 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + public static PixelTypeInfo GetPixelTypeInfo() + => PixelTypeInfo.Create( + PixelComponentInfo.Create(4, 32, 32, 32, 32), + PixelColorType.RGB | PixelColorType.Alpha, + PixelAlphaRepresentation.Unassociated); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgr24(Bgr24 source) => this.FromScaledVector4(source.ToScaledVector4()); + public static PixelOperations CreatePixelOperations() => new PixelOperations(); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static RgbaVector FromScaledVector4(Vector4 source) => FromVector4(source); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromAbgr32(Abgr32 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static RgbaVector FromVector4(Vector4 source) + { + source = Numerics.Clamp(source, Vector4.Zero, Vector4.One); + return new(source.X, source.Y, source.Z, source.W); + } - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static RgbaVector FromAbgr32(Abgr32 source) => FromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL8(L8 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static RgbaVector FromArgb32(Argb32 source) => FromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL16(L16 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static RgbaVector FromBgra5551(Bgra5551 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa16(La16 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static RgbaVector FromBgr24(Bgr24 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa32(La32 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static RgbaVector FromBgra32(Bgra32 source) => FromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb24(Rgb24 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static RgbaVector FromL8(L8 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba32(Rgba32 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static RgbaVector FromL16(L16 source) => FromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void ToRgba32(ref Rgba32 dest) => dest.FromScaledVector4(this.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static RgbaVector FromLa16(La16 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb48(Rgb48 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static RgbaVector FromLa32(La32 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static RgbaVector FromRgb24(Rgb24 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static RgbaVector FromRgba32(Rgba32 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static RgbaVector FromRgb48(Rgb48 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static RgbaVector FromRgba64(Rgba64 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + /// Creates a new instance of the struct. + /// + /// + /// The hexadecimal representation of the combined color components arranged + /// in rgb, rgba, rrggbb, or rrggbbaa format to match web syntax. + /// + /// + /// The . + /// + public static RgbaVector FromHex(string hex) => Color.ParseHex(hex).ToPixel(); /// /// Converts the value of this instance to a hexadecimal string. @@ -195,7 +199,6 @@ public readonly string ToHex() public override readonly bool Equals(object? obj) => obj is RgbaVector other && this.Equals(other); /// - [MethodImpl(InliningOptions.ShortMethod)] public readonly bool Equals(RgbaVector other) => this.R.Equals(other.R) && this.G.Equals(other.G) diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Short2.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Short2.cs index 832e8c770f..403d3fbea3 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Short2.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Short2.cs @@ -50,7 +50,7 @@ public Short2(float x, float y) /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Short2 left, Short2 right) => left.Equals(right); /// @@ -61,126 +61,127 @@ public Short2(float x, float y) /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Short2 left, Short2 right) => !left.Equals(right); /// - public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Rgba32 ToRgba32() => Rgba32.FromScaledVector4(this.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromScaledVector4(Vector4 vector) - { - Vector2 scaled = new Vector2(vector.X, vector.Y) * 65534F; - scaled -= new Vector2(32767F); - this.PackedValue = Pack(scaled); - } - - /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Vector4 ToScaledVector4() { - var scaled = this.ToVector2(); - scaled += new Vector2(32767F); + Vector2 scaled = this.ToVector2(); + scaled += new Vector2(32767f); scaled /= 65534F; - return new Vector4(scaled, 0F, 1F); + return new Vector4(scaled, 0f, 1f); } /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromVector4(Vector4 vector) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Vector4 ToVector4() => new((short)(this.PackedValue & 0xFFFF), (short)(this.PackedValue >> 0x10), 0f, 1f); + + /// + public static PixelTypeInfo GetPixelTypeInfo() + => PixelTypeInfo.Create( + PixelComponentInfo.Create(2, 16, 16), + PixelColorType.Red | PixelColorType.Green, + PixelAlphaRepresentation.None); + + /// + public static PixelOperations CreatePixelOperations() => new PixelOperations(); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Short2 FromScaledVector4(Vector4 source) { - var vector2 = new Vector2(vector.X, vector.Y); - this.PackedValue = Pack(vector2); + Vector2 scaled = new Vector2(source.X, source.Y) * 65534F; + scaled -= new Vector2(32767F); + return new() { PackedValue = Pack(scaled) }; } /// - [MethodImpl(InliningOptions.ShortMethod)] - public readonly Vector4 ToVector4() => new((short)(this.PackedValue & 0xFFFF), (short)(this.PackedValue >> 0x10), 0, 1); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Short2 FromVector4(Vector4 source) => new() { PackedValue = Pack(new Vector2(source.X, source.Y)) }; /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromArgb32(Argb32 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Short2 FromAbgr32(Abgr32 source) => FromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgr24(Bgr24 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Short2 FromArgb32(Argb32 source) => FromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Short2 FromBgra5551(Bgra5551 source) => FromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromAbgr32(Abgr32 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Short2 FromBgr24(Bgr24 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL8(L8 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Short2 FromBgra32(Bgra32 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL16(L16 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Short2 FromL8(L8 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa16(La16 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Short2 FromL16(L16 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa32(La32 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Short2 FromLa16(La16 source) => FromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb24(Rgb24 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Short2 FromLa32(La32 source) => FromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba32(Rgba32 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Short2 FromRgb24(Rgb24 source) => FromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void ToRgba32(ref Rgba32 dest) => dest.FromScaledVector4(this.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Short2 FromRgba32(Rgba32 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb48(Rgb48 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Short2 FromRgb48(Rgb48 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Short2 FromRgba64(Rgba64 source) => FromScaledVector4(source.ToScaledVector4()); /// /// Expands the packed representation into a . /// The vector components are typically expanded in least to greatest significance order. /// /// The . - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] 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); /// - [MethodImpl(InliningOptions.ShortMethod)] public readonly bool Equals(Short2 other) => this.PackedValue.Equals(other.PackedValue); /// - [MethodImpl(InliningOptions.ShortMethod)] public override readonly int GetHashCode() => this.PackedValue.GetHashCode(); /// public override readonly string ToString() { - var vector = this.ToVector2(); + Vector2 vector = this.ToVector2(); return FormattableString.Invariant($"Short2({vector.X:#0.##}, {vector.Y:#0.##})"); } - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] private static uint Pack(Vector2 vector) { vector = Vector2.Clamp(vector, Min, Max); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Short4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Short4.cs index c4dc324a13..b6cece2bef 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Short4.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Short4.cs @@ -20,8 +20,8 @@ public partial struct Short4 : IPixel, IPackedVector // Two's complement private const float MinNeg = ~(int)MaxPos; - private static readonly Vector4 Max = new Vector4(MaxPos); - private static readonly Vector4 Min = new Vector4(MinNeg); + private static readonly Vector4 Max = new(MaxPos); + private static readonly Vector4 Min = new(MinNeg); /// /// Initializes a new instance of the struct. @@ -39,7 +39,7 @@ public Short4(float x, float y, float z, float w) /// Initializes a new instance of the struct. /// /// A vector containing the initial values for the components. - public Short4(Vector4 vector) => this.PackedValue = Pack(ref vector); + public Short4(Vector4 vector) => this.PackedValue = Pack(vector); /// public ulong PackedValue { get; set; } @@ -52,7 +52,7 @@ public Short4(float x, float y, float z, float w) /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Short4 left, Short4 right) => left.Equals(right); /// @@ -63,132 +63,131 @@ public Short4(float x, float y, float z, float w) /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Short4 left, Short4 right) => !left.Equals(right); /// - public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Rgba32 ToRgba32() => Rgba32.FromScaledVector4(this.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromScaledVector4(Vector4 vector) - { - vector *= 65534F; - vector -= new Vector4(32767F); - this.FromVector4(vector); - } - - /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Vector4 ToScaledVector4() { - var scaled = this.ToVector4(); - scaled += new Vector4(32767F); - scaled /= 65534F; + Vector4 scaled = this.ToVector4(); + scaled += new Vector4(32767f); + scaled /= 65534f; return scaled; } /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector); - - /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Vector4 ToVector4() - { - return new Vector4( + => new( (short)(this.PackedValue & 0xFFFF), (short)((this.PackedValue >> 0x10) & 0xFFFF), (short)((this.PackedValue >> 0x20) & 0xFFFF), (short)((this.PackedValue >> 0x30) & 0xFFFF)); + + /// + public static PixelTypeInfo GetPixelTypeInfo() + => PixelTypeInfo.Create( + PixelComponentInfo.Create(4, 16, 16, 16, 16), + PixelColorType.RGB | PixelColorType.Alpha, + PixelAlphaRepresentation.Unassociated); + + /// + public static PixelOperations CreatePixelOperations() => new PixelOperations(); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Short4 FromScaledVector4(Vector4 source) + { + source *= 65534F; + source -= new Vector4(32767F); + return FromVector4(source); } /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromArgb32(Argb32 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Short4 FromVector4(Vector4 source) => new(source); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgr24(Bgr24 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Short4 FromAbgr32(Abgr32 source) => FromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Short4 FromArgb32(Argb32 source) => FromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromAbgr32(Abgr32 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Short4 FromBgra5551(Bgra5551 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Short4 FromBgr24(Bgr24 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL8(L8 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Short4 FromBgra32(Bgra32 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL16(L16 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Short4 FromL8(L8 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa16(La16 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Short4 FromL16(L16 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa32(La32 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Short4 FromLa16(La16 source) => FromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb24(Rgb24 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Short4 FromLa32(La32 source) => FromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba32(Rgba32 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Short4 FromRgb24(Rgb24 source) => FromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void ToRgba32(ref Rgba32 dest) - { - dest.FromScaledVector4(this.ToScaledVector4()); - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Short4 FromRgba32(Rgba32 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb48(Rgb48 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Short4 FromRgb48(Rgb48 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Short4 FromRgba64(Rgba64 source) => FromScaledVector4(source.ToScaledVector4()); /// public override readonly bool Equals(object? obj) => obj is Short4 other && this.Equals(other); /// - [MethodImpl(InliningOptions.ShortMethod)] public readonly bool Equals(Short4 other) => this.PackedValue.Equals(other.PackedValue); /// /// Gets the hash code for the current instance. /// /// Hash code for the instance. - [MethodImpl(InliningOptions.ShortMethod)] public override readonly int GetHashCode() => this.PackedValue.GetHashCode(); /// public override readonly string ToString() { - var vector = this.ToVector4(); + Vector4 vector = this.ToVector4(); return FormattableString.Invariant($"Short4({vector.X:#0.##}, {vector.Y:#0.##}, {vector.Z:#0.##}, {vector.W:#0.##})"); } - [MethodImpl(InliningOptions.ShortMethod)] - private static ulong Pack(ref Vector4 vector) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static ulong Pack(Vector4 vector) { - vector = Numerics.Clamp(vector, Min, Max); - // Clamp the value between min and max values + vector = Numerics.Clamp(vector, Min, Max); 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; diff --git a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.cs b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.cs index 7e84bd6392..712d43f760 100644 --- a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.cs @@ -14,20 +14,17 @@ public partial class PixelOperations /// /// A to configure internal operations. /// The source of data. - /// The to the destination pixels. - public virtual void FromArgb32(Configuration configuration, ReadOnlySpan source, Span destinationPixels) + /// The to the destination pixels. + public virtual void FromArgb32(Configuration configuration, ReadOnlySpan source, Span destination) { - Guard.DestinationShouldNotBeTooShort(source, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Argb32 sourceBaseRef = ref MemoryMarshal.GetReference(source); - ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Argb32 sourceBase = ref MemoryMarshal.GetReference(source); + ref TPixel destinationBase = ref MemoryMarshal.GetReference(destination); for (nuint i = 0; i < (uint)source.Length; i++) { - ref Argb32 sp = ref Unsafe.Add(ref sourceBaseRef, i); - ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); - - dp.FromArgb32(sp); + Unsafe.Add(ref destinationBase, i) = TPixel.FromArgb32(Unsafe.Add(ref sourceBase, i)); } } @@ -37,48 +34,45 @@ public virtual void FromArgb32(Configuration configuration, ReadOnlySpan /// /// A to configure internal operations. /// The to the source bytes. - /// The to the destination pixels. + /// The to the destination pixels. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void FromArgb32Bytes(Configuration configuration, ReadOnlySpan sourceBytes, Span destinationPixels, int count) + public void FromArgb32Bytes(Configuration configuration, ReadOnlySpan sourceBytes, Span destination, int count) { - this.FromArgb32(configuration, MemoryMarshal.Cast(sourceBytes).Slice(0, count), destinationPixels); + this.FromArgb32(configuration, MemoryMarshal.Cast(sourceBytes).Slice(0, count), destination); } /// - /// Converts all pixels of the 'sourcePixels` span to a span of -s. + /// Converts all pixels of the 'source` span to a span of -s. /// /// A to configure internal operations - /// The span of source pixels - /// The destination span of data. - public virtual void ToArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destinationPixels) + /// The span of source pixels + /// The destination span of data. + public virtual void ToArgb32(Configuration configuration, ReadOnlySpan source, Span destination) { - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Argb32 destBaseRef = ref MemoryMarshal.GetReference(destinationPixels); + ref TPixel sourceBase = ref MemoryMarshal.GetReference(source); + ref Argb32 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); - ref Argb32 dp = ref Unsafe.Add(ref destBaseRef, i); - - dp.FromScaledVector4(sp.ToScaledVector4()); + Unsafe.Add(ref destinationBase, i) = Argb32.FromScaledVector4(Unsafe.Add(ref sourceBase, i).ToScaledVector4()); } } /// /// A helper for that expects a byte span as destination. - /// The layout of the data in 'destBytes' must be compatible with layout. + /// The layout of the data in 'destination' must be compatible with layout. /// /// A to configure internal operations - /// The to the source pixels. - /// The to the destination bytes. + /// The to the source pixels. + /// The to the destination bytes. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToArgb32Bytes(Configuration configuration, ReadOnlySpan sourcePixels, Span destBytes, int count) + public void ToArgb32Bytes(Configuration configuration, ReadOnlySpan source, Span destination, int count) { - this.ToArgb32(configuration, sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); + this.ToArgb32(configuration, source.Slice(0, count), MemoryMarshal.Cast(destination)); } /// @@ -86,20 +80,17 @@ public void ToArgb32Bytes(Configuration configuration, ReadOnlySpan sour /// /// A to configure internal operations. /// The source of data. - /// The to the destination pixels. - public virtual void FromAbgr32(Configuration configuration, ReadOnlySpan source, Span destinationPixels) + /// The to the destination pixels. + public virtual void FromAbgr32(Configuration configuration, ReadOnlySpan source, Span destination) { - Guard.DestinationShouldNotBeTooShort(source, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Abgr32 sourceBaseRef = ref MemoryMarshal.GetReference(source); - ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Abgr32 sourceBase = ref MemoryMarshal.GetReference(source); + ref TPixel destinationBase = ref MemoryMarshal.GetReference(destination); for (nuint i = 0; i < (uint)source.Length; i++) { - ref Abgr32 sp = ref Unsafe.Add(ref sourceBaseRef, i); - ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); - - dp.FromAbgr32(sp); + Unsafe.Add(ref destinationBase, i) = TPixel.FromAbgr32(Unsafe.Add(ref sourceBase, i)); } } @@ -109,48 +100,45 @@ public virtual void FromAbgr32(Configuration configuration, ReadOnlySpan /// /// A to configure internal operations. /// The to the source bytes. - /// The to the destination pixels. + /// The to the destination pixels. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void FromAbgr32Bytes(Configuration configuration, ReadOnlySpan sourceBytes, Span destinationPixels, int count) + public void FromAbgr32Bytes(Configuration configuration, ReadOnlySpan sourceBytes, Span destination, int count) { - this.FromAbgr32(configuration, MemoryMarshal.Cast(sourceBytes).Slice(0, count), destinationPixels); + this.FromAbgr32(configuration, MemoryMarshal.Cast(sourceBytes).Slice(0, count), destination); } /// - /// Converts all pixels of the 'sourcePixels` span to a span of -s. + /// Converts all pixels of the 'source` span to a span of -s. /// /// A to configure internal operations - /// The span of source pixels - /// The destination span of data. - public virtual void ToAbgr32(Configuration configuration, ReadOnlySpan sourcePixels, Span destinationPixels) + /// The span of source pixels + /// The destination span of data. + public virtual void ToAbgr32(Configuration configuration, ReadOnlySpan source, Span destination) { - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Abgr32 destBaseRef = ref MemoryMarshal.GetReference(destinationPixels); + ref TPixel sourceBase = ref MemoryMarshal.GetReference(source); + ref Abgr32 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); - ref Abgr32 dp = ref Unsafe.Add(ref destBaseRef, i); - - dp.FromScaledVector4(sp.ToScaledVector4()); + Unsafe.Add(ref destinationBase, i) = Abgr32.FromScaledVector4(Unsafe.Add(ref sourceBase, i).ToScaledVector4()); } } /// /// A helper for that expects a byte span as destination. - /// The layout of the data in 'destBytes' must be compatible with layout. + /// The layout of the data in 'destination' must be compatible with layout. /// /// A to configure internal operations - /// The to the source pixels. - /// The to the destination bytes. + /// The to the source pixels. + /// The to the destination bytes. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToAbgr32Bytes(Configuration configuration, ReadOnlySpan sourcePixels, Span destBytes, int count) + public void ToAbgr32Bytes(Configuration configuration, ReadOnlySpan source, Span destination, int count) { - this.ToAbgr32(configuration, sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); + this.ToAbgr32(configuration, source.Slice(0, count), MemoryMarshal.Cast(destination)); } /// @@ -158,20 +146,17 @@ public void ToAbgr32Bytes(Configuration configuration, ReadOnlySpan sour /// /// A to configure internal operations. /// The source of data. - /// The to the destination pixels. - public virtual void FromBgr24(Configuration configuration, ReadOnlySpan source, Span destinationPixels) + /// The to the destination pixels. + public virtual void FromBgr24(Configuration configuration, ReadOnlySpan source, Span destination) { - Guard.DestinationShouldNotBeTooShort(source, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Bgr24 sourceBaseRef = ref MemoryMarshal.GetReference(source); - ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Bgr24 sourceBase = ref MemoryMarshal.GetReference(source); + ref TPixel destinationBase = ref MemoryMarshal.GetReference(destination); for (nuint i = 0; i < (uint)source.Length; i++) { - ref Bgr24 sp = ref Unsafe.Add(ref sourceBaseRef, i); - ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); - - dp.FromBgr24(sp); + Unsafe.Add(ref destinationBase, i) = TPixel.FromBgr24(Unsafe.Add(ref sourceBase, i)); } } @@ -181,48 +166,45 @@ public virtual void FromBgr24(Configuration configuration, ReadOnlySpan s /// /// A to configure internal operations. /// The to the source bytes. - /// The to the destination pixels. + /// The to the destination pixels. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void FromBgr24Bytes(Configuration configuration, ReadOnlySpan sourceBytes, Span destinationPixels, int count) + public void FromBgr24Bytes(Configuration configuration, ReadOnlySpan sourceBytes, Span destination, int count) { - this.FromBgr24(configuration, MemoryMarshal.Cast(sourceBytes).Slice(0, count), destinationPixels); + this.FromBgr24(configuration, MemoryMarshal.Cast(sourceBytes).Slice(0, count), destination); } /// - /// Converts all pixels of the 'sourcePixels` span to a span of -s. + /// Converts all pixels of the 'source` span to a span of -s. /// /// A to configure internal operations - /// The span of source pixels - /// The destination span of data. - public virtual void ToBgr24(Configuration configuration, ReadOnlySpan sourcePixels, Span destinationPixels) + /// The span of source pixels + /// The destination span of data. + public virtual void ToBgr24(Configuration configuration, ReadOnlySpan source, Span destination) { - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Bgr24 destBaseRef = ref MemoryMarshal.GetReference(destinationPixels); + ref TPixel sourceBase = ref MemoryMarshal.GetReference(source); + ref Bgr24 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); - ref Bgr24 dp = ref Unsafe.Add(ref destBaseRef, i); - - dp.FromScaledVector4(sp.ToScaledVector4()); + Unsafe.Add(ref destinationBase, i) = Bgr24.FromScaledVector4(Unsafe.Add(ref sourceBase, i).ToScaledVector4()); } } /// /// A helper for that expects a byte span as destination. - /// The layout of the data in 'destBytes' must be compatible with layout. + /// The layout of the data in 'destination' must be compatible with layout. /// /// A to configure internal operations - /// The to the source pixels. - /// The to the destination bytes. + /// The to the source pixels. + /// The to the destination bytes. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgr24Bytes(Configuration configuration, ReadOnlySpan sourcePixels, Span destBytes, int count) + public void ToBgr24Bytes(Configuration configuration, ReadOnlySpan source, Span destination, int count) { - this.ToBgr24(configuration, sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); + this.ToBgr24(configuration, source.Slice(0, count), MemoryMarshal.Cast(destination)); } /// @@ -230,20 +212,17 @@ public void ToBgr24Bytes(Configuration configuration, ReadOnlySpan sourc /// /// A to configure internal operations. /// The source of data. - /// The to the destination pixels. - public virtual void FromBgra32(Configuration configuration, ReadOnlySpan source, Span destinationPixels) + /// The to the destination pixels. + public virtual void FromBgra32(Configuration configuration, ReadOnlySpan source, Span destination) { - Guard.DestinationShouldNotBeTooShort(source, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Bgra32 sourceBaseRef = ref MemoryMarshal.GetReference(source); - ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Bgra32 sourceBase = ref MemoryMarshal.GetReference(source); + ref TPixel destinationBase = ref MemoryMarshal.GetReference(destination); for (nuint i = 0; i < (uint)source.Length; i++) { - ref Bgra32 sp = ref Unsafe.Add(ref sourceBaseRef, i); - ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); - - dp.FromBgra32(sp); + Unsafe.Add(ref destinationBase, i) = TPixel.FromBgra32(Unsafe.Add(ref sourceBase, i)); } } @@ -253,48 +232,45 @@ public virtual void FromBgra32(Configuration configuration, ReadOnlySpan /// /// A to configure internal operations. /// The to the source bytes. - /// The to the destination pixels. + /// The to the destination pixels. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void FromBgra32Bytes(Configuration configuration, ReadOnlySpan sourceBytes, Span destinationPixels, int count) + public void FromBgra32Bytes(Configuration configuration, ReadOnlySpan sourceBytes, Span destination, int count) { - this.FromBgra32(configuration, MemoryMarshal.Cast(sourceBytes).Slice(0, count), destinationPixels); + this.FromBgra32(configuration, MemoryMarshal.Cast(sourceBytes).Slice(0, count), destination); } /// - /// Converts all pixels of the 'sourcePixels` span to a span of -s. + /// Converts all pixels of the 'source` span to a span of -s. /// /// A to configure internal operations - /// The span of source pixels - /// The destination span of data. - public virtual void ToBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destinationPixels) + /// The span of source pixels + /// The destination span of data. + public virtual void ToBgra32(Configuration configuration, ReadOnlySpan source, Span destination) { - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Bgra32 destBaseRef = ref MemoryMarshal.GetReference(destinationPixels); + ref TPixel sourceBase = ref MemoryMarshal.GetReference(source); + ref Bgra32 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); - ref Bgra32 dp = ref Unsafe.Add(ref destBaseRef, i); - - dp.FromScaledVector4(sp.ToScaledVector4()); + Unsafe.Add(ref destinationBase, i) = Bgra32.FromScaledVector4(Unsafe.Add(ref sourceBase, i).ToScaledVector4()); } } /// /// A helper for that expects a byte span as destination. - /// The layout of the data in 'destBytes' must be compatible with layout. + /// The layout of the data in 'destination' must be compatible with layout. /// /// A to configure internal operations - /// The to the source pixels. - /// The to the destination bytes. + /// The to the source pixels. + /// The to the destination bytes. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgra32Bytes(Configuration configuration, ReadOnlySpan sourcePixels, Span destBytes, int count) + public void ToBgra32Bytes(Configuration configuration, ReadOnlySpan source, Span destination, int count) { - this.ToBgra32(configuration, sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); + this.ToBgra32(configuration, source.Slice(0, count), MemoryMarshal.Cast(destination)); } /// @@ -302,20 +278,17 @@ public void ToBgra32Bytes(Configuration configuration, ReadOnlySpan sour /// /// A to configure internal operations. /// The source of data. - /// The to the destination pixels. - public virtual void FromL8(Configuration configuration, ReadOnlySpan source, Span destinationPixels) + /// The to the destination pixels. + public virtual void FromL8(Configuration configuration, ReadOnlySpan source, Span destination) { - Guard.DestinationShouldNotBeTooShort(source, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref L8 sourceBaseRef = ref MemoryMarshal.GetReference(source); - ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destinationPixels); + ref L8 sourceBase = ref MemoryMarshal.GetReference(source); + ref TPixel destinationBase = ref MemoryMarshal.GetReference(destination); for (nuint i = 0; i < (uint)source.Length; i++) { - ref L8 sp = ref Unsafe.Add(ref sourceBaseRef, i); - ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); - - dp.FromL8(sp); + Unsafe.Add(ref destinationBase, i) = TPixel.FromL8(Unsafe.Add(ref sourceBase, i)); } } @@ -325,48 +298,45 @@ public virtual void FromL8(Configuration configuration, ReadOnlySpan source, /// /// A to configure internal operations. /// The to the source bytes. - /// The to the destination pixels. + /// The to the destination pixels. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void FromL8Bytes(Configuration configuration, ReadOnlySpan sourceBytes, Span destinationPixels, int count) + public void FromL8Bytes(Configuration configuration, ReadOnlySpan sourceBytes, Span destination, int count) { - this.FromL8(configuration, MemoryMarshal.Cast(sourceBytes).Slice(0, count), destinationPixels); + this.FromL8(configuration, MemoryMarshal.Cast(sourceBytes).Slice(0, count), destination); } /// - /// Converts all pixels of the 'sourcePixels` span to a span of -s. + /// Converts all pixels of the 'source` span to a span of -s. /// /// A to configure internal operations - /// The span of source pixels - /// The destination span of data. - public virtual void ToL8(Configuration configuration, ReadOnlySpan sourcePixels, Span destinationPixels) + /// The span of source pixels + /// The destination span of data. + public virtual void ToL8(Configuration configuration, ReadOnlySpan source, Span destination) { - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); - ref L8 destBaseRef = ref MemoryMarshal.GetReference(destinationPixels); + ref TPixel sourceBase = ref MemoryMarshal.GetReference(source); + ref L8 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); - ref L8 dp = ref Unsafe.Add(ref destBaseRef, i); - - dp.FromScaledVector4(sp.ToScaledVector4()); + Unsafe.Add(ref destinationBase, i) = L8.FromScaledVector4(Unsafe.Add(ref sourceBase, i).ToScaledVector4()); } } /// /// A helper for that expects a byte span as destination. - /// The layout of the data in 'destBytes' must be compatible with layout. + /// The layout of the data in 'destination' must be compatible with layout. /// /// A to configure internal operations - /// The to the source pixels. - /// The to the destination bytes. + /// The to the source pixels. + /// The to the destination bytes. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToL8Bytes(Configuration configuration, ReadOnlySpan sourcePixels, Span destBytes, int count) + public void ToL8Bytes(Configuration configuration, ReadOnlySpan source, Span destination, int count) { - this.ToL8(configuration, sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); + this.ToL8(configuration, source.Slice(0, count), MemoryMarshal.Cast(destination)); } /// @@ -374,20 +344,17 @@ public void ToL8Bytes(Configuration configuration, ReadOnlySpan sourcePi /// /// A to configure internal operations. /// The source of data. - /// The to the destination pixels. - public virtual void FromL16(Configuration configuration, ReadOnlySpan source, Span destinationPixels) + /// The to the destination pixels. + public virtual void FromL16(Configuration configuration, ReadOnlySpan source, Span destination) { - Guard.DestinationShouldNotBeTooShort(source, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref L16 sourceBaseRef = ref MemoryMarshal.GetReference(source); - ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destinationPixels); + ref L16 sourceBase = ref MemoryMarshal.GetReference(source); + ref TPixel destinationBase = ref MemoryMarshal.GetReference(destination); for (nuint i = 0; i < (uint)source.Length; i++) { - ref L16 sp = ref Unsafe.Add(ref sourceBaseRef, i); - ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); - - dp.FromL16(sp); + Unsafe.Add(ref destinationBase, i) = TPixel.FromL16(Unsafe.Add(ref sourceBase, i)); } } @@ -397,48 +364,45 @@ public virtual void FromL16(Configuration configuration, ReadOnlySpan sourc /// /// A to configure internal operations. /// The to the source bytes. - /// The to the destination pixels. + /// The to the destination pixels. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void FromL16Bytes(Configuration configuration, ReadOnlySpan sourceBytes, Span destinationPixels, int count) + public void FromL16Bytes(Configuration configuration, ReadOnlySpan sourceBytes, Span destination, int count) { - this.FromL16(configuration, MemoryMarshal.Cast(sourceBytes).Slice(0, count), destinationPixels); + this.FromL16(configuration, MemoryMarshal.Cast(sourceBytes).Slice(0, count), destination); } /// - /// Converts all pixels of the 'sourcePixels` span to a span of -s. + /// Converts all pixels of the 'source` span to a span of -s. /// /// A to configure internal operations - /// The span of source pixels - /// The destination span of data. - public virtual void ToL16(Configuration configuration, ReadOnlySpan sourcePixels, Span destinationPixels) + /// The span of source pixels + /// The destination span of data. + public virtual void ToL16(Configuration configuration, ReadOnlySpan source, Span destination) { - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); - ref L16 destBaseRef = ref MemoryMarshal.GetReference(destinationPixels); + ref TPixel sourceBase = ref MemoryMarshal.GetReference(source); + ref L16 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); - ref L16 dp = ref Unsafe.Add(ref destBaseRef, i); - - dp.FromScaledVector4(sp.ToScaledVector4()); + Unsafe.Add(ref destinationBase, i) = L16.FromScaledVector4(Unsafe.Add(ref sourceBase, i).ToScaledVector4()); } } /// /// A helper for that expects a byte span as destination. - /// The layout of the data in 'destBytes' must be compatible with layout. + /// The layout of the data in 'destination' must be compatible with layout. /// /// A to configure internal operations - /// The to the source pixels. - /// The to the destination bytes. + /// The to the source pixels. + /// The to the destination bytes. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToL16Bytes(Configuration configuration, ReadOnlySpan sourcePixels, Span destBytes, int count) + public void ToL16Bytes(Configuration configuration, ReadOnlySpan source, Span destination, int count) { - this.ToL16(configuration, sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); + this.ToL16(configuration, source.Slice(0, count), MemoryMarshal.Cast(destination)); } /// @@ -446,20 +410,17 @@ public void ToL16Bytes(Configuration configuration, ReadOnlySpan sourceP /// /// A to configure internal operations. /// The source of data. - /// The to the destination pixels. - public virtual void FromLa16(Configuration configuration, ReadOnlySpan source, Span destinationPixels) + /// The to the destination pixels. + public virtual void FromLa16(Configuration configuration, ReadOnlySpan source, Span destination) { - Guard.DestinationShouldNotBeTooShort(source, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref La16 sourceBaseRef = ref MemoryMarshal.GetReference(source); - ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destinationPixels); + ref La16 sourceBase = ref MemoryMarshal.GetReference(source); + ref TPixel destinationBase = ref MemoryMarshal.GetReference(destination); for (nuint i = 0; i < (uint)source.Length; i++) { - ref La16 sp = ref Unsafe.Add(ref sourceBaseRef, i); - ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); - - dp.FromLa16(sp); + Unsafe.Add(ref destinationBase, i) = TPixel.FromLa16(Unsafe.Add(ref sourceBase, i)); } } @@ -469,48 +430,45 @@ public virtual void FromLa16(Configuration configuration, ReadOnlySpan sou /// /// A to configure internal operations. /// The to the source bytes. - /// The to the destination pixels. + /// The to the destination pixels. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void FromLa16Bytes(Configuration configuration, ReadOnlySpan sourceBytes, Span destinationPixels, int count) + public void FromLa16Bytes(Configuration configuration, ReadOnlySpan sourceBytes, Span destination, int count) { - this.FromLa16(configuration, MemoryMarshal.Cast(sourceBytes).Slice(0, count), destinationPixels); + this.FromLa16(configuration, MemoryMarshal.Cast(sourceBytes).Slice(0, count), destination); } /// - /// Converts all pixels of the 'sourcePixels` span to a span of -s. + /// Converts all pixels of the 'source` span to a span of -s. /// /// A to configure internal operations - /// The span of source pixels - /// The destination span of data. - public virtual void ToLa16(Configuration configuration, ReadOnlySpan sourcePixels, Span destinationPixels) + /// The span of source pixels + /// The destination span of data. + public virtual void ToLa16(Configuration configuration, ReadOnlySpan source, Span destination) { - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); - ref La16 destBaseRef = ref MemoryMarshal.GetReference(destinationPixels); + ref TPixel sourceBase = ref MemoryMarshal.GetReference(source); + ref La16 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); - ref La16 dp = ref Unsafe.Add(ref destBaseRef, i); - - dp.FromScaledVector4(sp.ToScaledVector4()); + Unsafe.Add(ref destinationBase, i) = La16.FromScaledVector4(Unsafe.Add(ref sourceBase, i).ToScaledVector4()); } } /// /// A helper for that expects a byte span as destination. - /// The layout of the data in 'destBytes' must be compatible with layout. + /// The layout of the data in 'destination' must be compatible with layout. /// /// A to configure internal operations - /// The to the source pixels. - /// The to the destination bytes. + /// The to the source pixels. + /// The to the destination bytes. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToLa16Bytes(Configuration configuration, ReadOnlySpan sourcePixels, Span destBytes, int count) + public void ToLa16Bytes(Configuration configuration, ReadOnlySpan source, Span destination, int count) { - this.ToLa16(configuration, sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); + this.ToLa16(configuration, source.Slice(0, count), MemoryMarshal.Cast(destination)); } /// @@ -518,20 +476,17 @@ public void ToLa16Bytes(Configuration configuration, ReadOnlySpan source /// /// A to configure internal operations. /// The source of data. - /// The to the destination pixels. - public virtual void FromLa32(Configuration configuration, ReadOnlySpan source, Span destinationPixels) + /// The to the destination pixels. + public virtual void FromLa32(Configuration configuration, ReadOnlySpan source, Span destination) { - Guard.DestinationShouldNotBeTooShort(source, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref La32 sourceBaseRef = ref MemoryMarshal.GetReference(source); - ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destinationPixels); + ref La32 sourceBase = ref MemoryMarshal.GetReference(source); + ref TPixel destinationBase = ref MemoryMarshal.GetReference(destination); for (nuint i = 0; i < (uint)source.Length; i++) { - ref La32 sp = ref Unsafe.Add(ref sourceBaseRef, i); - ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); - - dp.FromLa32(sp); + Unsafe.Add(ref destinationBase, i) = TPixel.FromLa32(Unsafe.Add(ref sourceBase, i)); } } @@ -541,48 +496,45 @@ public virtual void FromLa32(Configuration configuration, ReadOnlySpan sou /// /// A to configure internal operations. /// The to the source bytes. - /// The to the destination pixels. + /// The to the destination pixels. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void FromLa32Bytes(Configuration configuration, ReadOnlySpan sourceBytes, Span destinationPixels, int count) + public void FromLa32Bytes(Configuration configuration, ReadOnlySpan sourceBytes, Span destination, int count) { - this.FromLa32(configuration, MemoryMarshal.Cast(sourceBytes).Slice(0, count), destinationPixels); + this.FromLa32(configuration, MemoryMarshal.Cast(sourceBytes).Slice(0, count), destination); } /// - /// Converts all pixels of the 'sourcePixels` span to a span of -s. + /// Converts all pixels of the 'source` span to a span of -s. /// /// A to configure internal operations - /// The span of source pixels - /// The destination span of data. - public virtual void ToLa32(Configuration configuration, ReadOnlySpan sourcePixels, Span destinationPixels) + /// The span of source pixels + /// The destination span of data. + public virtual void ToLa32(Configuration configuration, ReadOnlySpan source, Span destination) { - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); - ref La32 destBaseRef = ref MemoryMarshal.GetReference(destinationPixels); + ref TPixel sourceBase = ref MemoryMarshal.GetReference(source); + ref La32 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); - ref La32 dp = ref Unsafe.Add(ref destBaseRef, i); - - dp.FromScaledVector4(sp.ToScaledVector4()); + Unsafe.Add(ref destinationBase, i) = La32.FromScaledVector4(Unsafe.Add(ref sourceBase, i).ToScaledVector4()); } } /// /// A helper for that expects a byte span as destination. - /// The layout of the data in 'destBytes' must be compatible with layout. + /// The layout of the data in 'destination' must be compatible with layout. /// /// A to configure internal operations - /// The to the source pixels. - /// The to the destination bytes. + /// The to the source pixels. + /// The to the destination bytes. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToLa32Bytes(Configuration configuration, ReadOnlySpan sourcePixels, Span destBytes, int count) + public void ToLa32Bytes(Configuration configuration, ReadOnlySpan source, Span destination, int count) { - this.ToLa32(configuration, sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); + this.ToLa32(configuration, source.Slice(0, count), MemoryMarshal.Cast(destination)); } /// @@ -590,20 +542,17 @@ public void ToLa32Bytes(Configuration configuration, ReadOnlySpan source /// /// A to configure internal operations. /// The source of data. - /// The to the destination pixels. - public virtual void FromRgb24(Configuration configuration, ReadOnlySpan source, Span destinationPixels) + /// The to the destination pixels. + public virtual void FromRgb24(Configuration configuration, ReadOnlySpan source, Span destination) { - Guard.DestinationShouldNotBeTooShort(source, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Rgb24 sourceBaseRef = ref MemoryMarshal.GetReference(source); - ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Rgb24 sourceBase = ref MemoryMarshal.GetReference(source); + ref TPixel destinationBase = ref MemoryMarshal.GetReference(destination); for (nuint i = 0; i < (uint)source.Length; i++) { - ref Rgb24 sp = ref Unsafe.Add(ref sourceBaseRef, i); - ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); - - dp.FromRgb24(sp); + Unsafe.Add(ref destinationBase, i) = TPixel.FromRgb24(Unsafe.Add(ref sourceBase, i)); } } @@ -613,48 +562,45 @@ public virtual void FromRgb24(Configuration configuration, ReadOnlySpan s /// /// A to configure internal operations. /// The to the source bytes. - /// The to the destination pixels. + /// The to the destination pixels. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void FromRgb24Bytes(Configuration configuration, ReadOnlySpan sourceBytes, Span destinationPixels, int count) + public void FromRgb24Bytes(Configuration configuration, ReadOnlySpan sourceBytes, Span destination, int count) { - this.FromRgb24(configuration, MemoryMarshal.Cast(sourceBytes).Slice(0, count), destinationPixels); + this.FromRgb24(configuration, MemoryMarshal.Cast(sourceBytes).Slice(0, count), destination); } /// - /// Converts all pixels of the 'sourcePixels` span to a span of -s. + /// Converts all pixels of the 'source` span to a span of -s. /// /// A to configure internal operations - /// The span of source pixels - /// The destination span of data. - public virtual void ToRgb24(Configuration configuration, ReadOnlySpan sourcePixels, Span destinationPixels) + /// The span of source pixels + /// The destination span of data. + public virtual void ToRgb24(Configuration configuration, ReadOnlySpan source, Span destination) { - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgb24 destBaseRef = ref MemoryMarshal.GetReference(destinationPixels); + ref TPixel sourceBase = ref MemoryMarshal.GetReference(source); + ref Rgb24 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); - ref Rgb24 dp = ref Unsafe.Add(ref destBaseRef, i); - - dp.FromScaledVector4(sp.ToScaledVector4()); + Unsafe.Add(ref destinationBase, i) = Rgb24.FromScaledVector4(Unsafe.Add(ref sourceBase, i).ToScaledVector4()); } } /// /// A helper for that expects a byte span as destination. - /// The layout of the data in 'destBytes' must be compatible with layout. + /// The layout of the data in 'destination' must be compatible with layout. /// /// A to configure internal operations - /// The to the source pixels. - /// The to the destination bytes. + /// The to the source pixels. + /// The to the destination bytes. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24Bytes(Configuration configuration, ReadOnlySpan sourcePixels, Span destBytes, int count) + public void ToRgb24Bytes(Configuration configuration, ReadOnlySpan source, Span destination, int count) { - this.ToRgb24(configuration, sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); + this.ToRgb24(configuration, source.Slice(0, count), MemoryMarshal.Cast(destination)); } /// @@ -662,20 +608,17 @@ public void ToRgb24Bytes(Configuration configuration, ReadOnlySpan sourc /// /// A to configure internal operations. /// The source of data. - /// The to the destination pixels. - public virtual void FromRgba32(Configuration configuration, ReadOnlySpan source, Span destinationPixels) + /// The to the destination pixels. + public virtual void FromRgba32(Configuration configuration, ReadOnlySpan source, Span destination) { - Guard.DestinationShouldNotBeTooShort(source, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Rgba32 sourceBaseRef = ref MemoryMarshal.GetReference(source); - ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Rgba32 sourceBase = ref MemoryMarshal.GetReference(source); + ref TPixel destinationBase = ref MemoryMarshal.GetReference(destination); for (nuint i = 0; i < (uint)source.Length; i++) { - ref Rgba32 sp = ref Unsafe.Add(ref sourceBaseRef, i); - ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); - - dp.FromRgba32(sp); + Unsafe.Add(ref destinationBase, i) = TPixel.FromRgba32(Unsafe.Add(ref sourceBase, i)); } } @@ -685,48 +628,45 @@ public virtual void FromRgba32(Configuration configuration, ReadOnlySpan /// /// A to configure internal operations. /// The to the source bytes. - /// The to the destination pixels. + /// The to the destination pixels. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void FromRgba32Bytes(Configuration configuration, ReadOnlySpan sourceBytes, Span destinationPixels, int count) + public void FromRgba32Bytes(Configuration configuration, ReadOnlySpan sourceBytes, Span destination, int count) { - this.FromRgba32(configuration, MemoryMarshal.Cast(sourceBytes).Slice(0, count), destinationPixels); + this.FromRgba32(configuration, MemoryMarshal.Cast(sourceBytes).Slice(0, count), destination); } /// - /// Converts all pixels of the 'sourcePixels` span to a span of -s. + /// Converts all pixels of the 'source` span to a span of -s. /// /// A to configure internal operations - /// The span of source pixels - /// The destination span of data. - public virtual void ToRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destinationPixels) + /// The span of source pixels + /// The destination span of data. + public virtual void ToRgba32(Configuration configuration, ReadOnlySpan source, Span destination) { - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgba32 destBaseRef = ref MemoryMarshal.GetReference(destinationPixels); + ref TPixel sourceBase = ref MemoryMarshal.GetReference(source); + ref Rgba32 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); - ref Rgba32 dp = ref Unsafe.Add(ref destBaseRef, i); - - dp.FromScaledVector4(sp.ToScaledVector4()); + Unsafe.Add(ref destinationBase, i) = Rgba32.FromScaledVector4(Unsafe.Add(ref sourceBase, i).ToScaledVector4()); } } /// /// A helper for that expects a byte span as destination. - /// The layout of the data in 'destBytes' must be compatible with layout. + /// The layout of the data in 'destination' must be compatible with layout. /// /// A to configure internal operations - /// The to the source pixels. - /// The to the destination bytes. + /// The to the source pixels. + /// The to the destination bytes. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba32Bytes(Configuration configuration, ReadOnlySpan sourcePixels, Span destBytes, int count) + public void ToRgba32Bytes(Configuration configuration, ReadOnlySpan source, Span destination, int count) { - this.ToRgba32(configuration, sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); + this.ToRgba32(configuration, source.Slice(0, count), MemoryMarshal.Cast(destination)); } /// @@ -734,20 +674,17 @@ public void ToRgba32Bytes(Configuration configuration, ReadOnlySpan sour /// /// A to configure internal operations. /// The source of data. - /// The to the destination pixels. - public virtual void FromRgb48(Configuration configuration, ReadOnlySpan source, Span destinationPixels) + /// The to the destination pixels. + public virtual void FromRgb48(Configuration configuration, ReadOnlySpan source, Span destination) { - Guard.DestinationShouldNotBeTooShort(source, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Rgb48 sourceBaseRef = ref MemoryMarshal.GetReference(source); - ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Rgb48 sourceBase = ref MemoryMarshal.GetReference(source); + ref TPixel destinationBase = ref MemoryMarshal.GetReference(destination); for (nuint i = 0; i < (uint)source.Length; i++) { - ref Rgb48 sp = ref Unsafe.Add(ref sourceBaseRef, i); - ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); - - dp.FromRgb48(sp); + Unsafe.Add(ref destinationBase, i) = TPixel.FromRgb48(Unsafe.Add(ref sourceBase, i)); } } @@ -757,48 +694,45 @@ public virtual void FromRgb48(Configuration configuration, ReadOnlySpan s /// /// A to configure internal operations. /// The to the source bytes. - /// The to the destination pixels. + /// The to the destination pixels. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void FromRgb48Bytes(Configuration configuration, ReadOnlySpan sourceBytes, Span destinationPixels, int count) + public void FromRgb48Bytes(Configuration configuration, ReadOnlySpan sourceBytes, Span destination, int count) { - this.FromRgb48(configuration, MemoryMarshal.Cast(sourceBytes).Slice(0, count), destinationPixels); + this.FromRgb48(configuration, MemoryMarshal.Cast(sourceBytes).Slice(0, count), destination); } /// - /// Converts all pixels of the 'sourcePixels` span to a span of -s. + /// Converts all pixels of the 'source` span to a span of -s. /// /// A to configure internal operations - /// The span of source pixels - /// The destination span of data. - public virtual void ToRgb48(Configuration configuration, ReadOnlySpan sourcePixels, Span destinationPixels) + /// The span of source pixels + /// The destination span of data. + public virtual void ToRgb48(Configuration configuration, ReadOnlySpan source, Span destination) { - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgb48 destBaseRef = ref MemoryMarshal.GetReference(destinationPixels); + ref TPixel sourceBase = ref MemoryMarshal.GetReference(source); + ref Rgb48 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); - ref Rgb48 dp = ref Unsafe.Add(ref destBaseRef, i); - - dp.FromScaledVector4(sp.ToScaledVector4()); + Unsafe.Add(ref destinationBase, i) = Rgb48.FromScaledVector4(Unsafe.Add(ref sourceBase, i).ToScaledVector4()); } } /// /// A helper for that expects a byte span as destination. - /// The layout of the data in 'destBytes' must be compatible with layout. + /// The layout of the data in 'destination' must be compatible with layout. /// /// A to configure internal operations - /// The to the source pixels. - /// The to the destination bytes. + /// The to the source pixels. + /// The to the destination bytes. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48Bytes(Configuration configuration, ReadOnlySpan sourcePixels, Span destBytes, int count) + public void ToRgb48Bytes(Configuration configuration, ReadOnlySpan source, Span destination, int count) { - this.ToRgb48(configuration, sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); + this.ToRgb48(configuration, source.Slice(0, count), MemoryMarshal.Cast(destination)); } /// @@ -806,20 +740,17 @@ public void ToRgb48Bytes(Configuration configuration, ReadOnlySpan sourc /// /// A to configure internal operations. /// The source of data. - /// The to the destination pixels. - public virtual void FromRgba64(Configuration configuration, ReadOnlySpan source, Span destinationPixels) + /// The to the destination pixels. + public virtual void FromRgba64(Configuration configuration, ReadOnlySpan source, Span destination) { - Guard.DestinationShouldNotBeTooShort(source, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Rgba64 sourceBaseRef = ref MemoryMarshal.GetReference(source); - ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Rgba64 sourceBase = ref MemoryMarshal.GetReference(source); + ref TPixel destinationBase = ref MemoryMarshal.GetReference(destination); for (nuint i = 0; i < (uint)source.Length; i++) { - ref Rgba64 sp = ref Unsafe.Add(ref sourceBaseRef, i); - ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); - - dp.FromRgba64(sp); + Unsafe.Add(ref destinationBase, i) = TPixel.FromRgba64(Unsafe.Add(ref sourceBase, i)); } } @@ -829,48 +760,45 @@ public virtual void FromRgba64(Configuration configuration, ReadOnlySpan /// /// A to configure internal operations. /// The to the source bytes. - /// The to the destination pixels. + /// The to the destination pixels. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void FromRgba64Bytes(Configuration configuration, ReadOnlySpan sourceBytes, Span destinationPixels, int count) + public void FromRgba64Bytes(Configuration configuration, ReadOnlySpan sourceBytes, Span destination, int count) { - this.FromRgba64(configuration, MemoryMarshal.Cast(sourceBytes).Slice(0, count), destinationPixels); + this.FromRgba64(configuration, MemoryMarshal.Cast(sourceBytes).Slice(0, count), destination); } /// - /// Converts all pixels of the 'sourcePixels` span to a span of -s. + /// Converts all pixels of the 'source` span to a span of -s. /// /// A to configure internal operations - /// The span of source pixels - /// The destination span of data. - public virtual void ToRgba64(Configuration configuration, ReadOnlySpan sourcePixels, Span destinationPixels) + /// The span of source pixels + /// The destination span of data. + public virtual void ToRgba64(Configuration configuration, ReadOnlySpan source, Span destination) { - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgba64 destBaseRef = ref MemoryMarshal.GetReference(destinationPixels); + ref TPixel sourceBase = ref MemoryMarshal.GetReference(source); + ref Rgba64 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); - ref Rgba64 dp = ref Unsafe.Add(ref destBaseRef, i); - - dp.FromScaledVector4(sp.ToScaledVector4()); + Unsafe.Add(ref destinationBase, i) = Rgba64.FromScaledVector4(Unsafe.Add(ref sourceBase, i).ToScaledVector4()); } } /// /// A helper for that expects a byte span as destination. - /// The layout of the data in 'destBytes' must be compatible with layout. + /// The layout of the data in 'destination' must be compatible with layout. /// /// A to configure internal operations - /// The to the source pixels. - /// The to the destination bytes. + /// The to the source pixels. + /// The to the destination bytes. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64Bytes(Configuration configuration, ReadOnlySpan sourcePixels, Span destBytes, int count) + public void ToRgba64Bytes(Configuration configuration, ReadOnlySpan source, Span destination, int count) { - this.ToRgba64(configuration, sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); + this.ToRgba64(configuration, source.Slice(0, count), MemoryMarshal.Cast(destination)); } /// @@ -878,20 +806,17 @@ public void ToRgba64Bytes(Configuration configuration, ReadOnlySpan sour /// /// A to configure internal operations. /// The source of data. - /// The to the destination pixels. - public virtual void FromBgra5551(Configuration configuration, ReadOnlySpan source, Span destinationPixels) + /// The to the destination pixels. + public virtual void FromBgra5551(Configuration configuration, ReadOnlySpan source, Span destination) { - Guard.DestinationShouldNotBeTooShort(source, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Bgra5551 sourceBaseRef = ref MemoryMarshal.GetReference(source); - ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Bgra5551 sourceBase = ref MemoryMarshal.GetReference(source); + ref TPixel destinationBase = ref MemoryMarshal.GetReference(destination); for (nuint i = 0; i < (uint)source.Length; i++) { - ref Bgra5551 sp = ref Unsafe.Add(ref sourceBaseRef, i); - ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); - - dp.FromBgra5551(sp); + Unsafe.Add(ref destinationBase, i) = TPixel.FromBgra5551(Unsafe.Add(ref sourceBase, i)); } } @@ -901,47 +826,44 @@ public virtual void FromBgra5551(Configuration configuration, ReadOnlySpan /// A to configure internal operations. /// The to the source bytes. - /// The to the destination pixels. + /// The to the destination pixels. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void FromBgra5551Bytes(Configuration configuration, ReadOnlySpan sourceBytes, Span destinationPixels, int count) + public void FromBgra5551Bytes(Configuration configuration, ReadOnlySpan sourceBytes, Span destination, int count) { - this.FromBgra5551(configuration, MemoryMarshal.Cast(sourceBytes).Slice(0, count), destinationPixels); + this.FromBgra5551(configuration, MemoryMarshal.Cast(sourceBytes).Slice(0, count), destination); } /// - /// Converts all pixels of the 'sourcePixels` span to a span of -s. + /// Converts all pixels of the 'source` span to a span of -s. /// /// A to configure internal operations - /// The span of source pixels - /// The destination span of data. - public virtual void ToBgra5551(Configuration configuration, ReadOnlySpan sourcePixels, Span destinationPixels) + /// The span of source pixels + /// The destination span of data. + public virtual void ToBgra5551(Configuration configuration, ReadOnlySpan source, Span destination) { - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Bgra5551 destBaseRef = ref MemoryMarshal.GetReference(destinationPixels); + ref TPixel sourceBase = ref MemoryMarshal.GetReference(source); + ref Bgra5551 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); - ref Bgra5551 dp = ref Unsafe.Add(ref destBaseRef, i); - - dp.FromScaledVector4(sp.ToScaledVector4()); + Unsafe.Add(ref destinationBase, i) = Bgra5551.FromScaledVector4(Unsafe.Add(ref sourceBase, i).ToScaledVector4()); } } /// /// A helper for that expects a byte span as destination. - /// The layout of the data in 'destBytes' must be compatible with layout. + /// The layout of the data in 'destination' must be compatible with layout. /// /// A to configure internal operations - /// The to the source pixels. - /// The to the destination bytes. + /// The to the source pixels. + /// The to the destination bytes. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgra5551Bytes(Configuration configuration, ReadOnlySpan sourcePixels, Span destBytes, int count) + public void ToBgra5551Bytes(Configuration configuration, ReadOnlySpan source, Span destination, int count) { - this.ToBgra5551(configuration, sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); + this.ToBgra5551(configuration, source.Slice(0, count), MemoryMarshal.Cast(destination)); } } diff --git a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.tt b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.tt index 8ba3398e39..b2697cb4e4 100644 --- a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.tt @@ -20,20 +20,17 @@ /// /// A to configure internal operations. /// The source of data. - /// The to the destination pixels. - public virtual void From<#=pixelType#>(Configuration configuration, ReadOnlySpan<<#=pixelType#>> source, Span destinationPixels) + /// The to the destination pixels. + public virtual void From<#=pixelType#>(Configuration configuration, ReadOnlySpan<<#=pixelType#>> source, Span destination) { - Guard.DestinationShouldNotBeTooShort(source, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref <#=pixelType#> sourceBaseRef = ref MemoryMarshal.GetReference(source); - ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destinationPixels); + ref <#=pixelType#> sourceBase = ref MemoryMarshal.GetReference(source); + ref TPixel destinationBase = ref MemoryMarshal.GetReference(destination); for (nuint i = 0; i < (uint)source.Length; i++) { - ref <#=pixelType#> sp = ref Unsafe.Add(ref sourceBaseRef, i); - ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); - - dp.From<#=pixelType#>(sp); + Unsafe.Add(ref destinationBase, i) = TPixel.From<#=pixelType#>(Unsafe.Add(ref sourceBase, i)); } } @@ -43,12 +40,12 @@ /// /// A to configure internal operations. /// The to the source bytes. - /// The to the destination pixels. + /// The to the destination pixels. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void From<#=pixelType#>Bytes(Configuration configuration, ReadOnlySpan sourceBytes, Span destinationPixels, int count) + public void From<#=pixelType#>Bytes(Configuration configuration, ReadOnlySpan sourceBytes, Span destination, int count) { - this.From<#=pixelType#>(configuration, MemoryMarshal.Cast>(sourceBytes).Slice(0, count), destinationPixels); + this.From<#=pixelType#>(configuration, MemoryMarshal.Cast>(sourceBytes).Slice(0, count), destination); } <# @@ -58,39 +55,36 @@ { #> /// - /// Converts all pixels of the 'sourcePixels` span to a span of -s. + /// Converts all pixels of the 'source` span to a span of -s. /// /// A to configure internal operations - /// The span of source pixels - /// The destination span of data. - public virtual void To<#=pixelType#>(Configuration configuration, ReadOnlySpan sourcePixels, Span<<#=pixelType#>> destinationPixels) + /// The span of source pixels + /// The destination span of data. + public virtual void To<#=pixelType#>(Configuration configuration, ReadOnlySpan source, Span<<#=pixelType#>> destination) { - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); - ref <#=pixelType#> destBaseRef = ref MemoryMarshal.GetReference(destinationPixels); + ref TPixel sourceBase = ref MemoryMarshal.GetReference(source); + ref <#=pixelType#> destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); - ref <#=pixelType#> dp = ref Unsafe.Add(ref destBaseRef, i); - - dp.FromScaledVector4(sp.ToScaledVector4()); + Unsafe.Add(ref destinationBase, i) = <#=pixelType#>.FromScaledVector4(Unsafe.Add(ref sourceBase, i).ToScaledVector4()); } } /// /// A helper for that expects a byte span as destination. - /// The layout of the data in 'destBytes' must be compatible with layout. + /// The layout of the data in 'destination' must be compatible with layout. /// /// A to configure internal operations - /// The to the source pixels. - /// The to the destination bytes. + /// The to the source pixels. + /// The to the destination bytes. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void To<#=pixelType#>Bytes(Configuration configuration, ReadOnlySpan sourcePixels, Span destBytes, int count) + public void To<#=pixelType#>Bytes(Configuration configuration, ReadOnlySpan source, Span destination, int count) { - this.To<#=pixelType#>(configuration, sourcePixels.Slice(0, count), MemoryMarshal.Cast>(destBytes)); + this.To<#=pixelType#>(configuration, source.Slice(0, count), MemoryMarshal.Cast>(destination)); } <# } diff --git a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs index beebec8283..c769b389d2 100644 --- a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs +++ b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs @@ -5,7 +5,6 @@ using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.Memory; namespace SixLabors.ImageSharp.PixelFormats; @@ -18,8 +17,7 @@ namespace SixLabors.ImageSharp.PixelFormats; public partial class PixelOperations where TPixel : unmanaged, IPixel { - private static readonly Lazy LazyInfo = new(() => PixelTypeInfo.Create(), true); - private static readonly Lazy> LazyInstance = new(() => default(TPixel).CreatePixelOperations(), true); + private static readonly Lazy> LazyInstance = new(TPixel.CreatePixelOperations, true); /// /// Gets the global instance for the pixel type @@ -32,10 +30,10 @@ public partial class PixelOperations /// Gets the pixel type info for the given . /// /// The . - public virtual PixelTypeInfo GetPixelTypeInfo() => LazyInfo.Value; + public PixelTypeInfo GetPixelTypeInfo() => TPixel.GetPixelTypeInfo(); /// - /// Bulk version of converting 'sourceVectors.Length' pixels into 'destinationColors'. + /// Bulk version of converting 'sourceVectors.Length' pixels into 'destinationColors'. /// The method is DESTRUCTIVE altering the contents of . /// /// @@ -44,21 +42,21 @@ public partial class PixelOperations /// /// A to configure internal operations /// The to the source vectors. - /// The to the destination colors. + /// The to the destination colors. /// The to apply during the conversion public virtual void FromVector4Destructive( Configuration configuration, Span sourceVectors, - Span destinationPixels, + Span destination, PixelConversionModifiers modifiers) { Guard.NotNull(configuration, nameof(configuration)); - Utils.Vector4Converters.Default.FromVector4(sourceVectors, destinationPixels, modifiers); + Utils.Vector4Converters.Default.FromVector4(sourceVectors, destination, modifiers); } /// - /// Bulk version of converting 'sourceVectors.Length' pixels into 'destinationColors'. + /// Bulk version of converting 'sourceVectors.Length' pixels into 'destinationColors'. /// The method is DESTRUCTIVE altering the contents of . /// /// @@ -67,77 +65,77 @@ public virtual void FromVector4Destructive( /// /// A to configure internal operations /// The to the source vectors. - /// The to the destination colors. + /// The to the destination colors. public void FromVector4Destructive( Configuration configuration, Span sourceVectors, - Span destinationPixels) - => this.FromVector4Destructive(configuration, sourceVectors, destinationPixels, PixelConversionModifiers.None); + Span destination) + => this.FromVector4Destructive(configuration, sourceVectors, destination, PixelConversionModifiers.None); /// /// Bulk version of converting 'sourceColors.Length' pixels into 'destinationVectors'. /// /// A to configure internal operations - /// The to the source colors. + /// The to the source colors. /// The to the destination vectors. /// The to apply during the conversion public virtual void ToVector4( Configuration configuration, - ReadOnlySpan sourcePixels, + ReadOnlySpan source, Span destinationVectors, PixelConversionModifiers modifiers) { Guard.NotNull(configuration, nameof(configuration)); - Utils.Vector4Converters.Default.ToVector4(sourcePixels, destinationVectors, modifiers); + Utils.Vector4Converters.Default.ToVector4(source, destinationVectors, modifiers); } /// /// Bulk version of converting 'sourceColors.Length' pixels into 'destinationVectors'. /// /// A to configure internal operations - /// The to the source colors. + /// The to the source colors. /// The to the destination vectors. public void ToVector4( Configuration configuration, - ReadOnlySpan sourcePixels, + ReadOnlySpan source, Span destinationVectors) - => this.ToVector4(configuration, sourcePixels, destinationVectors, PixelConversionModifiers.None); + => this.ToVector4(configuration, source, destinationVectors, PixelConversionModifiers.None); /// - /// Bulk operation that copies the to in + /// Bulk operation that copies the to in /// format. /// /// The destination pixel type. /// A to configure internal operations. - /// The to the source pixels. - /// The to the destination pixels. + /// The to the source pixels. + /// The to the destination pixels. public virtual void From( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) where TSourcePixel : unmanaged, IPixel { const int sliceLength = 1024; - int numberOfSlices = sourcePixels.Length / sliceLength; + int numberOfSlices = source.Length / sliceLength; using IMemoryOwner tempVectors = configuration.MemoryAllocator.Allocate(sliceLength); Span vectorSpan = tempVectors.GetSpan(); for (int i = 0; i < numberOfSlices; i++) { int start = i * sliceLength; - ReadOnlySpan s = sourcePixels.Slice(start, sliceLength); - Span d = destinationPixels.Slice(start, sliceLength); + ReadOnlySpan s = source.Slice(start, sliceLength); + Span d = destination.Slice(start, sliceLength); PixelOperations.Instance.ToVector4(configuration, s, vectorSpan, PixelConversionModifiers.Scale); this.FromVector4Destructive(configuration, vectorSpan, d, PixelConversionModifiers.Scale); } int endOfCompleteSlices = numberOfSlices * sliceLength; - int remainder = sourcePixels.Length - endOfCompleteSlices; + int remainder = source.Length - endOfCompleteSlices; if (remainder > 0) { - ReadOnlySpan s = sourcePixels[endOfCompleteSlices..]; - Span d = destinationPixels[endOfCompleteSlices..]; + ReadOnlySpan s = source[endOfCompleteSlices..]; + Span d = destination[endOfCompleteSlices..]; vectorSpan = vectorSpan[..remainder]; PixelOperations.Instance.ToVector4(configuration, s, vectorSpan, PixelConversionModifiers.Scale); this.FromVector4Destructive(configuration, vectorSpan, d, PixelConversionModifiers.Scale); @@ -145,23 +143,23 @@ public virtual void From( } /// - /// Bulk operation that copies the to in + /// Bulk operation that copies the to in /// format. /// /// The destination pixel type. /// A to configure internal operations. - /// The to the source pixels. - /// The to the destination pixels. + /// The to the source pixels. + /// The to the destination pixels. public virtual void To( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) where TDestinationPixel : unmanaged, IPixel { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - PixelOperations.Instance.From(configuration, sourcePixels, destinationPixels); + PixelOperations.Instance.From(configuration, source, destination); } /// @@ -192,7 +190,7 @@ internal virtual void PackFromRgbPlanes( rgb24.R = Unsafe.Add(ref r, i); rgb24.G = Unsafe.Add(ref g, i); rgb24.B = Unsafe.Add(ref b, i); - Unsafe.Add(ref d, i).FromRgb24(rgb24); + Unsafe.Add(ref d, i) = TPixel.FromRgb24(rgb24); } } @@ -214,15 +212,13 @@ internal virtual void UnpackIntoRgbPlanes( int count = source.Length; - Rgba32 rgba32 = default; - ref float r = ref MemoryMarshal.GetReference(redChannel); ref float g = ref MemoryMarshal.GetReference(greenChannel); ref float b = ref MemoryMarshal.GetReference(blueChannel); ref TPixel src = ref MemoryMarshal.GetReference(source); for (nuint i = 0; i < (uint)count; i++) { - Unsafe.Add(ref src, i).ToRgba32(ref rgba32); + Rgba32 rgba32 = Unsafe.Add(ref src, i).ToRgba32(); Unsafe.Add(ref r, i) = rgba32.R; Unsafe.Add(ref g, i) = rgba32.G; Unsafe.Add(ref b, i) = rgba32.B; diff --git a/src/ImageSharp/PixelFormats/PixelTypeInfo.cs b/src/ImageSharp/PixelFormats/PixelTypeInfo.cs new file mode 100644 index 0000000000..7865b9900e --- /dev/null +++ b/src/ImageSharp/PixelFormats/PixelTypeInfo.cs @@ -0,0 +1,62 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Runtime.CompilerServices; + +// TODO: Review this type as it's used to represent 2 different things. +// 1. The encoded image pixel format. +// 2. The pixel format of the decoded image. +// Only the bits per pixel is used by the decoder, we should make it a property of the image metadata. +namespace SixLabors.ImageSharp.PixelFormats; + +/// +/// Contains information about the pixels that make up an images visual data. +/// +/// +/// Initializes a new instance of the struct. +/// +/// Color depth, in number of bits per pixel. +public readonly struct PixelTypeInfo(int bitsPerPixel) +{ + /// + /// Gets color depth, in number of bits per pixel. + /// + public int BitsPerPixel { get; init; } = bitsPerPixel; + + /// + /// Gets the component bit depth and padding within the pixel. + /// + public PixelComponentInfo? ComponentInfo { get; init; } + + /// + /// Gets the pixel color type. + /// + public PixelColorType ColorType { get; init; } + + /// + /// Gets the pixel alpha transparency behavior. + /// means unknown, unspecified. + /// + public PixelAlphaRepresentation AlphaRepresentation { get; init; } + + /// + /// Creates a new instance. + /// + /// The type of pixel format. + /// The pixel component info. + /// The pixel color type. + /// The pixel alpha representation. + /// The . + public static PixelTypeInfo Create( + PixelComponentInfo info, + PixelColorType colorType, + PixelAlphaRepresentation alphaRepresentation) + where TPixel : unmanaged, IPixel + => new() + { + BitsPerPixel = Unsafe.SizeOf() * 8, + ComponentInfo = info, + ColorType = colorType, + AlphaRepresentation = alphaRepresentation + }; +} diff --git a/src/ImageSharp/PixelFormats/README.md b/src/ImageSharp/PixelFormats/README.md index cbebaf23ad..4c7ee545a2 100644 --- a/src/ImageSharp/PixelFormats/README.md +++ b/src/ImageSharp/PixelFormats/README.md @@ -1,4 +1,4 @@ -Pixel formats adapted and extended from: +Pixel formats adapted and extended from: https://github.com/MonoGame/MonoGame diff --git a/src/ImageSharp/PixelFormats/Utils/Vector4Converters.Default.cs b/src/ImageSharp/PixelFormats/Utils/Vector4Converters.Default.cs index 4d07a8a9b6..d7cac15309 100644 --- a/src/ImageSharp/PixelFormats/Utils/Vector4Converters.Default.cs +++ b/src/ImageSharp/PixelFormats/Utils/Vector4Converters.Default.cs @@ -21,139 +21,139 @@ public static class Default { [MethodImpl(InliningOptions.ShortMethod)] public static void FromVector4( - Span sourceVectors, - Span destPixels, + Span source, + Span destination, PixelConversionModifiers modifiers) where TPixel : unmanaged, IPixel { - Guard.DestinationShouldNotBeTooShort(sourceVectors, destPixels, nameof(destPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - UnsafeFromVector4(sourceVectors, destPixels, modifiers); + UnsafeFromVector4(source, destination, modifiers); } [MethodImpl(InliningOptions.ShortMethod)] public static void ToVector4( - ReadOnlySpan sourcePixels, - Span destVectors, + ReadOnlySpan source, + Span destination, PixelConversionModifiers modifiers) where TPixel : unmanaged, IPixel { - Guard.DestinationShouldNotBeTooShort(sourcePixels, destVectors, nameof(destVectors)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - UnsafeToVector4(sourcePixels, destVectors, modifiers); + UnsafeToVector4(source, destination, modifiers); } [MethodImpl(InliningOptions.ShortMethod)] public static void UnsafeFromVector4( - Span sourceVectors, - Span destPixels, + Span source, + Span destination, PixelConversionModifiers modifiers) where TPixel : unmanaged, IPixel { - ApplyBackwardConversionModifiers(sourceVectors, modifiers); + ApplyBackwardConversionModifiers(source, modifiers); if (modifiers.IsDefined(PixelConversionModifiers.Scale)) { - UnsafeFromScaledVector4Core(sourceVectors, destPixels); + UnsafeFromScaledVector4Core(source, destination); } else { - UnsafeFromVector4Core(sourceVectors, destPixels); + UnsafeFromVector4Core(source, destination); } } [MethodImpl(InliningOptions.ShortMethod)] public static void UnsafeToVector4( - ReadOnlySpan sourcePixels, - Span destVectors, + ReadOnlySpan source, + Span destination, PixelConversionModifiers modifiers) where TPixel : unmanaged, IPixel { if (modifiers.IsDefined(PixelConversionModifiers.Scale)) { - UnsafeToScaledVector4Core(sourcePixels, destVectors); + UnsafeToScaledVector4Core(source, destination); } else { - UnsafeToVector4Core(sourcePixels, destVectors); + UnsafeToVector4Core(source, destination); } - ApplyForwardConversionModifiers(destVectors, modifiers); + ApplyForwardConversionModifiers(destination, modifiers); } [MethodImpl(InliningOptions.ShortMethod)] private static void UnsafeFromVector4Core( - ReadOnlySpan sourceVectors, - Span destPixels) + ReadOnlySpan source, + Span destination) where TPixel : unmanaged, IPixel { - ref Vector4 sourceStart = ref MemoryMarshal.GetReference(sourceVectors); - ref Vector4 sourceEnd = ref Unsafe.Add(ref sourceStart, (uint)sourceVectors.Length); - ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); + ref Vector4 sourceStart = ref MemoryMarshal.GetReference(source); + ref Vector4 sourceEnd = ref Unsafe.Add(ref sourceStart, (uint)source.Length); + ref TPixel destinationBase = ref MemoryMarshal.GetReference(destination); while (Unsafe.IsAddressLessThan(ref sourceStart, ref sourceEnd)) { - destRef.FromVector4(sourceStart); + destinationBase = TPixel.FromVector4(sourceStart); sourceStart = ref Unsafe.Add(ref sourceStart, 1); - destRef = ref Unsafe.Add(ref destRef, 1); + destinationBase = ref Unsafe.Add(ref destinationBase, 1); } } [MethodImpl(InliningOptions.ShortMethod)] private static void UnsafeToVector4Core( - ReadOnlySpan sourcePixels, - Span destVectors) + ReadOnlySpan source, + Span destination) where TPixel : unmanaged, IPixel { - ref TPixel sourceStart = ref MemoryMarshal.GetReference(sourcePixels); - ref TPixel sourceEnd = ref Unsafe.Add(ref sourceStart, (uint)sourcePixels.Length); - ref Vector4 destRef = ref MemoryMarshal.GetReference(destVectors); + ref TPixel sourceStart = ref MemoryMarshal.GetReference(source); + ref TPixel sourceEnd = ref Unsafe.Add(ref sourceStart, (uint)source.Length); + ref Vector4 destinationBase = ref MemoryMarshal.GetReference(destination); while (Unsafe.IsAddressLessThan(ref sourceStart, ref sourceEnd)) { - destRef = sourceStart.ToVector4(); + destinationBase = sourceStart.ToVector4(); sourceStart = ref Unsafe.Add(ref sourceStart, 1); - destRef = ref Unsafe.Add(ref destRef, 1); + destinationBase = ref Unsafe.Add(ref destinationBase, 1); } } [MethodImpl(InliningOptions.ShortMethod)] private static void UnsafeFromScaledVector4Core( - ReadOnlySpan sourceVectors, - Span destinationColors) + ReadOnlySpan source, + Span destination) where TPixel : unmanaged, IPixel { - ref Vector4 sourceStart = ref MemoryMarshal.GetReference(sourceVectors); - ref Vector4 sourceEnd = ref Unsafe.Add(ref sourceStart, (uint)sourceVectors.Length); - ref TPixel destRef = ref MemoryMarshal.GetReference(destinationColors); + ref Vector4 sourceStart = ref MemoryMarshal.GetReference(source); + ref Vector4 sourceEnd = ref Unsafe.Add(ref sourceStart, (uint)source.Length); + ref TPixel destinationBase = ref MemoryMarshal.GetReference(destination); while (Unsafe.IsAddressLessThan(ref sourceStart, ref sourceEnd)) { - destRef.FromScaledVector4(sourceStart); + destinationBase = TPixel.FromScaledVector4(sourceStart); sourceStart = ref Unsafe.Add(ref sourceStart, 1); - destRef = ref Unsafe.Add(ref destRef, 1); + destinationBase = ref Unsafe.Add(ref destinationBase, 1); } } [MethodImpl(InliningOptions.ShortMethod)] private static void UnsafeToScaledVector4Core( - ReadOnlySpan sourceColors, - Span destinationVectors) + ReadOnlySpan source, + Span destination) where TPixel : unmanaged, IPixel { - ref TPixel sourceStart = ref MemoryMarshal.GetReference(sourceColors); - ref TPixel sourceEnd = ref Unsafe.Add(ref sourceStart, (uint)sourceColors.Length); - ref Vector4 destRef = ref MemoryMarshal.GetReference(destinationVectors); + ref TPixel sourceStart = ref MemoryMarshal.GetReference(source); + ref TPixel sourceEnd = ref Unsafe.Add(ref sourceStart, (uint)source.Length); + ref Vector4 destinationBase = ref MemoryMarshal.GetReference(destination); while (Unsafe.IsAddressLessThan(ref sourceStart, ref sourceEnd)) { - destRef = sourceStart.ToScaledVector4(); + destinationBase = sourceStart.ToScaledVector4(); sourceStart = ref Unsafe.Add(ref sourceStart, 1); - destRef = ref Unsafe.Add(ref destRef, 1); + destinationBase = ref Unsafe.Add(ref destinationBase, 1); } } } diff --git a/src/ImageSharp/PixelFormats/Utils/Vector4Converters.RgbaCompatible.cs b/src/ImageSharp/PixelFormats/Utils/Vector4Converters.RgbaCompatible.cs index 3442a08075..9e649f3c08 100644 --- a/src/ImageSharp/PixelFormats/Utils/Vector4Converters.RgbaCompatible.cs +++ b/src/ImageSharp/PixelFormats/Utils/Vector4Converters.RgbaCompatible.cs @@ -5,6 +5,7 @@ using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; namespace SixLabors.ImageSharp.PixelFormats.Utils; @@ -28,100 +29,120 @@ public static class RgbaCompatible private static readonly int Vector4ConversionThreshold = CalculateVector4ConversionThreshold(); /// - /// Provides an efficient default implementation for + /// Provides an efficient default implementation for /// The method works by internally converting to a therefore it's not applicable for that type! /// - [MethodImpl(InliningOptions.ShortMethod)] + /// The type of pixel format. + /// The configuration. + /// The pixel operations instance. + /// The source buffer. + /// The destination buffer. + /// The conversion modifier flags. + [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static void ToVector4( Configuration configuration, PixelOperations pixelOperations, - ReadOnlySpan sourcePixels, - Span destVectors, + ReadOnlySpan source, + Span destination, PixelConversionModifiers modifiers) where TPixel : unmanaged, IPixel { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destVectors, nameof(destVectors)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = sourcePixels.Length; + int count = source.Length; // Not worth for small buffers: if (count < Vector4ConversionThreshold) { - Default.UnsafeToVector4(sourcePixels, destVectors, modifiers); + Default.UnsafeToVector4(source, destination, modifiers); return; } - // Using the last quarter of 'destVectors' as a temporary buffer to avoid allocation: + // Using the last quarter of 'destination' as a temporary buffer to avoid allocation: int countWithoutLastItem = count - 1; - ReadOnlySpan reducedSource = sourcePixels[..countWithoutLastItem]; - Span lastQuarterOfDestBuffer = MemoryMarshal.Cast(destVectors).Slice((3 * count) + 1, countWithoutLastItem); - pixelOperations.ToRgba32(configuration, reducedSource, lastQuarterOfDestBuffer); + ReadOnlySpan reducedSource = source[..countWithoutLastItem]; + Span lastQuarterOfDestination = MemoryMarshal.Cast(destination).Slice((3 * count) + 1, countWithoutLastItem); + pixelOperations.ToRgba32(configuration, reducedSource, lastQuarterOfDestination); - // 'destVectors' and 'lastQuarterOfDestBuffer' are overlapping buffers, + // 'destination' and 'lastQuarterOfDestination' are overlapping buffers, // but we are always reading/writing at different positions: SimdUtils.ByteToNormalizedFloat( - MemoryMarshal.Cast(lastQuarterOfDestBuffer), - MemoryMarshal.Cast(destVectors[..countWithoutLastItem])); + MemoryMarshal.Cast(lastQuarterOfDestination), + MemoryMarshal.Cast(destination[..countWithoutLastItem])); - destVectors[countWithoutLastItem] = sourcePixels[countWithoutLastItem].ToVector4(); + destination[countWithoutLastItem] = source[countWithoutLastItem].ToVector4(); // TODO: Investigate optimized 1-pass approach! - ApplyForwardConversionModifiers(destVectors, modifiers); + ApplyForwardConversionModifiers(destination, modifiers); } /// - /// Provides an efficient default implementation for + /// Provides an efficient default implementation for /// The method is works by internally converting to a therefore it's not applicable for that type! /// - [MethodImpl(InliningOptions.ShortMethod)] + /// The type of pixel format. + /// The configuration. + /// The pixel operations instance. + /// The source buffer. + /// The destination buffer. + /// The conversion modifier flags. + [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static void FromVector4( Configuration configuration, PixelOperations pixelOperations, - Span sourceVectors, - Span destPixels, + Span source, + Span destination, PixelConversionModifiers modifiers) where TPixel : unmanaged, IPixel { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourceVectors, destPixels, nameof(destPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = sourceVectors.Length; + int count = source.Length; // Not worth for small buffers: if (count < Vector4ConversionThreshold) { - Default.UnsafeFromVector4(sourceVectors, destPixels, modifiers); + Default.UnsafeFromVector4(source, destination, modifiers); return; } // TODO: Investigate optimized 1-pass approach! - ApplyBackwardConversionModifiers(sourceVectors, modifiers); + ApplyBackwardConversionModifiers(source, modifiers); // For the opposite direction it's not easy to implement the trick used in RunRgba32CompatibleToVector4Conversion, // so let's allocate a temporary buffer as usually: - using (IMemoryOwner tempBuffer = configuration.MemoryAllocator.Allocate(count)) - { - Span tempSpan = tempBuffer.Memory.Span; + using IMemoryOwner tempBuffer = configuration.MemoryAllocator.Allocate(count); + Span tempSpan = tempBuffer.Memory.Span; - SimdUtils.NormalizedFloatToByteSaturate( - MemoryMarshal.Cast(sourceVectors), - MemoryMarshal.Cast(tempSpan)); + SimdUtils.NormalizedFloatToByteSaturate( + MemoryMarshal.Cast(source), + MemoryMarshal.Cast(tempSpan)); - pixelOperations.FromRgba32(configuration, tempSpan, destPixels); - } + pixelOperations.FromRgba32(configuration, tempSpan, destination); } private static int CalculateVector4ConversionThreshold() { - if (!Vector.IsHardwareAccelerated) + if (!Vector128.IsHardwareAccelerated) { return int.MaxValue; } - return SimdUtils.ExtendedIntrinsics.IsAvailable && SimdUtils.HasVector8 ? 256 : 128; + if (Vector512.IsHardwareAccelerated) + { + return 512; + } + + if (Vector256.IsHardwareAccelerated) + { + return 256; + } + + return 128; } } } diff --git a/src/ImageSharp/PixelFormats/Utils/Vector4Converters.cs b/src/ImageSharp/PixelFormats/Utils/Vector4Converters.cs index 8f682ae8f6..0a0b5660d2 100644 --- a/src/ImageSharp/PixelFormats/Utils/Vector4Converters.cs +++ b/src/ImageSharp/PixelFormats/Utils/Vector4Converters.cs @@ -3,7 +3,7 @@ using System.Numerics; using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.ColorSpaces.Companding; +using SixLabors.ImageSharp.ColorProfiles.Companding; namespace SixLabors.ImageSharp.PixelFormats.Utils; @@ -12,6 +12,8 @@ internal static partial class Vector4Converters /// /// Apply modifiers used requested by ToVector4() conversion. /// + /// The span of vectors. + /// The modifier rule. [MethodImpl(InliningOptions.ShortMethod)] internal static void ApplyForwardConversionModifiers(Span vectors, PixelConversionModifiers modifiers) { @@ -29,6 +31,8 @@ internal static void ApplyForwardConversionModifiers(Span vectors, Pixe /// /// Apply modifiers used requested by FromVector4() conversion. /// + /// The span of vectors. + /// The modifier rule. [MethodImpl(InliningOptions.ShortMethod)] internal static void ApplyBackwardConversionModifiers(Span vectors, PixelConversionModifiers modifiers) { diff --git a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorCompassProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorCompassProcessor{TPixel}.cs index cbf893915c..ae891f3507 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorCompassProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorCompassProcessor{TPixel}.cs @@ -125,10 +125,7 @@ public void Invoke(int y) // Grab the max components of the two pixels ref TPixel currentPassPixel = ref Unsafe.Add(ref passPixelsBase, x); ref TPixel currentTargetPixel = ref Unsafe.Add(ref targetPixelsBase, x); - - var pixelValue = Vector4.Max(currentPassPixel.ToVector4(), currentTargetPixel.ToVector4()); - - currentTargetPixel.FromVector4(pixelValue); + currentTargetPixel = TPixel.FromVector4(Vector4.Max(currentPassPixel.ToVector4(), currentTargetPixel.ToVector4())); } } } diff --git a/src/ImageSharp/Processing/Processors/Dithering/ErrorDither.cs b/src/ImageSharp/Processing/Processors/Dithering/ErrorDither.cs index 3c56d0243b..3c0ebb7074 100644 --- a/src/ImageSharp/Processing/Processors/Dithering/ErrorDither.cs +++ b/src/ImageSharp/Processing/Processors/Dithering/ErrorDither.cs @@ -143,7 +143,7 @@ public void ApplyPaletteDither( for (int x = bounds.Left; x < bounds.Right; x++) { ref TPixel sourcePixel = ref Unsafe.Add(ref sourceRowRef, (uint)x); - TPixel transformed = Unsafe.AsRef(processor).GetPaletteColor(sourcePixel); + TPixel transformed = Unsafe.AsRef(in processor).GetPaletteColor(sourcePixel); this.Dither(source, bounds, sourcePixel, transformed, x, y, scale); sourcePixel = transformed; } @@ -203,7 +203,7 @@ internal TPixel Dither( Vector4 result = pixel.ToVector4(); result += error * coefficient; - pixel.FromVector4(result); + pixel = TPixel.FromVector4(result); } } diff --git a/src/ImageSharp/Processing/Processors/Dithering/OrderedDither.cs b/src/ImageSharp/Processing/Processors/Dithering/OrderedDither.cs index 1a02e7a221..d1f46c7441 100644 --- a/src/ImageSharp/Processing/Processors/Dithering/OrderedDither.cs +++ b/src/ImageSharp/Processing/Processors/Dithering/OrderedDither.cs @@ -181,8 +181,7 @@ internal TPixel Dither( float scale) where TPixel : unmanaged, IPixel { - Unsafe.SkipInit(out Rgba32 rgba); - source.ToRgba32(ref rgba); + Rgba32 rgba = source.ToRgba32(); Unsafe.SkipInit(out Rgba32 attempt); float factor = spread * this.thresholdMatrix[y % this.modulusY, x % this.modulusX] * scale; @@ -192,10 +191,7 @@ internal TPixel Dither( attempt.B = (byte)Numerics.Clamp(rgba.B + factor, byte.MinValue, byte.MaxValue); attempt.A = (byte)Numerics.Clamp(rgba.A + factor, byte.MinValue, byte.MaxValue); - TPixel result = default; - result.FromRgba32(attempt); - - return result; + return TPixel.FromRgba32(attempt); } /// diff --git a/src/ImageSharp/Processing/Processors/Effects/PixelRowDelegateProcessor{TPixel,TDelegate}.cs b/src/ImageSharp/Processing/Processors/Effects/PixelRowDelegateProcessor{TPixel,TDelegate}.cs index f59b95050e..36bb327cf2 100644 --- a/src/ImageSharp/Processing/Processors/Effects/PixelRowDelegateProcessor{TPixel,TDelegate}.cs +++ b/src/ImageSharp/Processing/Processors/Effects/PixelRowDelegateProcessor{TPixel,TDelegate}.cs @@ -96,7 +96,7 @@ public void Invoke(int y, Span span) PixelOperations.Instance.ToVector4(this.configuration, rowSpan, span, this.modifiers); // Run the user defined pixel shader to the current row of pixels - Unsafe.AsRef(this.rowProcessor).Invoke(span, new Point(this.startX, y)); + Unsafe.AsRef(in this.rowProcessor).Invoke(span, new Point(this.startX, y)); PixelOperations.Instance.FromVector4Destructive(this.configuration, span, rowSpan, this.modifiers); } diff --git a/src/ImageSharp/Processing/Processors/Filters/FilterProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Filters/FilterProcessor{TPixel}.cs index 5ad245e3ce..5109139647 100644 --- a/src/ImageSharp/Processing/Processors/Filters/FilterProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Filters/FilterProcessor{TPixel}.cs @@ -78,7 +78,7 @@ public void Invoke(int y, Span span) Span rowSpan = this.source.DangerousGetRowSpan(y).Slice(this.startX, span.Length); PixelOperations.Instance.ToVector4(this.configuration, rowSpan, span, PixelConversionModifiers.Scale); - ColorNumerics.Transform(span, ref Unsafe.AsRef(this.matrix)); + ColorNumerics.Transform(span, ref Unsafe.AsRef(in this.matrix)); PixelOperations.Instance.FromVector4Destructive(this.configuration, span, rowSpan, PixelConversionModifiers.Scale); } diff --git a/src/ImageSharp/Processing/Processors/Filters/LomographProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Filters/LomographProcessor{TPixel}.cs index 4a02642fd6..c8a381d590 100644 --- a/src/ImageSharp/Processing/Processors/Filters/LomographProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Filters/LomographProcessor{TPixel}.cs @@ -12,7 +12,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Filters; internal class LomographProcessor : FilterProcessor where TPixel : unmanaged, IPixel { - private static readonly Color VeryDarkGreen = Color.FromRgba(0, 10, 0, 255); + private static readonly Color VeryDarkGreen = Color.FromPixel(new Rgba32(0, 10, 0, 255)); private readonly LomographProcessor definition; /// diff --git a/src/ImageSharp/Processing/Processors/Filters/PolaroidProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Filters/PolaroidProcessor{TPixel}.cs index c1b79d10a1..84c0364faf 100644 --- a/src/ImageSharp/Processing/Processors/Filters/PolaroidProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Filters/PolaroidProcessor{TPixel}.cs @@ -12,8 +12,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Filters; internal class PolaroidProcessor : FilterProcessor where TPixel : unmanaged, IPixel { - private static readonly Color LightOrange = Color.FromRgba(255, 153, 102, 128); - private static readonly Color VeryDarkOrange = Color.FromRgb(102, 34, 0); + private static readonly Color LightOrange = Color.FromPixel(new Rgba32(255, 153, 102, 128)); + private static readonly Color VeryDarkOrange = Color.FromPixel(new Rgb24(102, 34, 0)); private readonly PolaroidProcessor definition; /// diff --git a/src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistogramEqualizationProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistogramEqualizationProcessor{TPixel}.cs index 0baa87a611..78085eaab5 100644 --- a/src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistogramEqualizationProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistogramEqualizationProcessor{TPixel}.cs @@ -64,11 +64,11 @@ protected override void OnFrameApply(ImageFrame source) int luminanceLevels = this.LuminanceLevels; // The image is split up into tiles. For each tile the cumulative distribution function will be calculated. - using (var cdfData = new CdfTileData(this.Configuration, sourceWidth, sourceHeight, this.Tiles, this.Tiles, tileWidth, tileHeight, luminanceLevels)) + using (CdfTileData cdfData = new(this.Configuration, sourceWidth, sourceHeight, this.Tiles, this.Tiles, tileWidth, tileHeight, luminanceLevels)) { cdfData.CalculateLookupTables(source, this); - var tileYStartPositions = new List<(int Y, int CdfY)>(); + List<(int Y, int CdfY)> tileYStartPositions = []; int cdfY = 0; int yStart = halfTileHeight; for (int tile = 0; tile < tileCount - 1; tile++) @@ -78,7 +78,7 @@ protected override void OnFrameApply(ImageFrame source) yStart += tileHeight; } - var operation = new RowIntervalOperation(cdfData, tileYStartPositions, tileWidth, tileHeight, tileCount, halfTileWidth, luminanceLevels, source.PixelBuffer); + RowIntervalOperation operation = new(cdfData, tileYStartPositions, tileWidth, tileHeight, tileCount, halfTileWidth, luminanceLevels, source.PixelBuffer); ParallelRowIterator.IterateRowIntervals( this.Configuration, new Rectangle(0, 0, sourceWidth, tileYStartPositions.Count), @@ -145,7 +145,7 @@ private static void ProcessCornerTile( { ref TPixel pixel = ref rowSpan[dx]; float luminanceEqualized = cdfData.RemapGreyValue(cdfX, cdfY, GetLuminance(pixel, luminanceLevels)); - pixel.FromVector4(new Vector4(luminanceEqualized, luminanceEqualized, luminanceEqualized, pixel.ToVector4().W)); + pixel = TPixel.FromVector4(new(luminanceEqualized, luminanceEqualized, luminanceEqualized, pixel.ToVector4().W)); } } } @@ -191,7 +191,7 @@ private static void ProcessBorderColumn( { ref TPixel pixel = ref rowSpan[dx]; float luminanceEqualized = InterpolateBetweenTwoTiles(pixel, cdfData, cdfX, cdfY, cdfX, cdfY + 1, tileY, tileHeight, luminanceLevels); - pixel.FromVector4(new Vector4(luminanceEqualized, luminanceEqualized, luminanceEqualized, pixel.ToVector4().W)); + pixel = TPixel.FromVector4(new Vector4(luminanceEqualized, luminanceEqualized, luminanceEqualized, pixel.ToVector4().W)); } tileY++; @@ -243,7 +243,7 @@ private static void ProcessBorderRow( { ref TPixel pixel = ref rowSpan[dx]; float luminanceEqualized = InterpolateBetweenTwoTiles(pixel, cdfData, cdfX, cdfY, cdfX + 1, cdfY, tileX, tileWidth, luminanceLevels); - pixel.FromVector4(new Vector4(luminanceEqualized, luminanceEqualized, luminanceEqualized, pixel.ToVector4().W)); + pixel = TPixel.FromVector4(new Vector4(luminanceEqualized, luminanceEqualized, luminanceEqualized, pixel.ToVector4().W)); tileX++; } } @@ -404,10 +404,7 @@ public void Invoke(in RowInterval rows) { 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) = this.tileYStartPositions[index]; int cdfX = 0; int x = this.halfTileWidth; for (int tile = 0; tile < this.tileCount - 1; tile++) @@ -430,12 +427,12 @@ public void Invoke(in RowInterval rows) tileX, tileY, cdfX, - cdfYY, + cdfY, this.tileWidth, this.tileHeight, this.luminanceLevels); - pixel.FromVector4(new Vector4(luminanceEqualized, luminanceEqualized, luminanceEqualized, pixel.ToVector4().W)); + pixel = TPixel.FromVector4(new Vector4(luminanceEqualized, luminanceEqualized, luminanceEqualized, pixel.ToVector4().W)); tileX++; } @@ -494,7 +491,7 @@ public CdfTileData( this.pixelsInTile = tileWidth * tileHeight; // Calculate the start positions and rent buffers. - this.tileYStartPositions = new List<(int Y, int CdfY)>(); + this.tileYStartPositions = []; int cdfY = 0; for (int y = 0; y < sourceHeight; y += tileHeight) { @@ -505,7 +502,7 @@ public CdfTileData( public void CalculateLookupTables(ImageFrame source, HistogramEqualizationProcessor processor) { - var operation = new RowIntervalOperation( + RowIntervalOperation operation = new( processor, this.memoryAllocator, this.cdfMinBuffer2D, diff --git a/src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistogramEqualizationSlidingWindowProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistogramEqualizationSlidingWindowProcessor{TPixel}.cs index d2bec0b49b..93144653e3 100644 --- a/src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistogramEqualizationSlidingWindowProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistogramEqualizationSlidingWindowProcessor{TPixel}.cs @@ -383,7 +383,7 @@ public void Invoke(int x) // Map the current pixel to the new equalized value. int luminance = GetLuminance(this.source[x, y], this.processor.LuminanceLevels); float luminanceEqualized = Unsafe.Add(ref cdfBase, (uint)luminance) / numberOfPixelsMinusCdfMin; - this.targetPixels[x, y].FromVector4(new Vector4(luminanceEqualized, luminanceEqualized, luminanceEqualized, this.source[x, y].ToVector4().W)); + this.targetPixels[x, y] = TPixel.FromVector4(new(luminanceEqualized, luminanceEqualized, luminanceEqualized, this.source[x, y].ToVector4().W)); // Remove top most row from the histogram, mirroring rows which exceeds the borders. if (this.useFastPath) diff --git a/src/ImageSharp/Processing/Processors/Quantization/EuclideanPixelMap{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/EuclideanPixelMap{TPixel}.cs index 72148374aa..4fd37d479d 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/EuclideanPixelMap{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/EuclideanPixelMap{TPixel}.cs @@ -55,8 +55,7 @@ public EuclideanPixelMap(Configuration configuration, ReadOnlyMemory pal PixelOperations.Instance.ToRgba32(configuration, this.Palette.Span, this.rgbaPalette); this.transparentIndex = transparentIndex; - Unsafe.SkipInit(out this.transparentMatch); - this.transparentMatch.FromRgba32(default); + this.transparentMatch = TPixel.FromRgba32(default); } /// @@ -76,8 +75,7 @@ public EuclideanPixelMap(Configuration configuration, ReadOnlyMemory pal public int GetClosestColor(TPixel color, out TPixel match) { ref TPixel paletteRef = ref MemoryMarshal.GetReference(this.Palette.Span); - Unsafe.SkipInit(out Rgba32 rgba); - color.ToRgba32(ref rgba); + Rgba32 rgba = color.ToRgba32(); // Check if the color is in the lookup table if (!this.cache.TryGetValue(rgba, out short index)) diff --git a/src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer{TPixel}.cs index fe422882bc..8b39b74579 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer{TPixel}.cs @@ -126,7 +126,7 @@ public void AddPaletteColors(Buffer2DRegion pixelRegion) /// [MethodImpl(InliningOptions.ShortMethod)] public readonly IndexedImageFrame QuantizeFrame(ImageFrame source, Rectangle bounds) - => QuantizerUtilities.QuantizeFrame(ref Unsafe.AsRef(this), source, bounds); + => QuantizerUtilities.QuantizeFrame(ref Unsafe.AsRef(in this), source, bounds); /// [MethodImpl(InliningOptions.ShortMethod)] @@ -277,8 +277,7 @@ public void Palletize(Span palette, int colorCount, ref int paletteIndex [MethodImpl(InliningOptions.ShortMethod)] public int GetPaletteIndex(TPixel color) { - Unsafe.SkipInit(out Rgba32 rgba); - color.ToRgba32(ref rgba); + Rgba32 rgba = color.ToRgba32(); return this.root.GetPaletteIndex(ref rgba, 0); } @@ -476,9 +475,7 @@ public void ConstructPalette(Span palette, ref int index) Vector3.Zero, new Vector3(255)); - Unsafe.SkipInit(out TPixel pixel); - pixel.FromRgba32(new Rgba32((byte)vector.X, (byte)vector.Y, (byte)vector.Z, byte.MaxValue)); - palette[index] = pixel; + palette[index] = TPixel.FromRgba32(new Rgba32((byte)vector.X, (byte)vector.Y, (byte)vector.Z)); // Consume the next palette index this.paletteIndex = index++; diff --git a/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer.cs b/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer.cs index acd179ffcc..13a59a26de 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer.cs @@ -62,9 +62,10 @@ public IQuantizer CreatePixelSpecificQuantizer(Configuration con { Guard.NotNull(options, nameof(options)); - // Always use the palette length over options since the palette cannot be reduced. - TPixel[] palette = new TPixel[this.colorPalette.Length]; - Color.ToPixel(this.colorPalette.Span, palette.AsSpan()); + // If the palette is larger than the max colors then we need to trim it down. + // treat the buffer as FILO. + TPixel[] palette = new TPixel[Math.Min(options.MaxColors, this.colorPalette.Length)]; + Color.ToPixel(this.colorPalette.Span[..palette.Length], palette.AsSpan()); return new PaletteQuantizer(configuration, options, palette, this.transparentIndex); } } diff --git a/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer{TPixel}.cs index 3df80ea9b7..092975d28a 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer{TPixel}.cs @@ -56,7 +56,7 @@ public PaletteQuantizer( /// [MethodImpl(InliningOptions.ShortMethod)] public readonly IndexedImageFrame QuantizeFrame(ImageFrame source, Rectangle bounds) - => QuantizerUtilities.QuantizeFrame(ref Unsafe.AsRef(this), source, bounds); + => QuantizerUtilities.QuantizeFrame(ref Unsafe.AsRef(in this), source, bounds); /// [MethodImpl(InliningOptions.ShortMethod)] diff --git a/src/ImageSharp/Processing/Processors/Quantization/QuantizerUtilities.cs b/src/ImageSharp/Processing/Processors/Quantization/QuantizerUtilities.cs index 10ffe68dca..fc1dda6be5 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/QuantizerUtilities.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/QuantizerUtilities.cs @@ -161,7 +161,7 @@ private static void SecondPass( for (int x = 0; x < destinationRow.Length; x++) { - destinationRow[x] = Unsafe.AsRef(quantizer).GetQuantizedColor(sourceRow[x + offsetX], out TPixel _); + destinationRow[x] = Unsafe.AsRef(in quantizer).GetQuantizedColor(sourceRow[x + offsetX], out TPixel _); } } diff --git a/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer{TPixel}.cs index f6928c3dd4..ba2ab825ad 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer{TPixel}.cs @@ -142,8 +142,7 @@ public void AddPaletteColors(Buffer2DRegion pixelRegion) if (moment.Weight > 0) { - ref TPixel color = ref paletteSpan[k]; - color.FromScaledVector4(moment.Normalize()); + paletteSpan[k] = TPixel.FromScaledVector4(moment.Normalize()); } } @@ -168,7 +167,7 @@ public void AddPaletteColors(Buffer2DRegion pixelRegion) /// [MethodImpl(InliningOptions.ShortMethod)] public readonly IndexedImageFrame QuantizeFrame(ImageFrame source, Rectangle bounds) - => QuantizerUtilities.QuantizeFrame(ref Unsafe.AsRef(this), source, bounds); + => QuantizerUtilities.QuantizeFrame(ref Unsafe.AsRef(in this), source, bounds); /// public readonly byte GetQuantizedColor(TPixel color, out TPixel match) @@ -178,8 +177,7 @@ public readonly byte GetQuantizedColor(TPixel color, out TPixel match) return (byte)this.pixelMap!.GetClosestColor(color, out match); } - Rgba32 rgba = default; - color.ToRgba32(ref rgba); + Rgba32 rgba = color.ToRgba32(); const int shift = 8 - IndexBits; int r = rgba.R >> shift; @@ -549,7 +547,7 @@ private readonly float Maximize(ref Box cube, int direction, int first, int last /// The first set. /// The second set. /// Returns a value indicating whether the box has been split. - private bool Cut(ref Box set1, ref Box set2) + private readonly bool Cut(ref Box set1, ref Box set2) { ReadOnlySpan momentSpan = this.momentsOwner.GetSpan(); Moment whole = Volume(ref set1, momentSpan); diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor{TPixel}.cs index 98c2523fae..cfc30edc0f 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor{TPixel}.cs @@ -197,7 +197,7 @@ private static void ApplyResizeFrameTransform( bool compand, bool premultiplyAlpha) { - PixelAlphaRepresentation? alphaRepresentation = PixelOperations.Instance.GetPixelTypeInfo()?.AlphaRepresentation; + PixelAlphaRepresentation? alphaRepresentation = PixelOperations.Instance.GetPixelTypeInfo().AlphaRepresentation; // Premultiply only if alpha representation is unknown or Unassociated: bool needsPremultiplication = alphaRepresentation == null || alphaRepresentation.Value == PixelAlphaRepresentation.Unassociated; diff --git a/tests/Directory.Build.targets b/tests/Directory.Build.targets index 3a29442872..d6b35d003f 100644 --- a/tests/Directory.Build.targets +++ b/tests/Directory.Build.targets @@ -18,20 +18,18 @@ - - - - - - - - - - - - + + + + + + + + + + - + diff --git a/tests/ImageSharp.Benchmarks/Bulk/FromRgba32Bytes.cs b/tests/ImageSharp.Benchmarks/Bulk/FromRgba32Bytes.cs index bd938c9da9..6cae208538 100644 --- a/tests/ImageSharp.Benchmarks/Bulk/FromRgba32Bytes.cs +++ b/tests/ImageSharp.Benchmarks/Bulk/FromRgba32Bytes.cs @@ -49,23 +49,17 @@ public void Naive() for (int i = 0; i < this.Count; i++) { int i4 = i * 4; - var c = default(TPixel); - c.FromRgba32(new Rgba32(s[i4], s[i4 + 1], s[i4 + 2], s[i4 + 3])); - d[i] = c; + d[i] = TPixel.FromRgba32(new Rgba32(s[i4], s[i4 + 1], s[i4 + 2], s[i4 + 3])); } } [Benchmark(Baseline = true)] public void CommonBulk() - { - new PixelOperations().FromRgba32Bytes(this.configuration, this.source.GetSpan(), this.destination.GetSpan(), this.Count); - } + => new PixelOperations().FromRgba32Bytes(this.configuration, this.source.GetSpan(), this.destination.GetSpan(), this.Count); [Benchmark] public void OptimizedBulk() - { - PixelOperations.Instance.FromRgba32Bytes(this.configuration, this.source.GetSpan(), this.destination.GetSpan(), this.Count); - } + => PixelOperations.Instance.FromRgba32Bytes(this.configuration, this.source.GetSpan(), this.destination.GetSpan(), this.Count); } public class FromRgba32Bytes_ToRgba32 : FromRgba32Bytes diff --git a/tests/ImageSharp.Benchmarks/Bulk/FromVector4.cs b/tests/ImageSharp.Benchmarks/Bulk/FromVector4.cs index 7e6cec2018..53c26a57ea 100644 --- a/tests/ImageSharp.Benchmarks/Bulk/FromVector4.cs +++ b/tests/ImageSharp.Benchmarks/Bulk/FromVector4.cs @@ -14,13 +14,13 @@ // ReSharper disable InconsistentNaming namespace SixLabors.ImageSharp.Benchmarks.Bulk; -[Config(typeof(Config.ShortCore31))] +[Config(typeof(Config.Short))] public abstract class FromVector4 where TPixel : unmanaged, IPixel { - protected IMemoryOwner source; + protected IMemoryOwner Source { get; set; } - protected IMemoryOwner destination; + protected IMemoryOwner Destination { get; set; } protected Configuration Configuration => Configuration.Default; @@ -31,66 +31,44 @@ public abstract class FromVector4 [GlobalSetup] public void Setup() { - this.destination = this.Configuration.MemoryAllocator.Allocate(this.Count); - this.source = this.Configuration.MemoryAllocator.Allocate(this.Count); + this.Destination = this.Configuration.MemoryAllocator.Allocate(this.Count); + this.Source = this.Configuration.MemoryAllocator.Allocate(this.Count); } [GlobalCleanup] public void Cleanup() { - this.destination.Dispose(); - this.source.Dispose(); + this.Destination.Dispose(); + this.Source.Dispose(); } // [Benchmark] public void PerElement() { - ref Vector4 s = ref MemoryMarshal.GetReference(this.source.GetSpan()); - ref TPixel d = ref MemoryMarshal.GetReference(this.destination.GetSpan()); + ref Vector4 s = ref MemoryMarshal.GetReference(this.Source.GetSpan()); + ref TPixel d = ref MemoryMarshal.GetReference(this.Destination.GetSpan()); for (nuint i = 0; i < (uint)this.Count; i++) { - Unsafe.Add(ref d, i).FromVector4(Unsafe.Add(ref s, i)); + Unsafe.Add(ref d, i) = TPixel.FromVector4(Unsafe.Add(ref s, i)); } } [Benchmark(Baseline = true)] public void PixelOperations_Base() - { - new PixelOperations().FromVector4Destructive(this.Configuration, this.source.GetSpan(), this.destination.GetSpan()); - } + => new PixelOperations().FromVector4Destructive(this.Configuration, this.Source.GetSpan(), this.Destination.GetSpan()); [Benchmark] public void PixelOperations_Specialized() - { - PixelOperations.Instance.FromVector4Destructive(this.Configuration, this.source.GetSpan(), this.destination.GetSpan()); - } + => PixelOperations.Instance.FromVector4Destructive(this.Configuration, this.Source.GetSpan(), this.Destination.GetSpan()); } public class FromVector4Rgba32 : FromVector4 { - [Benchmark] - public void FallbackIntrinsics128() - { - Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); - Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); - - SimdUtils.FallbackIntrinsics128.NormalizedFloatToByteSaturate(sBytes, dFloats); - } - - [Benchmark] - public void ExtendedIntrinsic() - { - Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); - Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); - - SimdUtils.ExtendedIntrinsics.NormalizedFloatToByteSaturate(sBytes, dFloats); - } - [Benchmark] public void UseHwIntrinsics() { - Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); - Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); + Span sBytes = MemoryMarshal.Cast(this.Source.GetSpan()); + Span dFloats = MemoryMarshal.Cast(this.Destination.GetSpan()); SimdUtils.HwIntrinsics.NormalizedFloatToByteSaturate(sBytes, dFloats); } @@ -100,8 +78,8 @@ public void UseHwIntrinsics() [Benchmark] public void UseAvx2_Grouped() { - Span src = MemoryMarshal.Cast(this.source.GetSpan()); - Span dest = MemoryMarshal.Cast(this.destination.GetSpan()); + Span src = MemoryMarshal.Cast(this.Source.GetSpan()); + Span dest = MemoryMarshal.Cast(this.Destination.GetSpan()); nuint n = (uint)dest.Length / (uint)Vector.Count; @@ -111,7 +89,7 @@ public void UseAvx2_Grouped() ref byte maskBase = ref MemoryMarshal.GetReference(PermuteMaskDeinterleave8x32); Vector256 mask = Unsafe.As>(ref maskBase); - var maxBytes = Vector256.Create(255f); + Vector256 maxBytes = Vector256.Create(255f); for (nuint i = 0; i < n; i++) { @@ -141,25 +119,37 @@ public void UseAvx2_Grouped() } } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static Vector256 ConvertToInt32(Vector256 vf, Vector256 scale) - { - vf = Avx.Multiply(scale, vf); - return Avx.ConvertToVector256Int32(vf); - } - - // *** RESULTS 2020 March: *** - // Intel Core i7-8650U CPU 1.90GHz (Kaby Lake R), 1 CPU, 8 logical and 4 physical cores - // .NET Core SDK=3.1.200-preview-014971 - // Job-IUZXZT : .NET Core 3.1.2 (CoreCLR 4.700.20.6602, CoreFX 4.700.20.6702), X64 RyuJIT - // - // | Method | Count | Mean | Error | StdDev | Ratio | RatioSD | Gen 0 | Gen 1 | Gen 2 | Allocated | - // |---------------------------- |------ |-----------:|------------:|----------:|------:|--------:|------:|------:|------:|----------:| - // | FallbackIntrinsics128 | 1024 | 2,952.6 ns | 1,680.77 ns | 92.13 ns | 3.32 | 0.16 | - | - | - | - | - // | BasicIntrinsics256 | 1024 | 1,664.5 ns | 928.11 ns | 50.87 ns | 1.87 | 0.09 | - | - | - | - | - // | ExtendedIntrinsic | 1024 | 890.6 ns | 375.48 ns | 20.58 ns | 1.00 | 0.00 | - | - | - | - | - // | UseAvx2 | 1024 | 299.0 ns | 30.47 ns | 1.67 ns | 0.34 | 0.01 | - | - | - | - | - // | UseAvx2_Grouped | 1024 | 318.1 ns | 48.19 ns | 2.64 ns | 0.36 | 0.01 | - | - | - | - | - // | PixelOperations_Base | 1024 | 8,136.9 ns | 1,834.82 ns | 100.57 ns | 9.14 | 0.26 | - | - | - | 24 B | - // | PixelOperations_Specialized | 1024 | 951.1 ns | 123.93 ns | 6.79 ns | 1.07 | 0.03 | - | - | - | - | + /* + BenchmarkDotNet v0.13.10, Windows 11 (10.0.22631.3085/23H2/2023Update/SunValley3) + 11th Gen Intel Core i7-11370H 3.30GHz, 1 CPU, 8 logical and 4 physical cores + .NET SDK 8.0.200-preview.23624.5 + [Host] : .NET 8.0.1 (8.0.123.58001), X64 RyuJIT AVX2 + Job-YJYLLR : .NET 8.0.1 (8.0.123.58001), X64 RyuJIT AVX2 + + Runtime=.NET 8.0 Arguments=/p:DebugType=portable IterationCount=3 + LaunchCount=1 WarmupCount=3 + + | Method | Count | Mean | Error | StdDev | Ratio | RatioSD | Allocated | Alloc Ratio | + |---------------------------- |------ |------------:|-------------:|-----------:|------:|--------:|----------:|------------:| + | PixelOperations_Base | 64 | 114.80 ns | 16.459 ns | 0.902 ns | 1.00 | 0.00 | - | NA | + | PixelOperations_Specialized | 64 | 28.91 ns | 80.482 ns | 4.411 ns | 0.25 | 0.04 | - | NA | + | FallbackIntrinsics128 | 64 | 133.60 ns | 23.750 ns | 1.302 ns | 1.16 | 0.02 | - | NA | + | ExtendedIntrinsic | 64 | 40.11 ns | 10.183 ns | 0.558 ns | 0.35 | 0.01 | - | NA | + | UseHwIntrinsics | 64 | 14.71 ns | 4.860 ns | 0.266 ns | 0.13 | 0.00 | - | NA | + | UseAvx2_Grouped | 64 | 20.23 ns | 11.619 ns | 0.637 ns | 0.18 | 0.00 | - | NA | + | | | | | | | | | | + | PixelOperations_Base | 256 | 387.94 ns | 31.591 ns | 1.732 ns | 1.00 | 0.00 | - | NA | + | PixelOperations_Specialized | 256 | 50.93 ns | 22.388 ns | 1.227 ns | 0.13 | 0.00 | - | NA | + | FallbackIntrinsics128 | 256 | 509.72 ns | 249.926 ns | 13.699 ns | 1.31 | 0.04 | - | NA | + | ExtendedIntrinsic | 256 | 140.32 ns | 9.353 ns | 0.513 ns | 0.36 | 0.00 | - | NA | + | UseHwIntrinsics | 256 | 41.99 ns | 16.000 ns | 0.877 ns | 0.11 | 0.00 | - | NA | + | UseAvx2_Grouped | 256 | 63.81 ns | 2.360 ns | 0.129 ns | 0.16 | 0.00 | - | NA | + | | | | | | | | | | + | PixelOperations_Base | 2048 | 2,979.49 ns | 2,023.706 ns | 110.926 ns | 1.00 | 0.00 | - | NA | + | PixelOperations_Specialized | 2048 | 326.19 ns | 19.077 ns | 1.046 ns | 0.11 | 0.00 | - | NA | + | FallbackIntrinsics128 | 2048 | 3,885.95 ns | 411.078 ns | 22.533 ns | 1.31 | 0.05 | - | NA | + | ExtendedIntrinsic | 2048 | 1,078.58 ns | 136.960 ns | 7.507 ns | 0.36 | 0.01 | - | NA | + | UseHwIntrinsics | 2048 | 312.07 ns | 68.662 ns | 3.764 ns | 0.10 | 0.00 | - | NA | + | UseAvx2_Grouped | 2048 | 451.83 ns | 41.742 ns | 2.288 ns | 0.15 | 0.01 | - | NA | + */ } diff --git a/tests/ImageSharp.Benchmarks/Bulk/FromVector4_Rgb24.cs b/tests/ImageSharp.Benchmarks/Bulk/FromVector4_Rgb24.cs index fe0d2a10a7..c6125ef8f0 100644 --- a/tests/ImageSharp.Benchmarks/Bulk/FromVector4_Rgb24.cs +++ b/tests/ImageSharp.Benchmarks/Bulk/FromVector4_Rgb24.cs @@ -6,49 +6,27 @@ namespace SixLabors.ImageSharp.Benchmarks.Bulk; -[Config(typeof(Config.ShortMultiFramework))] -public class FromVector4_Rgb24 : FromVector4 -{ -} +[Config(typeof(Config.Short))] +public class FromVector4_Rgb24 : FromVector4; -// 2020-11-02 -// ########## -// -// BenchmarkDotNet = v0.12.1, OS = Windows 10.0.19041.572(2004 /?/ 20H1) -// Intel Core i7-8650U CPU 1.90GHz (Kaby Lake R), 1 CPU, 8 logical and 4 physical cores -// .NET Core SDK=3.1.403 -// [Host] : .NET Core 3.1.9 (CoreCLR 4.700.20.47201, CoreFX 4.700.20.47203), X64 RyuJIT -// Job-XYEQXL : .NET Framework 4.8 (4.8.4250.0), X64 RyuJIT -// Job-HSXNJV : .NET Core 2.1.23 (CoreCLR 4.6.29321.03, CoreFX 4.6.29321.01), X64 RyuJIT -// Job-YUREJO : .NET Core 3.1.9 (CoreCLR 4.700.20.47201, CoreFX 4.700.20.47203), X64 RyuJIT -// -// IterationCount=3 LaunchCount=1 WarmupCount=3 -// -// | Method | Job | Runtime | Count | Mean | Error | StdDev | Ratio | RatioSD | Gen 0 | Gen 1 | Gen 2 | Allocated | -// |---------------------------- |----------- |-------------- |------ |-----------:|------------:|----------:|------:|--------:|-------:|------:|------:|----------:| -// | PixelOperations_Base | Job-XYEQXL | .NET 4.7.2 | 64 | 343.2 ns | 305.91 ns | 16.77 ns | 1.00 | 0.00 | 0.0057 | - | - | 24 B | -// | PixelOperations_Specialized | Job-XYEQXL | .NET 4.7.2 | 64 | 320.8 ns | 19.93 ns | 1.09 ns | 0.94 | 0.05 | - | - | - | - | -// | | | | | | | | | | | | | | -// | PixelOperations_Base | Job-HSXNJV | .NET Core 2.1 | 64 | 234.3 ns | 17.98 ns | 0.99 ns | 1.00 | 0.00 | 0.0052 | - | - | 24 B | -// | PixelOperations_Specialized | Job-HSXNJV | .NET Core 2.1 | 64 | 246.0 ns | 82.34 ns | 4.51 ns | 1.05 | 0.02 | - | - | - | - | -// | | | | | | | | | | | | | | -// | PixelOperations_Base | Job-YUREJO | .NET Core 3.1 | 64 | 222.3 ns | 39.46 ns | 2.16 ns | 1.00 | 0.00 | 0.0057 | - | - | 24 B | -// | PixelOperations_Specialized | Job-YUREJO | .NET Core 3.1 | 64 | 243.4 ns | 33.58 ns | 1.84 ns | 1.09 | 0.01 | - | - | - | - | -// | | | | | | | | | | | | | | -// | PixelOperations_Base | Job-XYEQXL | .NET 4.7.2 | 256 | 824.9 ns | 32.77 ns | 1.80 ns | 1.00 | 0.00 | 0.0057 | - | - | 24 B | -// | PixelOperations_Specialized | Job-XYEQXL | .NET 4.7.2 | 256 | 967.0 ns | 39.09 ns | 2.14 ns | 1.17 | 0.01 | 0.0172 | - | - | 72 B | -// | | | | | | | | | | | | | | -// | PixelOperations_Base | Job-HSXNJV | .NET Core 2.1 | 256 | 756.9 ns | 94.43 ns | 5.18 ns | 1.00 | 0.00 | 0.0048 | - | - | 24 B | -// | PixelOperations_Specialized | Job-HSXNJV | .NET Core 2.1 | 256 | 1,003.3 ns | 3,192.09 ns | 174.97 ns | 1.32 | 0.22 | 0.0172 | - | - | 72 B | -// | | | | | | | | | | | | | | -// | PixelOperations_Base | Job-YUREJO | .NET Core 3.1 | 256 | 748.6 ns | 248.03 ns | 13.60 ns | 1.00 | 0.00 | 0.0057 | - | - | 24 B | -// | PixelOperations_Specialized | Job-YUREJO | .NET Core 3.1 | 256 | 437.0 ns | 36.48 ns | 2.00 ns | 0.58 | 0.01 | 0.0172 | - | - | 72 B | -// | | | | | | | | | | | | | | -// | PixelOperations_Base | Job-XYEQXL | .NET 4.7.2 | 2048 | 5,751.6 ns | 704.24 ns | 38.60 ns | 1.00 | 0.00 | - | - | - | 24 B | -// | PixelOperations_Specialized | Job-XYEQXL | .NET 4.7.2 | 2048 | 4,391.6 ns | 718.17 ns | 39.37 ns | 0.76 | 0.00 | 0.0153 | - | - | 72 B | -// | | | | | | | | | | | | | | -// | PixelOperations_Base | Job-HSXNJV | .NET Core 2.1 | 2048 | 6,202.0 ns | 1,815.18 ns | 99.50 ns | 1.00 | 0.00 | - | - | - | 24 B | -// | PixelOperations_Specialized | Job-HSXNJV | .NET Core 2.1 | 2048 | 4,225.6 ns | 1,004.03 ns | 55.03 ns | 0.68 | 0.01 | 0.0153 | - | - | 72 B | -// | | | | | | | | | | | | | | -// | PixelOperations_Base | Job-YUREJO | .NET Core 3.1 | 2048 | 6,157.1 ns | 2,516.98 ns | 137.96 ns | 1.00 | 0.00 | - | - | - | 24 B | -// | PixelOperations_Specialized | Job-YUREJO | .NET Core 3.1 | 2048 | 1,822.7 ns | 1,764.43 ns | 96.71 ns | 0.30 | 0.02 | 0.0172 | - | - | 72 B | +/* + BenchmarkDotNet v0.13.10, Windows 11 (10.0.22631.3085/23H2/2023Update/SunValley3) +11th Gen Intel Core i7-11370H 3.30GHz, 1 CPU, 8 logical and 4 physical cores +.NET SDK 8.0.200-preview.23624.5 + [Host] : .NET 8.0.1 (8.0.123.58001), X64 RyuJIT AVX2 + Job-NEHCEM : .NET 8.0.1 (8.0.123.58001), X64 RyuJIT AVX2 + +Runtime=.NET 8.0 Arguments=/p:DebugType=portable IterationCount=3 +LaunchCount=1 WarmupCount=3 + +| Method | Count | Mean | Error | StdDev | Ratio | Gen0 | Allocated | Alloc Ratio | +|---------------------------- |------ |------------:|----------:|---------:|------:|-------:|----------:|------------:| +| PixelOperations_Base | 64 | 95.87 ns | 13.60 ns | 0.745 ns | 1.00 | - | - | NA | +| PixelOperations_Specialized | 64 | 97.34 ns | 30.34 ns | 1.663 ns | 1.02 | - | - | NA | +| | | | | | | | | | +| PixelOperations_Base | 256 | 337.80 ns | 88.10 ns | 4.829 ns | 1.00 | - | - | NA | +| PixelOperations_Specialized | 256 | 195.07 ns | 30.54 ns | 1.674 ns | 0.58 | 0.0153 | 96 B | NA | +| | | | | | | | | | +| PixelOperations_Base | 2048 | 2,561.79 ns | 162.45 ns | 8.905 ns | 1.00 | - | - | NA | +| PixelOperations_Specialized | 2048 | 741.85 ns | 18.05 ns | 0.989 ns | 0.29 | 0.0153 | 96 B | NA | + */ diff --git a/tests/ImageSharp.Benchmarks/Bulk/ToRgba32Bytes.cs b/tests/ImageSharp.Benchmarks/Bulk/ToRgba32Bytes.cs index 6d3f8f9528..19ab780c01 100644 --- a/tests/ImageSharp.Benchmarks/Bulk/ToRgba32Bytes.cs +++ b/tests/ImageSharp.Benchmarks/Bulk/ToRgba32Bytes.cs @@ -47,8 +47,7 @@ public void Naive() { TPixel c = s[i]; int i4 = i * 4; - Rgba32 rgba = default; - c.ToRgba32(ref rgba); + Rgba32 rgba = c.ToRgba32(); d[i4] = rgba.R; d[i4 + 1] = rgba.G; d[i4 + 2] = rgba.B; diff --git a/tests/ImageSharp.Benchmarks/Bulk/ToVector4.cs b/tests/ImageSharp.Benchmarks/Bulk/ToVector4.cs index 3b4360b161..0df8d9818c 100644 --- a/tests/ImageSharp.Benchmarks/Bulk/ToVector4.cs +++ b/tests/ImageSharp.Benchmarks/Bulk/ToVector4.cs @@ -14,9 +14,9 @@ namespace SixLabors.ImageSharp.Benchmarks.Bulk; public abstract class ToVector4 where TPixel : unmanaged, IPixel { - protected IMemoryOwner source; + protected IMemoryOwner Source { get; set; } - protected IMemoryOwner destination; + protected IMemoryOwner Destination { get; set; } protected Configuration Configuration => Configuration.Default; @@ -26,22 +26,22 @@ public abstract class ToVector4 [GlobalSetup] public void Setup() { - this.source = this.Configuration.MemoryAllocator.Allocate(this.Count); - this.destination = this.Configuration.MemoryAllocator.Allocate(this.Count); + this.Source = this.Configuration.MemoryAllocator.Allocate(this.Count); + this.Destination = this.Configuration.MemoryAllocator.Allocate(this.Count); } [GlobalCleanup] public void Cleanup() { - this.source.Dispose(); - this.destination.Dispose(); + this.Source.Dispose(); + this.Destination.Dispose(); } // [Benchmark] public void Naive() { - Span s = this.source.GetSpan(); - Span d = this.destination.GetSpan(); + Span s = this.Source.GetSpan(); + Span d = this.Destination.GetSpan(); for (int i = 0; i < this.Count; i++) { @@ -50,11 +50,8 @@ public void Naive() } [Benchmark] - public void PixelOperations_Specialized() - { - PixelOperations.Instance.ToVector4( + public void PixelOperations_Specialized() => PixelOperations.Instance.ToVector4( this.Configuration, - this.source.GetSpan(), - this.destination.GetSpan()); - } + this.Source.GetSpan(), + this.Destination.GetSpan()); } diff --git a/tests/ImageSharp.Benchmarks/Bulk/ToVector4_Bgra32.cs b/tests/ImageSharp.Benchmarks/Bulk/ToVector4_Bgra32.cs index 2f1064439b..6499632b69 100644 --- a/tests/ImageSharp.Benchmarks/Bulk/ToVector4_Bgra32.cs +++ b/tests/ImageSharp.Benchmarks/Bulk/ToVector4_Bgra32.cs @@ -8,7 +8,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Bulk; -[Config(typeof(Config.ShortMultiFramework))] +[Config(typeof(Config.Short))] public class ToVector4_Bgra32 : ToVector4 { [Benchmark(Baseline = true)] @@ -16,8 +16,8 @@ public void PixelOperations_Base() { new PixelOperations().ToVector4( this.Configuration, - this.source.GetSpan(), - this.destination.GetSpan()); + this.Source.GetSpan(), + this.Destination.GetSpan()); } // RESULTS: diff --git a/tests/ImageSharp.Benchmarks/Bulk/ToVector4_Rgb24.cs b/tests/ImageSharp.Benchmarks/Bulk/ToVector4_Rgb24.cs index 2c700a733f..adedabf8f5 100644 --- a/tests/ImageSharp.Benchmarks/Bulk/ToVector4_Rgb24.cs +++ b/tests/ImageSharp.Benchmarks/Bulk/ToVector4_Rgb24.cs @@ -8,7 +8,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Bulk; -[Config(typeof(Config.ShortMultiFramework))] +[Config(typeof(Config.Short))] public class ToVector4_Rgb24 : ToVector4 { [Benchmark(Baseline = true)] @@ -16,8 +16,8 @@ public void PixelOperations_Base() { new PixelOperations().ToVector4( this.Configuration, - this.source.GetSpan(), - this.destination.GetSpan()); + this.Source.GetSpan(), + this.Destination.GetSpan()); } } diff --git a/tests/ImageSharp.Benchmarks/Bulk/ToVector4_Rgba32.cs b/tests/ImageSharp.Benchmarks/Bulk/ToVector4_Rgba32.cs index 9abf0ed22a..113793a033 100644 --- a/tests/ImageSharp.Benchmarks/Bulk/ToVector4_Rgba32.cs +++ b/tests/ImageSharp.Benchmarks/Bulk/ToVector4_Rgba32.cs @@ -11,39 +11,21 @@ namespace SixLabors.ImageSharp.Benchmarks.Bulk; -[Config(typeof(Config.ShortCore31))] +[Config(typeof(Config.Short))] public class ToVector4_Rgba32 : ToVector4 { - [Benchmark] - public void FallbackIntrinsics128() - { - Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); - Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); - - SimdUtils.FallbackIntrinsics128.ByteToNormalizedFloat(sBytes, dFloats); - } - [Benchmark] public void PixelOperations_Base() => new PixelOperations().ToVector4( this.Configuration, - this.source.GetSpan(), - this.destination.GetSpan()); - - [Benchmark] - public void ExtendedIntrinsics() - { - Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); - Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); - - SimdUtils.ExtendedIntrinsics.ByteToNormalizedFloat(sBytes, dFloats); - } + this.Source.GetSpan(), + this.Destination.GetSpan()); [Benchmark] public void HwIntrinsics() { - Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); - Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); + Span sBytes = MemoryMarshal.Cast(this.Source.GetSpan()); + Span dFloats = MemoryMarshal.Cast(this.Destination.GetSpan()); SimdUtils.HwIntrinsics.ByteToNormalizedFloat(sBytes, dFloats); } @@ -51,8 +33,8 @@ public void HwIntrinsics() // [Benchmark] public void ExtendedIntrinsics_BulkConvertByteToNormalizedFloat_2Loops() { - Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); - Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); + Span sBytes = MemoryMarshal.Cast(this.Source.GetSpan()); + Span dFloats = MemoryMarshal.Cast(this.Destination.GetSpan()); nuint n = (uint)dFloats.Length / (uint)Vector.Count; @@ -76,14 +58,14 @@ public void ExtendedIntrinsics_BulkConvertByteToNormalizedFloat_2Loops() } n = (uint)(dFloats.Length / Vector.Count); - var scale = new Vector(1f / 255f); + Vector scale = new(1f / 255f); for (nuint i = 0; i < n; i++) { ref Vector dRef = ref Unsafe.Add(ref destBase, i); - var du = Vector.AsVectorInt32(dRef); - var v = Vector.ConvertToSingle(du); + Vector du = Vector.AsVectorInt32(dRef); + Vector v = Vector.ConvertToSingle(du); v *= scale; dRef = v; @@ -93,14 +75,14 @@ public void ExtendedIntrinsics_BulkConvertByteToNormalizedFloat_2Loops() // [Benchmark] public void ExtendedIntrinsics_BulkConvertByteToNormalizedFloat_ConvertInSameLoop() { - Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); - Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); + Span sBytes = MemoryMarshal.Cast(this.Source.GetSpan()); + Span dFloats = MemoryMarshal.Cast(this.Destination.GetSpan()); nuint n = (uint)dFloats.Length / (uint)Vector.Count; ref Vector sourceBase = ref Unsafe.As>(ref MemoryMarshal.GetReference((ReadOnlySpan)sBytes)); ref Vector destBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(dFloats)); - var scale = new Vector(1f / 255f); + Vector scale = new(1f / 255f); for (nuint i = 0; i < n; i++) { @@ -126,8 +108,8 @@ public void ExtendedIntrinsics_BulkConvertByteToNormalizedFloat_ConvertInSameLoo [MethodImpl(MethodImplOptions.AggressiveInlining)] private static Vector ConvertToNormalizedSingle(Vector u, Vector scale) { - var vi = Vector.AsVectorInt32(u); - var v = Vector.ConvertToSingle(vi); + Vector vi = Vector.AsVectorInt32(u); + Vector v = Vector.ConvertToSingle(vi); v *= scale; return v; } @@ -160,4 +142,30 @@ private static Vector ConvertToNormalizedSingle(Vector u, Vector InputImageSubfoldersOrFiles => new[] { "Bmp/", "Jpg/baseline" }; diff --git a/tests/ImageSharp.Benchmarks/Codecs/Gif/DecodeGif.cs b/tests/ImageSharp.Benchmarks/Codecs/Gif/DecodeGif.cs index 21b193ddaf..525e9f5e5a 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Gif/DecodeGif.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Gif/DecodeGif.cs @@ -9,7 +9,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs; -[Config(typeof(Config.ShortMultiFramework))] +[Config(typeof(Config.Short))] public class DecodeGif { private byte[] gifBytes; diff --git a/tests/ImageSharp.Benchmarks/Codecs/Gif/EncodeGif.cs b/tests/ImageSharp.Benchmarks/Codecs/Gif/EncodeGif.cs index 048c2aadda..c3644221e1 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Gif/EncodeGif.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Gif/EncodeGif.cs @@ -12,7 +12,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs; -[Config(typeof(Config.ShortMultiFramework))] +[Config(typeof(Config.Short))] public class EncodeGif { // System.Drawing needs this. diff --git a/tests/ImageSharp.Benchmarks/Codecs/Gif/EncodeGifMultiple.cs b/tests/ImageSharp.Benchmarks/Codecs/Gif/EncodeGifMultiple.cs index c523b5c204..9557f616ca 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Gif/EncodeGifMultiple.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Gif/EncodeGifMultiple.cs @@ -9,7 +9,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs; -[Config(typeof(Config.ShortMultiFramework))] +[Config(typeof(Config.Short))] public class EncodeGifMultiple : MultiImageBenchmarkBase.WithImagesPreloaded { [Params(InputImageCategory.AllImages)] diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/CmykColorConversion.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/CmykColorConversion.cs index 51cd02bc7a..9189bec376 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/CmykColorConversion.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/CmykColorConversion.cs @@ -6,7 +6,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg; -[Config(typeof(Config.ShortMultiFramework))] +[Config(typeof(Config.Short))] public class CmykColorConversion : ColorConversionBenchmark { public CmykColorConversion() diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/GrayscaleColorConversion.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/GrayscaleColorConversion.cs index 8bf26d721d..a1d85ef466 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/GrayscaleColorConversion.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/GrayscaleColorConversion.cs @@ -6,7 +6,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg; -[Config(typeof(Config.ShortMultiFramework))] +[Config(typeof(Config.Short))] public class GrayscaleColorConversion : ColorConversionBenchmark { public GrayscaleColorConversion() diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/RgbColorConversion.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/RgbColorConversion.cs index ba09644219..5e2b6fe860 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/RgbColorConversion.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/RgbColorConversion.cs @@ -6,7 +6,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg; -[Config(typeof(Config.ShortMultiFramework))] +[Config(typeof(Config.Short))] public class RgbColorConversion : ColorConversionBenchmark { public RgbColorConversion() diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/YCbCrColorConversion.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/YCbCrColorConversion.cs index 87e1bf5aa9..f8621c2500 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/YCbCrColorConversion.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/YCbCrColorConversion.cs @@ -6,7 +6,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg; -[Config(typeof(Config.ShortMultiFramework))] +[Config(typeof(Config.Short))] public class YCbCrColorConversion : ColorConversionBenchmark { public YCbCrColorConversion() diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/YccKColorConverter.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/YccKColorConverter.cs index 136182936f..a414b6ed47 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/YccKColorConverter.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/YccKColorConverter.cs @@ -6,7 +6,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg; -[Config(typeof(Config.ShortMultiFramework))] +[Config(typeof(Config.Short))] public class YccKColorConverter : ColorConversionBenchmark { public YccKColorConverter() diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpegParseStreamOnly.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpegParseStreamOnly.cs index b5a7245292..f5178390f6 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpegParseStreamOnly.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpegParseStreamOnly.cs @@ -10,7 +10,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg; -[Config(typeof(Config.ShortMultiFramework))] +[Config(typeof(Config.Short))] public class DecodeJpegParseStreamOnly { [Params(TestImages.Jpeg.BenchmarkSuite.Lake_Small444YCbCr)] diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_Aggregate.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_Aggregate.cs index bece1de5bd..389fec88be 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_Aggregate.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_Aggregate.cs @@ -13,7 +13,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg; /// An expensive Jpeg benchmark, running on a wide range of input images, /// showing aggregate results. /// -[Config(typeof(Config.ShortMultiFramework))] +[Config(typeof(Config.Short))] public class DecodeJpeg_Aggregate : MultiImageBenchmarkBase { protected override IEnumerable InputImageSubfoldersOrFiles diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs index 035f800a9b..08df2580db 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs @@ -13,7 +13,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg; /// /// Image-specific Jpeg benchmarks /// -[Config(typeof(Config.ShortMultiFramework))] +[Config(typeof(Config.Short))] public class DecodeJpeg_ImageSpecific { private byte[] jpegBytes; diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/EncodeJpegComparison.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/EncodeJpegComparison.cs index d762e8e95e..deb3125b30 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/EncodeJpegComparison.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/EncodeJpegComparison.cs @@ -39,7 +39,7 @@ public void SetupImageSharp() using FileStream imageBinaryStream = File.OpenRead(Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, TestImage)); this.imageImageSharp = Image.Load(imageBinaryStream); - this.encoderImageSharp = new JpegEncoder { Quality = this.Quality, ColorType = JpegEncodingColor.YCbCrRatio420 }; + this.encoderImageSharp = new JpegEncoder { Quality = this.Quality, ColorType = JpegColorType.YCbCrRatio420 }; this.destinationStream = new MemoryStream(); } diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/EncodeJpegFeatures.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/EncodeJpegFeatures.cs index 98eb0b54dc..0692c5a3b5 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/EncodeJpegFeatures.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/EncodeJpegFeatures.cs @@ -20,19 +20,19 @@ public class EncodeJpegFeatures // No metadata private const string TestImage = TestImages.Jpeg.Baseline.Calliphora; - public static IEnumerable ColorSpaceValues => new[] + public static IEnumerable ColorSpaceValues => new[] { - JpegEncodingColor.Luminance, - JpegEncodingColor.Rgb, - JpegEncodingColor.YCbCrRatio420, - JpegEncodingColor.YCbCrRatio444, + JpegColorType.Luminance, + JpegColorType.Rgb, + JpegColorType.YCbCrRatio420, + JpegColorType.YCbCrRatio444, }; [Params(75, 90, 100)] public int Quality; [ParamsSource(nameof(ColorSpaceValues), Priority = -100)] - public JpegEncodingColor TargetColorSpace; + public JpegColorType TargetColorSpace; private Image bmpCore; private JpegEncoder encoder; diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/IdentifyJpeg.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/IdentifyJpeg.cs index d5ad59b00a..9cc61c741d 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/IdentifyJpeg.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/IdentifyJpeg.cs @@ -8,7 +8,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg; -[Config(typeof(Config.ShortMultiFramework))] +[Config(typeof(Config.Short))] public class IdentifyJpeg { private byte[] jpegBytes; diff --git a/tests/ImageSharp.Benchmarks/Codecs/Png/DecodeFilteredPng.cs b/tests/ImageSharp.Benchmarks/Codecs/Png/DecodeFilteredPng.cs index 986c1431c9..57de8068f0 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Png/DecodeFilteredPng.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Png/DecodeFilteredPng.cs @@ -8,7 +8,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs; -[Config(typeof(Config.ShortMultiFramework))] +[Config(typeof(Config.Short))] public class DecodeFilteredPng { private byte[] filter0; diff --git a/tests/ImageSharp.Benchmarks/Codecs/Png/DecodePng.cs b/tests/ImageSharp.Benchmarks/Codecs/Png/DecodePng.cs index c23fa25cca..2cf62fccf2 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Png/DecodePng.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Png/DecodePng.cs @@ -9,7 +9,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs; -[Config(typeof(Config.ShortMultiFramework))] +[Config(typeof(Config.Short))] public class DecodePng { private byte[] pngBytes; diff --git a/tests/ImageSharp.Benchmarks/Codecs/Png/EncodeIndexedPng.cs b/tests/ImageSharp.Benchmarks/Codecs/Png/EncodeIndexedPng.cs index 26fb0f4a41..a45e7aea9b 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Png/EncodeIndexedPng.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Png/EncodeIndexedPng.cs @@ -14,7 +14,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs; /// Benchmarks saving png files using different quantizers. /// System.Drawing cannot save indexed png files so we cannot compare. /// -[Config(typeof(Config.ShortMultiFramework))] +[Config(typeof(Config.Short))] public class EncodeIndexedPng { // System.Drawing needs this. diff --git a/tests/ImageSharp.Benchmarks/Codecs/Png/EncodePng.cs b/tests/ImageSharp.Benchmarks/Codecs/Png/EncodePng.cs index 5cbe88fee6..4287914783 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Png/EncodePng.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Png/EncodePng.cs @@ -10,7 +10,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs; -[Config(typeof(Config.ShortMultiFramework))] +[Config(typeof(Config.Short))] public class EncodePng { // System.Drawing needs this. diff --git a/tests/ImageSharp.Benchmarks/Codecs/Tga/DecodeTga.cs b/tests/ImageSharp.Benchmarks/Codecs/Tga/DecodeTga.cs index 363ecf908b..2ebab5e001 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Tga/DecodeTga.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Tga/DecodeTga.cs @@ -10,7 +10,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs; -[Config(typeof(Config.ShortMultiFramework))] +[Config(typeof(Config.Short))] public class DecodeTga { private string TestImageFullPath => Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, this.TestImage); diff --git a/tests/ImageSharp.Benchmarks/Codecs/Tga/EncodeTga.cs b/tests/ImageSharp.Benchmarks/Codecs/Tga/EncodeTga.cs index 935706b41b..a7f5e35893 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Tga/EncodeTga.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Tga/EncodeTga.cs @@ -8,7 +8,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs; -[Config(typeof(Config.ShortMultiFramework))] +[Config(typeof(Config.Short))] public class EncodeTga { private MagickImage tgaMagick; diff --git a/tests/ImageSharp.Benchmarks/Codecs/Tiff/DecodeTiff.cs b/tests/ImageSharp.Benchmarks/Codecs/Tiff/DecodeTiff.cs index 83f5fdd213..ecb87e16c5 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Tiff/DecodeTiff.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Tiff/DecodeTiff.cs @@ -15,7 +15,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs; [MarkdownExporter] [HtmlExporter] -[Config(typeof(Config.ShortMultiFramework))] +[Config(typeof(Config.Short))] public class DecodeTiff { private string prevImage; diff --git a/tests/ImageSharp.Benchmarks/Codecs/Tiff/EncodeTiff.cs b/tests/ImageSharp.Benchmarks/Codecs/Tiff/EncodeTiff.cs index ab3b0e95ea..d3e3944051 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Tiff/EncodeTiff.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Tiff/EncodeTiff.cs @@ -14,7 +14,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs; [MarkdownExporter] [HtmlExporter] -[Config(typeof(Config.ShortMultiFramework))] +[Config(typeof(Config.Short))] public class EncodeTiff { private Stream stream; diff --git a/tests/ImageSharp.Benchmarks/Codecs/Webp/DecodeWebp.cs b/tests/ImageSharp.Benchmarks/Codecs/Webp/DecodeWebp.cs index 34a4ad5931..6c71a62b50 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Webp/DecodeWebp.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Webp/DecodeWebp.cs @@ -12,7 +12,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs; [MarkdownExporter] [HtmlExporter] -[Config(typeof(Config.ShortMultiFramework))] +[Config(typeof(Config.Short))] public class DecodeWebp { private Configuration configuration; diff --git a/tests/ImageSharp.Benchmarks/Codecs/Webp/EncodeWebp.cs b/tests/ImageSharp.Benchmarks/Codecs/Webp/EncodeWebp.cs index c5fa8d03da..5be46a2220 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Webp/EncodeWebp.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Webp/EncodeWebp.cs @@ -12,7 +12,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs; [MarkdownExporter] [HtmlExporter] -[Config(typeof(Config.ShortMultiFramework))] +[Config(typeof(Config.Short))] public class EncodeWebp { private MagickImage webpMagick; diff --git a/tests/ImageSharp.Benchmarks/Color/ColorEquality.cs b/tests/ImageSharp.Benchmarks/Color/ColorEquality.cs index 1ff8013b28..5166c89a93 100644 --- a/tests/ImageSharp.Benchmarks/Color/ColorEquality.cs +++ b/tests/ImageSharp.Benchmarks/Color/ColorEquality.cs @@ -1,25 +1,19 @@ -// Copyright (c) Six Labors. +// Copyright (c) Six Labors. // Licensed under the Six Labors Split License. using BenchmarkDotNet.Attributes; - using SixLabors.ImageSharp.PixelFormats; +using SystemColor = System.Drawing.Color; namespace SixLabors.ImageSharp.Benchmarks; -using SystemColor = System.Drawing.Color; - public class ColorEquality { [Benchmark(Baseline = true, Description = "System.Drawing Color Equals")] public bool SystemDrawingColorEqual() - { - return SystemColor.FromArgb(128, 128, 128, 128).Equals(SystemColor.FromArgb(128, 128, 128, 128)); - } + => SystemColor.FromArgb(128, 128, 128, 128).Equals(SystemColor.FromArgb(128, 128, 128, 128)); [Benchmark(Description = "ImageSharp Color Equals")] public bool ColorEqual() - { - return new Rgba32(128, 128, 128, 128).Equals(new Rgba32(128, 128, 128, 128)); - } + => new Rgba32(128, 128, 128, 128).Equals(new Rgba32(128, 128, 128, 128)); } diff --git a/tests/ImageSharp.Benchmarks/Color/ColorspaceCieXyzToCieLabConvert.cs b/tests/ImageSharp.Benchmarks/Color/ColorspaceCieXyzToCieLabConvert.cs index da09a85232..1f8a6b1933 100644 --- a/tests/ImageSharp.Benchmarks/Color/ColorspaceCieXyzToCieLabConvert.cs +++ b/tests/ImageSharp.Benchmarks/Color/ColorspaceCieXyzToCieLabConvert.cs @@ -2,34 +2,25 @@ // Licensed under the Six Labors Split License. using BenchmarkDotNet.Attributes; - using Colourful; - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; +using SixLabors.ImageSharp.ColorProfiles; using Illuminants = Colourful.Illuminants; -namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces; +namespace SixLabors.ImageSharp.Benchmarks.ColorProfiles; public class ColorspaceCieXyzToCieLabConvert { - private static readonly CieXyz CieXyz = new CieXyz(0.95047F, 1, 1.08883F); + private static readonly CieXyz CieXyz = new(0.95047F, 1, 1.08883F); - private static readonly XYZColor XYZColor = new XYZColor(0.95047, 1, 1.08883); + private static readonly XYZColor XYZColor = new(0.95047, 1, 1.08883); - private static readonly ColorSpaceConverter ColorSpaceConverter = new ColorSpaceConverter(); + private static readonly ColorProfileConverter ColorProfileConverter = new(); private static readonly IColorConverter ColourfulConverter = new ConverterBuilder().FromXYZ(Illuminants.D50).ToLab(Illuminants.D50).Build(); [Benchmark(Baseline = true, Description = "Colourful Convert")] - public double ColourfulConvert() - { - return ColourfulConverter.Convert(XYZColor).L; - } + public double ColourfulConvert() => ColourfulConverter.Convert(XYZColor).L; [Benchmark(Description = "ImageSharp Convert")] - public float ColorSpaceConvert() - { - return ColorSpaceConverter.ToCieLab(CieXyz).L; - } + public float ColorSpaceConvert() => ColorProfileConverter.Convert(CieXyz).L; } diff --git a/tests/ImageSharp.Benchmarks/Color/ColorspaceCieXyzToHunterLabConvert.cs b/tests/ImageSharp.Benchmarks/Color/ColorspaceCieXyzToHunterLabConvert.cs index c3317c5d94..b11e788193 100644 --- a/tests/ImageSharp.Benchmarks/Color/ColorspaceCieXyzToHunterLabConvert.cs +++ b/tests/ImageSharp.Benchmarks/Color/ColorspaceCieXyzToHunterLabConvert.cs @@ -2,34 +2,25 @@ // Licensed under the Six Labors Split License. using BenchmarkDotNet.Attributes; - using Colourful; - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; +using SixLabors.ImageSharp.ColorProfiles; using Illuminants = Colourful.Illuminants; -namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces; +namespace SixLabors.ImageSharp.Benchmarks.ColorProfiles; public class ColorspaceCieXyzToHunterLabConvert { - private static readonly CieXyz CieXyz = new CieXyz(0.95047F, 1, 1.08883F); + private static readonly CieXyz CieXyz = new(0.95047F, 1, 1.08883F); - private static readonly XYZColor XYZColor = new XYZColor(0.95047, 1, 1.08883); + private static readonly XYZColor XYZColor = new(0.95047, 1, 1.08883); - private static readonly ColorSpaceConverter ColorSpaceConverter = new ColorSpaceConverter(); + private static readonly ColorProfileConverter ColorProfileConverter = new(); private static readonly IColorConverter ColourfulConverter = new ConverterBuilder().FromXYZ(Illuminants.C).ToHunterLab(Illuminants.C).Build(); [Benchmark(Baseline = true, Description = "Colourful Convert")] - public double ColourfulConvert() - { - return ColourfulConverter.Convert(XYZColor).L; - } + public double ColourfulConvert() => ColourfulConverter.Convert(XYZColor).L; [Benchmark(Description = "ImageSharp Convert")] - public float ColorSpaceConvert() - { - return ColorSpaceConverter.ToHunterLab(CieXyz).L; - } + public float ColorSpaceConvert() => ColorProfileConverter.Convert(CieXyz).L; } diff --git a/tests/ImageSharp.Benchmarks/Color/ColorspaceCieXyzToLmsConvert.cs b/tests/ImageSharp.Benchmarks/Color/ColorspaceCieXyzToLmsConvert.cs index ba213e5b0a..a2c7966d41 100644 --- a/tests/ImageSharp.Benchmarks/Color/ColorspaceCieXyzToLmsConvert.cs +++ b/tests/ImageSharp.Benchmarks/Color/ColorspaceCieXyzToLmsConvert.cs @@ -2,33 +2,24 @@ // Licensed under the Six Labors Split License. using BenchmarkDotNet.Attributes; - using Colourful; +using SixLabors.ImageSharp.ColorProfiles; -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces; +namespace SixLabors.ImageSharp.Benchmarks.ColorProfiles; public class ColorspaceCieXyzToLmsConvert { - private static readonly CieXyz CieXyz = new CieXyz(0.95047F, 1, 1.08883F); + private static readonly CieXyz CieXyz = new(0.95047F, 1, 1.08883F); - private static readonly XYZColor XYZColor = new XYZColor(0.95047, 1, 1.08883); + private static readonly XYZColor XYZColor = new(0.95047, 1, 1.08883); - private static readonly ColorSpaceConverter ColorSpaceConverter = new ColorSpaceConverter(); + private static readonly ColorProfileConverter ColorProfileConverter = new(); private static readonly IColorConverter ColourfulConverter = new ConverterBuilder().FromXYZ().ToLMS().Build(); [Benchmark(Baseline = true, Description = "Colourful Convert")] - public double ColourfulConvert() - { - return ColourfulConverter.Convert(XYZColor).L; - } + public double ColourfulConvert() => ColourfulConverter.Convert(XYZColor).L; [Benchmark(Description = "ImageSharp Convert")] - public float ColorSpaceConvert() - { - return ColorSpaceConverter.ToLms(CieXyz).L; - } + public float ColorSpaceConvert() => ColorProfileConverter.Convert(CieXyz).L; } diff --git a/tests/ImageSharp.Benchmarks/Color/ColorspaceCieXyzToRgbConvert.cs b/tests/ImageSharp.Benchmarks/Color/ColorspaceCieXyzToRgbConvert.cs index d7a5deafa7..b63f925046 100644 --- a/tests/ImageSharp.Benchmarks/Color/ColorspaceCieXyzToRgbConvert.cs +++ b/tests/ImageSharp.Benchmarks/Color/ColorspaceCieXyzToRgbConvert.cs @@ -2,33 +2,24 @@ // Licensed under the Six Labors Split License. using BenchmarkDotNet.Attributes; - using Colourful; +using SixLabors.ImageSharp.ColorProfiles; -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces; +namespace SixLabors.ImageSharp.Benchmarks.ColorProfiles; public class ColorspaceCieXyzToRgbConvert { - private static readonly CieXyz CieXyz = new CieXyz(0.95047F, 1, 1.08883F); + private static readonly CieXyz CieXyz = new(0.95047F, 1, 1.08883F); - private static readonly XYZColor XYZColor = new XYZColor(0.95047, 1, 1.08883); + private static readonly XYZColor XYZColor = new(0.95047, 1, 1.08883); - private static readonly ColorSpaceConverter ColorSpaceConverter = new ColorSpaceConverter(); + private static readonly ColorProfileConverter ColorProfileConverter = new(); private static readonly IColorConverter ColourfulConverter = new ConverterBuilder().FromXYZ(RGBWorkingSpaces.sRGB.WhitePoint).ToRGB(RGBWorkingSpaces.sRGB).Build(); [Benchmark(Baseline = true, Description = "Colourful Convert")] - public double ColourfulConvert() - { - return ColourfulConverter.Convert(XYZColor).R; - } + public double ColourfulConvert() => ColourfulConverter.Convert(XYZColor).R; [Benchmark(Description = "ImageSharp Convert")] - public float ColorSpaceConvert() - { - return ColorSpaceConverter.ToRgb(CieXyz).R; - } + public float ColorSpaceConvert() => ColorProfileConverter.Convert(CieXyz).R; } diff --git a/tests/ImageSharp.Benchmarks/Color/RgbWorkingSpaceAdapt.cs b/tests/ImageSharp.Benchmarks/Color/RgbWorkingSpaceAdapt.cs index 48b4880d94..6cd8df3fc7 100644 --- a/tests/ImageSharp.Benchmarks/Color/RgbWorkingSpaceAdapt.cs +++ b/tests/ImageSharp.Benchmarks/Color/RgbWorkingSpaceAdapt.cs @@ -2,33 +2,24 @@ // Licensed under the Six Labors Split License. using BenchmarkDotNet.Attributes; - using Colourful; +using SixLabors.ImageSharp.ColorProfiles; -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces; +namespace SixLabors.ImageSharp.Benchmarks.ColorProfiles; public class RgbWorkingSpaceAdapt { - private static readonly Rgb Rgb = new Rgb(0.206162F, 0.260277F, 0.746717F, RgbWorkingSpaces.WideGamutRgb); + private static readonly Rgb Rgb = new(0.206162F, 0.260277F, 0.746717F); - private static readonly RGBColor RGBColor = new RGBColor(0.206162, 0.260277, 0.746717); + private static readonly RGBColor RGBColor = new(0.206162, 0.260277, 0.746717); - private static readonly ColorSpaceConverter ColorSpaceConverter = new ColorSpaceConverter(new ColorSpaceConverterOptions { TargetRgbWorkingSpace = RgbWorkingSpaces.SRgb }); + private static readonly ColorProfileConverter ColorProfileConverter = new(new ColorConversionOptions { RgbWorkingSpace = KnownRgbWorkingSpaces.WideGamutRgb, TargetRgbWorkingSpace = KnownRgbWorkingSpaces.SRgb }); private static readonly IColorConverter ColourfulConverter = new ConverterBuilder().FromRGB(RGBWorkingSpaces.WideGamutRGB).ToRGB(RGBWorkingSpaces.sRGB).Build(); [Benchmark(Baseline = true, Description = "Colourful Adapt")] - public RGBColor ColourfulConvert() - { - return ColourfulConverter.Convert(RGBColor); - } + public RGBColor ColourfulConvert() => ColourfulConverter.Convert(RGBColor); [Benchmark(Description = "ImageSharp Adapt")] - public Rgb ColorSpaceConvert() - { - return ColorSpaceConverter.Adapt(Rgb); - } + public Rgb ColorSpaceConvert() => ColorProfileConverter.Convert(Rgb); } diff --git a/tests/ImageSharp.Benchmarks/Color/YcbCrToRgb.cs b/tests/ImageSharp.Benchmarks/Color/YcbCrToRgb.cs index 14d848bcb7..093397ad5f 100644 --- a/tests/ImageSharp.Benchmarks/Color/YcbCrToRgb.cs +++ b/tests/ImageSharp.Benchmarks/Color/YcbCrToRgb.cs @@ -11,9 +11,9 @@ public class YcbCrToRgb [Benchmark(Baseline = true, Description = "Floating Point Conversion")] public Vector3 YcbCrToRgba() { - int y = 255; - int cb = 128; - int cr = 128; + const int y = 255; + const int cb = 128; + const int cr = 128; int ccb = cb - 128; int ccr = cr - 128; @@ -28,9 +28,9 @@ public Vector3 YcbCrToRgba() [Benchmark(Description = "Scaled Integer Conversion")] public Vector3 YcbCrToRgbaScaled() { - int y = 255; - int cb = 128; - int cr = 128; + const int y = 255; + const int cb = 128; + const int cr = 128; int ccb = cb - 128; int ccr = cr - 128; diff --git a/tests/ImageSharp.Benchmarks/Config.HwIntrinsics.cs b/tests/ImageSharp.Benchmarks/Config.HwIntrinsics.cs index 5a0c574f17..92f8917cf8 100644 --- a/tests/ImageSharp.Benchmarks/Config.HwIntrinsics.cs +++ b/tests/ImageSharp.Benchmarks/Config.HwIntrinsics.cs @@ -56,7 +56,7 @@ public class HwIntrinsics_SSE_AVX : Config { public HwIntrinsics_SSE_AVX() { - this.AddJob(Job.Default.WithRuntime(CoreRuntime.Core60) + this.AddJob(Job.Default.WithRuntime(CoreRuntime.Core80) .WithEnvironmentVariables( new EnvironmentVariable(EnableHWIntrinsic, Off), new EnvironmentVariable(FeatureSIMD, Off)) @@ -64,14 +64,14 @@ public HwIntrinsics_SSE_AVX() if (Sse.IsSupported) { - this.AddJob(Job.Default.WithRuntime(CoreRuntime.Core60) + this.AddJob(Job.Default.WithRuntime(CoreRuntime.Core80) .WithEnvironmentVariables(new EnvironmentVariable(EnableAVX, Off)) .WithId("2. SSE")); } if (Avx.IsSupported) { - this.AddJob(Job.Default.WithRuntime(CoreRuntime.Core60) + this.AddJob(Job.Default.WithRuntime(CoreRuntime.Core80) .WithId("3. AVX")); } } diff --git a/tests/ImageSharp.Benchmarks/Config.cs b/tests/ImageSharp.Benchmarks/Config.cs index d95f4a202c..06e857484d 100644 --- a/tests/ImageSharp.Benchmarks/Config.cs +++ b/tests/ImageSharp.Benchmarks/Config.cs @@ -29,25 +29,25 @@ public Config() this.SummaryStyle = SummaryStyle.Default.WithMaxParameterColumnWidth(50); } - public class MultiFramework : Config + public class Standard : Config { - public MultiFramework() => this.AddJob( - Job.Default.WithRuntime(CoreRuntime.Core60).WithArguments(new Argument[] { new MsBuildArgument("/p:DebugType=portable") })); + public Standard() => this.AddJob( + Job.Default.WithRuntime(CoreRuntime.Core80).WithArguments(new Argument[] { new MsBuildArgument("/p:DebugType=portable") })); } - public class ShortMultiFramework : Config + public class Short : Config { - public ShortMultiFramework() => this.AddJob( - Job.Default.WithRuntime(CoreRuntime.Core60).WithLaunchCount(1).WithWarmupCount(3).WithIterationCount(3).WithArguments(new Argument[] { new MsBuildArgument("/p:DebugType=portable") })); - } - - public class ShortCore31 : Config - { - public ShortCore31() - => this.AddJob(Job.Default.WithRuntime(CoreRuntime.Core31).WithLaunchCount(1).WithWarmupCount(3).WithIterationCount(3)); + public Short() => this.AddJob( + Job.Default.WithRuntime(CoreRuntime.Core80) + .WithLaunchCount(1) + .WithWarmupCount(3) + .WithIterationCount(3) + .WithArguments(new Argument[] { new MsBuildArgument("/p:DebugType=portable") })); } #if OS_WINDOWS +#pragma warning disable CA1416 // Validate platform compatibility private bool IsElevated => new WindowsPrincipal(WindowsIdentity.GetCurrent()).IsInRole(WindowsBuiltInRole.Administrator); +#pragma warning restore CA1416 // Validate platform compatibility #endif } diff --git a/tests/ImageSharp.Benchmarks/General/Adler32Benchmark.cs b/tests/ImageSharp.Benchmarks/General/Adler32Benchmark.cs index 1aac3cff50..30023feca8 100644 --- a/tests/ImageSharp.Benchmarks/General/Adler32Benchmark.cs +++ b/tests/ImageSharp.Benchmarks/General/Adler32Benchmark.cs @@ -7,7 +7,7 @@ namespace SixLabors.ImageSharp.Benchmarks.General; -[Config(typeof(Config.ShortMultiFramework))] +[Config(typeof(Config.Short))] public class Adler32Benchmark { private byte[] data; diff --git a/tests/ImageSharp.Benchmarks/General/CopyBuffers.cs b/tests/ImageSharp.Benchmarks/General/CopyBuffers.cs index 3929f7c5ac..031f9ecf27 100644 --- a/tests/ImageSharp.Benchmarks/General/CopyBuffers.cs +++ b/tests/ImageSharp.Benchmarks/General/CopyBuffers.cs @@ -14,7 +14,7 @@ namespace SixLabors.ImageSharp.Benchmarks.General; /// - Span.CopyTo() has terrible performance on classic .NET Framework /// - Buffer.MemoryCopy() performance is good enough for all sizes (but needs pinning) /// -[Config(typeof(Config.ShortMultiFramework))] +[Config(typeof(Config.Short))] public class CopyBuffers { private byte[] destArray; diff --git a/tests/ImageSharp.Benchmarks/General/Crc32Benchmark.cs b/tests/ImageSharp.Benchmarks/General/Crc32Benchmark.cs deleted file mode 100644 index fdc9e26b60..0000000000 --- a/tests/ImageSharp.Benchmarks/General/Crc32Benchmark.cs +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using BenchmarkDotNet.Attributes; -using SixLabors.ImageSharp.Compression.Zlib; -using SharpCrc32 = ICSharpCode.SharpZipLib.Checksum.Crc32; - -namespace SixLabors.ImageSharp.Benchmarks.General; - -[Config(typeof(Config.ShortMultiFramework))] -public class Crc32Benchmark -{ - private byte[] data; - private readonly SharpCrc32 crc = new SharpCrc32(); - - [Params(1024, 2048, 4096)] - public int Count { get; set; } - - [GlobalSetup] - public void SetUp() - { - this.data = new byte[this.Count]; - new Random(1).NextBytes(this.data); - } - - [Benchmark(Baseline = true)] - public long SharpZipLibCalculate() - { - this.crc.Reset(); - this.crc.Update(this.data); - return this.crc.Value; - } - - [Benchmark] - public long SixLaborsCalculate() - { - return Crc32.Calculate(this.data); - } -} - -// ########## 17/05/2020 ########## -// -// | Method | Runtime | Count | Mean | Error | StdDev | Ratio | RatioSD | Gen 0 | Gen 1 | Gen 2 | Allocated | -// |--------------------- |-------------- |------ |-------------:|-------------:|-----------:|------:|--------:|------:|------:|------:|----------:| -// | SharpZipLibCalculate | .NET 4.7.2 | 1024 | 2,797.77 ns | 278.697 ns | 15.276 ns | 1.00 | 0.00 | - | - | - | - | -// | SixLaborsCalculate | .NET 4.7.2 | 1024 | 2,275.56 ns | 216.100 ns | 11.845 ns | 0.81 | 0.01 | - | - | - | - | -// | | | | | | | | | | | | | -// | SharpZipLibCalculate | .NET Core 2.1 | 1024 | 2,923.43 ns | 2,656.882 ns | 145.633 ns | 1.00 | 0.00 | - | - | - | - | -// | SixLaborsCalculate | .NET Core 2.1 | 1024 | 2,257.79 ns | 75.081 ns | 4.115 ns | 0.77 | 0.04 | - | - | - | - | -// | | | | | | | | | | | | | -// | SharpZipLibCalculate | .NET Core 3.1 | 1024 | 2,764.14 ns | 86.281 ns | 4.729 ns | 1.00 | 0.00 | - | - | - | - | -// | SixLaborsCalculate | .NET Core 3.1 | 1024 | 49.32 ns | 1.813 ns | 0.099 ns | 0.02 | 0.00 | - | - | - | - | -// | | | | | | | | | | | | | -// | SharpZipLibCalculate | .NET 4.7.2 | 2048 | 5,603.71 ns | 427.240 ns | 23.418 ns | 1.00 | 0.00 | - | - | - | - | -// | SixLaborsCalculate | .NET 4.7.2 | 2048 | 4,525.02 ns | 33.931 ns | 1.860 ns | 0.81 | 0.00 | - | - | - | - | -// | | | | | | | | | | | | | -// | SharpZipLibCalculate | .NET Core 2.1 | 2048 | 5,563.32 ns | 49.337 ns | 2.704 ns | 1.00 | 0.00 | - | - | - | - | -// | SixLaborsCalculate | .NET Core 2.1 | 2048 | 4,519.61 ns | 29.837 ns | 1.635 ns | 0.81 | 0.00 | - | - | - | - | -// | | | | | | | | | | | | | -// | SharpZipLibCalculate | .NET Core 3.1 | 2048 | 5,543.37 ns | 518.551 ns | 28.424 ns | 1.00 | 0.00 | - | - | - | - | -// | SixLaborsCalculate | .NET Core 3.1 | 2048 | 89.07 ns | 3.312 ns | 0.182 ns | 0.02 | 0.00 | - | - | - | - | -// | | | | | | | | | | | | | -// | SharpZipLibCalculate | .NET 4.7.2 | 4096 | 11,396.95 ns | 373.450 ns | 20.470 ns | 1.00 | 0.00 | - | - | - | - | -// | SixLaborsCalculate | .NET 4.7.2 | 4096 | 9,070.35 ns | 271.083 ns | 14.859 ns | 0.80 | 0.00 | - | - | - | - | -// | | | | | | | | | | | | | -// | SharpZipLibCalculate | .NET Core 2.1 | 4096 | 11,127.81 ns | 239.177 ns | 13.110 ns | 1.00 | 0.00 | - | - | - | - | -// | SixLaborsCalculate | .NET Core 2.1 | 4096 | 9,050.46 ns | 230.916 ns | 12.657 ns | 0.81 | 0.00 | - | - | - | - | -// | | | | | | | | | | | | | -// | SharpZipLibCalculate | .NET Core 3.1 | 4096 | 11,098.62 ns | 687.978 ns | 37.710 ns | 1.00 | 0.00 | - | - | - | - | -// | SixLaborsCalculate | .NET Core 3.1 | 4096 | 168.11 ns | 3.633 ns | 0.199 ns | 0.02 | 0.00 | - | - | - | - | diff --git a/tests/ImageSharp.Benchmarks/General/GetSetPixel.cs b/tests/ImageSharp.Benchmarks/General/GetSetPixel.cs index a6aac20c3b..5ba7809e13 100644 --- a/tests/ImageSharp.Benchmarks/General/GetSetPixel.cs +++ b/tests/ImageSharp.Benchmarks/General/GetSetPixel.cs @@ -21,7 +21,7 @@ public System.Drawing.Color GetSetSystemDrawing() public Rgba32 GetSetImageSharp() { using Image image = new(400, 400); - image[200, 200] = Color.White; + image[200, 200] = Color.White.ToPixel(); return image[200, 200]; } } diff --git a/tests/ImageSharp.Benchmarks/General/IO/BufferedStreams.cs b/tests/ImageSharp.Benchmarks/General/IO/BufferedStreams.cs index 2a926d1cd8..9560d6ee71 100644 --- a/tests/ImageSharp.Benchmarks/General/IO/BufferedStreams.cs +++ b/tests/ImageSharp.Benchmarks/General/IO/BufferedStreams.cs @@ -6,7 +6,7 @@ namespace SixLabors.ImageSharp.Benchmarks.IO; -[Config(typeof(Config.ShortMultiFramework))] +[Config(typeof(Config.Short))] public class BufferedStreams { private readonly byte[] buffer = CreateTestBytes(); diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/ITestPixel.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/ITestPixel.cs index 8820406af6..82f0da5052 100644 --- a/tests/ImageSharp.Benchmarks/General/PixelConversion/ITestPixel.cs +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/ITestPixel.cs @@ -11,19 +11,23 @@ public interface ITestPixel { void FromRgba32(Rgba32 source); + static abstract T StaticFromRgba32(Rgba32 source); + void FromRgba32(ref Rgba32 source); void FromBytes(byte r, byte g, byte b, byte a); void FromVector4(Vector4 source); + static abstract T StaticFromVector4(Vector4 source); + void FromVector4(ref Vector4 source); Rgba32 ToRgba32(); - void CopyToRgba32(ref Rgba32 dest); + void CopyToRgba32(ref Rgba32 destination); Vector4 ToVector4(); - void CopyToVector4(ref Vector4 dest); + void CopyToVector4(ref Vector4 destination); } diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromRgba32.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromRgba32.cs index 8d16849825..1d83b94dc8 100644 --- a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromRgba32.cs +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromRgba32.cs @@ -13,25 +13,25 @@ namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion; public abstract class PixelConversion_ConvertFromRgba32 { - internal struct ConversionRunner + internal readonly struct ConversionRunner where T : struct, ITestPixel { - public readonly T[] Dest; + public readonly T[] Destination; public readonly Rgba32[] Source; public ConversionRunner(int count) { - this.Dest = new T[count]; + this.Destination = new T[count]; this.Source = new Rgba32[count]; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void RunByRefConversion() + public readonly void RunByRefConversion() { - int count = this.Dest.Length; + int count = this.Destination.Length; - ref T destBaseRef = ref this.Dest[0]; + ref T destBaseRef = ref this.Destination[0]; ref Rgba32 sourceBaseRef = ref this.Source[0]; for (nuint i = 0; i < (uint)count; i++) @@ -41,11 +41,11 @@ public void RunByRefConversion() } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void RunByValConversion() + public readonly void RunByValConversion() { - int count = this.Dest.Length; + int count = this.Destination.Length; - ref T destBaseRef = ref this.Dest[0]; + ref T destBaseRef = ref this.Destination[0]; ref Rgba32 sourceBaseRef = ref this.Source[0]; for (nuint i = 0; i < (uint)count; i++) @@ -55,11 +55,25 @@ public void RunByValConversion() } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void RunFromBytesConversion() + public readonly void RunStaticByValConversion() { - int count = this.Dest.Length; + int count = this.Destination.Length; - ref T destBaseRef = ref this.Dest[0]; + ref T destBaseRef = ref this.Destination[0]; + ref Rgba32 sourceBaseRef = ref this.Source[0]; + + for (nuint i = 0; i < (uint)count; i++) + { + Unsafe.Add(ref destBaseRef, i) = T.StaticFromRgba32(Unsafe.Add(ref sourceBaseRef, i)); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly void RunFromBytesConversion() + { + int count = this.Destination.Length; + + ref T destBaseRef = ref this.Destination[0]; ref Rgba32 sourceBaseRef = ref this.Source[0]; for (nuint i = 0; i < (uint)count; i++) @@ -74,6 +88,8 @@ public void RunFromBytesConversion() internal ConversionRunner PermutedRunnerRgbaToArgb; + internal ConversionRunner RunnerRgbaToRgbaVector; + [Params(256, 2048)] public int Count { get; set; } @@ -82,34 +98,29 @@ public void Setup() { this.CompatibleMemLayoutRunner = new ConversionRunner(this.Count); this.PermutedRunnerRgbaToArgb = new ConversionRunner(this.Count); + this.RunnerRgbaToRgbaVector = new ConversionRunner(this.Count); } } public class PixelConversion_ConvertFromRgba32_Compatible : PixelConversion_ConvertFromRgba32 { [Benchmark(Baseline = true)] - public void ByRef() - { - this.CompatibleMemLayoutRunner.RunByRefConversion(); - } + public void ByRef() => this.CompatibleMemLayoutRunner.RunByRefConversion(); [Benchmark] - public void ByVal() - { - this.CompatibleMemLayoutRunner.RunByValConversion(); - } + public void ByVal() => this.CompatibleMemLayoutRunner.RunByValConversion(); [Benchmark] - public void FromBytes() - { - this.CompatibleMemLayoutRunner.RunFromBytesConversion(); - } + public void StaticByVal() => this.CompatibleMemLayoutRunner.RunStaticByValConversion(); + + [Benchmark] + public void FromBytes() => this.CompatibleMemLayoutRunner.RunFromBytesConversion(); [Benchmark] public void Inline() { ref Rgba32 sBase = ref this.CompatibleMemLayoutRunner.Source[0]; - ref Rgba32 dBase = ref Unsafe.As(ref this.CompatibleMemLayoutRunner.Dest[0]); + ref Rgba32 dBase = ref Unsafe.As(ref this.CompatibleMemLayoutRunner.Destination[0]); for (nuint i = 0; i < (uint)this.Count; i++) { @@ -117,39 +128,49 @@ public void Inline() } } - /* Method | Count | Mean | Error | StdDev | Scaled | ScaledSD | - ---------- |------ |---------:|---------:|---------:|-------:|---------:| - ByRef | 256 | 128.5 ns | 1.217 ns | 1.138 ns | 1.00 | 0.00 | - ByVal | 256 | 196.7 ns | 2.792 ns | 2.612 ns | 1.53 | 0.02 | - FromBytes | 256 | 321.7 ns | 2.180 ns | 1.820 ns | 2.50 | 0.03 | - Inline | 256 | 129.9 ns | 2.759 ns | 2.581 ns | 1.01 | 0.02 | */ + /* + BenchmarkDotNet v0.13.10, Windows 11 (10.0.22631.3007/23H2/2023Update/SunValley3) + 11th Gen Intel Core i7-11370H 3.30GHz, 1 CPU, 8 logical and 4 physical cores + .NET SDK 8.0.200-preview.23624.5 + [Host] : .NET 8.0.1 (8.0.123.58001), X64 RyuJIT AVX2 + DefaultJob : .NET 8.0.1 (8.0.123.58001), X64 RyuJIT AVX2 + + + | Method | Count | Mean | Error | StdDev | Ratio | + |------------ |------ |-----------:|--------:|--------:|------:| + | ByRef | 256 | 103.4 ns | 0.52 ns | 0.46 ns | 1.00 | + | ByVal | 256 | 103.3 ns | 1.48 ns | 1.38 ns | 1.00 | + | StaticByVal | 256 | 104.0 ns | 0.36 ns | 0.30 ns | 1.01 | + | FromBytes | 256 | 201.8 ns | 1.30 ns | 1.15 ns | 1.95 | + | Inline | 256 | 106.6 ns | 0.40 ns | 0.34 ns | 1.03 | + | | | | | | | + | ByRef | 2048 | 771.5 ns | 3.68 ns | 3.27 ns | 1.00 | + | ByVal | 2048 | 769.7 ns | 3.39 ns | 2.83 ns | 1.00 | + | StaticByVal | 2048 | 773.2 ns | 3.95 ns | 3.50 ns | 1.00 | + | FromBytes | 2048 | 1,555.3 ns | 9.24 ns | 8.19 ns | 2.02 | + | Inline | 2048 | 799.5 ns | 5.91 ns | 4.93 ns | 1.04 | + */ } public class PixelConversion_ConvertFromRgba32_Permuted_RgbaToArgb : PixelConversion_ConvertFromRgba32 { [Benchmark(Baseline = true)] - public void ByRef() - { - this.PermutedRunnerRgbaToArgb.RunByRefConversion(); - } + public void ByRef() => this.PermutedRunnerRgbaToArgb.RunByRefConversion(); [Benchmark] - public void ByVal() - { - this.PermutedRunnerRgbaToArgb.RunByValConversion(); - } + public void ByVal() => this.PermutedRunnerRgbaToArgb.RunByValConversion(); [Benchmark] - public void FromBytes() - { - this.PermutedRunnerRgbaToArgb.RunFromBytesConversion(); - } + public void StaticByVal() => this.PermutedRunnerRgbaToArgb.RunStaticByValConversion(); + + [Benchmark] + public void FromBytes() => this.PermutedRunnerRgbaToArgb.RunFromBytesConversion(); [Benchmark] public void InlineShuffle() { ref Rgba32 sBase = ref this.PermutedRunnerRgbaToArgb.Source[0]; - ref TestArgb dBase = ref this.PermutedRunnerRgbaToArgb.Dest[0]; + ref TestArgb dBase = ref this.PermutedRunnerRgbaToArgb.Destination[0]; for (nuint i = 0; i < (uint)this.Count; i++) { @@ -167,25 +188,64 @@ public void InlineShuffle() public void PixelConverter_Rgba32_ToArgb32() { Span source = MemoryMarshal.Cast(this.PermutedRunnerRgbaToArgb.Source); - Span dest = MemoryMarshal.Cast(this.PermutedRunnerRgbaToArgb.Dest); + Span dest = MemoryMarshal.Cast(this.PermutedRunnerRgbaToArgb.Destination); PixelConverter.FromRgba32.ToArgb32(source, dest); } /* - RESULTS: - | Method | Count | Mean | Error | StdDev | Median | Ratio | RatioSD | - |------------------------------- |------ |------------:|----------:|----------:|------------:|------:|--------:| - | ByRef | 256 | 288.84 ns | 19.601 ns | 52.319 ns | 268.10 ns | 1.00 | 0.00 | - | ByVal | 256 | 267.97 ns | 1.831 ns | 1.713 ns | 267.85 ns | 0.77 | 0.18 | - | FromBytes | 256 | 266.81 ns | 2.427 ns | 2.270 ns | 266.47 ns | 0.76 | 0.18 | - | InlineShuffle | 256 | 291.41 ns | 5.820 ns | 5.444 ns | 290.17 ns | 0.83 | 0.19 | - | PixelConverter_Rgba32_ToArgb32 | 256 | 38.62 ns | 0.431 ns | 0.403 ns | 38.68 ns | 0.11 | 0.03 | - | | | | | | | | | - | ByRef | 2048 | 2,197.69 ns | 15.826 ns | 14.804 ns | 2,197.25 ns | 1.00 | 0.00 | - | ByVal | 2048 | 2,226.81 ns | 44.266 ns | 62.054 ns | 2,197.17 ns | 1.03 | 0.04 | - | FromBytes | 2048 | 2,181.35 ns | 18.033 ns | 16.868 ns | 2,185.97 ns | 0.99 | 0.01 | - | InlineShuffle | 2048 | 2,233.10 ns | 27.673 ns | 24.531 ns | 2,229.78 ns | 1.02 | 0.01 | - | PixelConverter_Rgba32_ToArgb32 | 2048 | 139.90 ns | 2.152 ns | 3.825 ns | 138.70 ns | 0.06 | 0.00 | + BenchmarkDotNet v0.13.10, Windows 11 (10.0.22631.3007/23H2/2023Update/SunValley3) + 11th Gen Intel Core i7-11370H 3.30GHz, 1 CPU, 8 logical and 4 physical cores + .NET SDK 8.0.200-preview.23624.5 + [Host] : .NET 8.0.1 (8.0.123.58001), X64 RyuJIT AVX2 + DefaultJob : .NET 8.0.1 (8.0.123.58001), X64 RyuJIT AVX2 + + + | Method | Count | Mean | Error | StdDev | Ratio | RatioSD | + |------------------------------- |------ |------------:|----------:|---------:|------:|--------:| + | ByRef | 256 | 203.48 ns | 3.318 ns | 3.104 ns | 1.00 | 0.00 | + | ByVal | 256 | 201.46 ns | 2.242 ns | 1.872 ns | 0.99 | 0.02 | + | StaticByVal | 256 | 201.45 ns | 0.791 ns | 0.701 ns | 0.99 | 0.02 | + | FromBytes | 256 | 200.76 ns | 1.365 ns | 1.140 ns | 0.99 | 0.01 | + | InlineShuffle | 256 | 221.65 ns | 2.104 ns | 1.968 ns | 1.09 | 0.02 | + | PixelConverter_Rgba32_ToArgb32 | 256 | 26.23 ns | 0.277 ns | 0.231 ns | 0.13 | 0.00 | + | | | | | | | | + | ByRef | 2048 | 1,561.54 ns | 11.208 ns | 8.751 ns | 1.00 | 0.00 | + | ByVal | 2048 | 1,554.26 ns | 9.607 ns | 8.517 ns | 1.00 | 0.01 | + | StaticByVal | 2048 | 1,562.48 ns | 8.937 ns | 8.360 ns | 1.00 | 0.01 | + | FromBytes | 2048 | 1,552.68 ns | 7.445 ns | 5.812 ns | 0.99 | 0.01 | + | InlineShuffle | 2048 | 1,711.28 ns | 7.559 ns | 6.312 ns | 1.10 | 0.01 | + | PixelConverter_Rgba32_ToArgb32 | 2048 | 94.43 ns | 0.363 ns | 0.322 ns | 0.06 | 0.00 | + */ +} + +public class PixelConversion_ConvertFromRgba32_RgbaToRgbaVector : PixelConversion_ConvertFromRgba32 +{ + [Benchmark(Baseline = true)] + public void ByRef() => this.RunnerRgbaToRgbaVector.RunByRefConversion(); + + [Benchmark] + public void ByVal() => this.RunnerRgbaToRgbaVector.RunByValConversion(); + + [Benchmark] + public void StaticByVal() => this.RunnerRgbaToRgbaVector.RunStaticByValConversion(); + + /* + BenchmarkDotNet v0.13.10, Windows 11 (10.0.22631.3007/23H2/2023Update/SunValley3) + 11th Gen Intel Core i7-11370H 3.30GHz, 1 CPU, 8 logical and 4 physical cores + .NET SDK 8.0.200-preview.23624.5 + [Host] : .NET 8.0.1 (8.0.123.58001), X64 RyuJIT AVX2 + DefaultJob : .NET 8.0.1 (8.0.123.58001), X64 RyuJIT AVX2 + + + | Method | Count | Mean | Error | StdDev | Ratio | RatioSD | + |------------ |------ |-----------:|---------:|---------:|------:|--------:| + | ByRef | 256 | 448.5 ns | 4.86 ns | 4.06 ns | 1.00 | 0.00 | + | ByVal | 256 | 447.0 ns | 1.55 ns | 1.21 ns | 1.00 | 0.01 | + | StaticByVal | 256 | 447.4 ns | 1.67 ns | 1.30 ns | 1.00 | 0.01 | + | | | | | | | | + | ByRef | 2048 | 3,577.7 ns | 53.80 ns | 47.69 ns | 1.00 | 0.00 | + | ByVal | 2048 | 3,590.5 ns | 43.59 ns | 36.40 ns | 1.00 | 0.02 | + | StaticByVal | 2048 | 3,604.6 ns | 16.19 ns | 14.36 ns | 1.01 | 0.01 | */ } diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromVector4.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromVector4.cs index dd85d06417..57f79ba1f3 100644 --- a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromVector4.cs +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromVector4.cs @@ -13,43 +13,6 @@ namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion; public class PixelConversion_ConvertFromVector4 { - [StructLayout(LayoutKind.Sequential)] - private struct TestRgbaVector : ITestPixel - { - private Vector4 v; - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void FromVector4(Vector4 p) - { - this.v = p; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void FromVector4(ref Vector4 p) - { - this.v = p; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToVector4() => this.v; - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void CopyToVector4(ref Vector4 dest) - { - dest = this.v; - } - - public void FromRgba32(Rgba32 source) => throw new System.NotImplementedException(); - - public void FromRgba32(ref Rgba32 source) => throw new System.NotImplementedException(); - - public void FromBytes(byte r, byte g, byte b, byte a) => throw new System.NotImplementedException(); - - public Rgba32 ToRgba32() => throw new System.NotImplementedException(); - - public void CopyToRgba32(ref Rgba32 dest) => throw new System.NotImplementedException(); - } - private struct ConversionRunner where T : struct, ITestPixel { 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 0ee507832a..a8c6a021ae 100644 --- a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_Rgba32_To_Argb32.cs +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_Rgba32_To_Argb32.cs @@ -12,8 +12,7 @@ namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion; public class PixelConversion_Rgba32_To_Argb32 { private Rgba32[] source; - - private Argb32[] dest; + private Argb32[] destination; [Params(64)] public int Count { get; set; } @@ -22,19 +21,19 @@ public class PixelConversion_Rgba32_To_Argb32 public void Setup() { this.source = new Rgba32[this.Count]; - this.dest = new Argb32[this.Count]; + this.destination = new Argb32[this.Count]; } [Benchmark(Baseline = true)] public void Default() { ref Rgba32 sBase = ref this.source[0]; - ref Argb32 dBase = ref this.dest[0]; + ref Argb32 dBase = ref this.destination[0]; for (nuint i = 0; i < (uint)this.Count; i++) { Rgba32 s = Unsafe.Add(ref sBase, i); - Unsafe.Add(ref dBase, i).FromRgba32(s); + Unsafe.Add(ref dBase, i) = Argb32.FromRgba32(s); } } @@ -48,21 +47,18 @@ private static void Default_GenericImpl(ReadOnlySpan source, Spa for (nuint i = 0; i < (uint)source.Length; i++) { Rgba32 s = Unsafe.Add(ref sBase, i); - Unsafe.Add(ref dBase, i).FromRgba32(s); + Unsafe.Add(ref dBase, i) = TPixel.FromRgba32(s); } } [Benchmark] - public void Default_Generic() - { - Default_GenericImpl(this.source.AsSpan(), this.dest.AsSpan()); - } + public void Default_Generic() => Default_GenericImpl(this.source.AsSpan(), this.destination.AsSpan()); [Benchmark] public void Default_Group2() { ref Rgba32 sBase = ref this.source[0]; - ref Argb32 dBase = ref this.dest[0]; + ref Argb32 dBase = ref this.destination[0]; for (nuint i = 0; i < (uint)this.Count; i += 2) { @@ -70,8 +66,8 @@ public void Default_Group2() Rgba32 s1 = Unsafe.Add(ref s0, 1); ref Argb32 d0 = ref Unsafe.Add(ref dBase, i); - d0.FromRgba32(s0); - Unsafe.Add(ref d0, 1).FromRgba32(s1); + d0 = Argb32.FromRgba32(s0); + Unsafe.Add(ref d0, 1) = Argb32.FromRgba32(s1); } } @@ -79,7 +75,7 @@ public void Default_Group2() public void Default_Group4() { ref Rgba32 sBase = ref this.source[0]; - ref Argb32 dBase = ref this.dest[0]; + ref Argb32 dBase = ref this.destination[0]; for (nuint i = 0; i < (uint)this.Count; i += 4) { @@ -92,10 +88,10 @@ public void Default_Group4() ref Argb32 d1 = ref Unsafe.Add(ref d0, 1); ref Argb32 d2 = ref Unsafe.Add(ref d1, 1); - d0.FromRgba32(s0); - d1.FromRgba32(s1); - d2.FromRgba32(s2); - Unsafe.Add(ref d2, 1).FromRgba32(s3); + d0 = Argb32.FromRgba32(s0); + d1 = Argb32.FromRgba32(s1); + d2 = Argb32.FromRgba32(s2); + Unsafe.Add(ref d2, 1) = Argb32.FromRgba32(s3); } } @@ -103,7 +99,7 @@ public void Default_Group4() public void BitOps() { ref uint sBase = ref Unsafe.As(ref this.source[0]); - ref uint dBase = ref Unsafe.As(ref this.dest[0]); + ref uint dBase = ref Unsafe.As(ref this.destination[0]); for (nuint i = 0; i < (uint)this.Count; i++) { @@ -116,7 +112,7 @@ public void BitOps() public void BitOps_GroupAsULong() { ref ulong sBase = ref Unsafe.As(ref this.source[0]); - ref ulong dBase = ref Unsafe.As(ref this.dest[0]); + ref ulong dBase = ref Unsafe.As(ref this.destination[0]); for (nuint i = 0; i < (uint)this.Count / 2; i++) { @@ -134,10 +130,6 @@ public void BitOps_GroupAsULong() public static class FromRgba32 { - /// - /// Converts a packed to . - /// - /// The argb value. [MethodImpl(InliningOptions.ShortMethod)] public static uint ToArgb32(uint packedRgba) { @@ -146,10 +138,6 @@ public static uint ToArgb32(uint packedRgba) return (packedRgba << 8) | (packedRgba >> 24); } - /// - /// Converts a packed to . - /// - /// The bgra value. [MethodImpl(InliningOptions.ShortMethod)] public static uint ToBgra32(uint packedRgba) { 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 499f3483dc..f4fb9e4204 100644 --- a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_Rgba32_To_Bgra32.cs +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_Rgba32_To_Bgra32.cs @@ -55,7 +55,7 @@ public void Default() for (nuint i = 0; i < (uint)this.Count; i++) { ref Rgba32 s = ref Unsafe.Add(ref sBase, i); - Unsafe.Add(ref dBase, i).FromRgba32(s); + Unsafe.Add(ref dBase, i) = Bgra32.FromRgba32(s); } } @@ -69,15 +69,12 @@ private static void Default_GenericImpl(ReadOnlySpan source, Spa for (nuint i = 0; i < (uint)source.Length; i++) { ref Rgba32 s = ref Unsafe.Add(ref sBase, i); - Unsafe.Add(ref dBase, i).FromRgba32(s); + Unsafe.Add(ref dBase, i) = TPixel.FromRgba32(s); } } [Benchmark] - public void Default_Generic() - { - Default_GenericImpl(this.source.AsSpan(), this.dest.AsSpan()); - } + public void Default_Generic() => Default_GenericImpl(this.source.AsSpan(), this.dest.AsSpan()); [Benchmark] public void Default_Group2() @@ -91,8 +88,8 @@ public void Default_Group2() Rgba32 s1 = Unsafe.Add(ref s0, 1); ref Bgra32 d0 = ref Unsafe.Add(ref dBase, i); - d0.FromRgba32(s0); - Unsafe.Add(ref d0, 1).FromRgba32(s1); + d0 = Bgra32.FromRgba32(s0); + Unsafe.Add(ref d0, 1) = Bgra32.FromRgba32(s1); } } @@ -113,10 +110,10 @@ public void Default_Group4() ref Bgra32 d1 = ref Unsafe.Add(ref d0, 1); ref Bgra32 d2 = ref Unsafe.Add(ref d1, 1); - d0.FromRgba32(s0); - d1.FromRgba32(s1); - d2.FromRgba32(s2); - Unsafe.Add(ref d2, 1).FromRgba32(s3); + d0 = Bgra32.FromRgba32(s0); + d1 = Bgra32.FromRgba32(s1); + d2 = Bgra32.FromRgba32(s2); + Unsafe.Add(ref d2, 1) = Bgra32.FromRgba32(s3); } } @@ -138,18 +135,15 @@ private static void Group4GenericImpl(ReadOnlySpan source, Span< ref TPixel d1 = ref Unsafe.Add(ref d0, 1); ref TPixel d2 = ref Unsafe.Add(ref d1, 1); - d0.FromRgba32(s0); - d1.FromRgba32(s1); - d2.FromRgba32(s2); - Unsafe.Add(ref d2, 1).FromRgba32(s3); + d0 = TPixel.FromRgba32(s0); + d1 = TPixel.FromRgba32(s1); + d2 = TPixel.FromRgba32(s2); + Unsafe.Add(ref d2, 1) = TPixel.FromRgba32(s3); } } // [Benchmark] - public void Default_Group4_Generic() - { - Group4GenericImpl(this.source.AsSpan(), this.dest.AsSpan()); - } + public void Default_Group4_Generic() => Group4GenericImpl(this.source.AsSpan(), this.dest.AsSpan()); // [Benchmark] public void Default_Group8() @@ -178,15 +172,15 @@ public void Default_Group8() ref Bgra32 d5 = ref Unsafe.Add(ref d4, 1); ref Bgra32 d6 = ref Unsafe.Add(ref d5, 1); - d0.FromRgba32(s0); - d1.FromRgba32(s1); - d2.FromRgba32(s2); - d3.FromRgba32(s3); + d0 = Bgra32.FromRgba32(s0); + d1 = Bgra32.FromRgba32(s1); + d2 = Bgra32.FromRgba32(s2); + d3 = Bgra32.FromRgba32(s3); - d4.FromRgba32(s4); - d5.FromRgba32(s5); - d6.FromRgba32(s6); - Unsafe.Add(ref d6, 1).FromRgba32(s7); + d4 = Bgra32.FromRgba32(s4); + d5 = Bgra32.FromRgba32(s5); + d6 = Bgra32.FromRgba32(s6); + Unsafe.Add(ref d6, 1) = Bgra32.FromRgba32(s7); } } @@ -352,10 +346,6 @@ public void BitOps_GroupAsULong_V2() public static class FromRgba32 { - /// - /// Converts a packed to . - /// - /// The argb value. [MethodImpl(InliningOptions.ShortMethod)] public static uint ToArgb32(uint packedRgba) { @@ -364,10 +354,6 @@ public static uint ToArgb32(uint packedRgba) return (packedRgba << 8) | (packedRgba >> 24); } - /// - /// Converts a packed to . - /// - /// The bgra value. [MethodImpl(InliningOptions.ShortMethod)] public static uint ToBgra32(uint packedRgba) { diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/TestArgb.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/TestArgb.cs index 84698a0e19..21bef5a156 100644 --- a/tests/ImageSharp.Benchmarks/General/PixelConversion/TestArgb.cs +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/TestArgb.cs @@ -4,6 +4,7 @@ using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion; @@ -16,26 +17,20 @@ public struct TestArgb : ITestPixel public byte G; public byte B; - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void FromRgba32(Rgba32 p) - { - this.R = p.R; - this.G = p.G; - this.B = p.B; - this.A = p.A; - } + private static readonly Vector4 MaxBytes = Vector128.Create(255f).AsVector4(); + private static readonly Vector4 Half = Vector128.Create(.5f).AsVector4(); [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void FromRgba32(ref Rgba32 p) + private TestArgb(Rgba32 source) { - this.R = p.R; - this.G = p.G; - this.B = p.B; - this.A = p.A; + this.R = source.R; + this.G = source.G; + this.B = source.B; + this.A = source.A; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void FromBytes(byte r, byte g, byte b, byte a) + private TestArgb(byte r, byte g, byte b, byte a) { this.R = r; this.G = g; @@ -44,50 +39,70 @@ public void FromBytes(byte r, byte g, byte b, byte a) } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void FromVector4(Vector4 p) + public void FromRgba32(Rgba32 source) { - this.R = (byte)p.X; - this.G = (byte)p.Y; - this.B = (byte)p.Z; - this.A = (byte)p.W; + this.R = source.R; + this.G = source.G; + this.B = source.B; + this.A = source.A; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void FromVector4(ref Vector4 p) + public void FromRgba32(ref Rgba32 source) { - this.R = (byte)p.X; - this.G = (byte)p.Y; - this.B = (byte)p.Z; - this.A = (byte)p.W; + this.R = source.R; + this.G = source.G; + this.B = source.B; + this.A = source.A; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Rgba32 ToRgba32() - { - return new Rgba32(this.R, this.G, this.B, this.A); - } + public static TestArgb StaticFromRgba32(Rgba32 source) => new(source); [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void CopyToRgba32(ref Rgba32 dest) + public void FromBytes(byte r, byte g, byte b, byte a) { - dest.R = this.R; - dest.G = this.G; - dest.B = this.B; - dest.A = this.A; + this.R = r; + this.G = g; + this.B = b; + this.A = a; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToVector4() + public void FromVector4(Vector4 source) => this = Pack(source); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TestArgb StaticFromVector4(Vector4 source) => Pack(source); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void FromVector4(ref Vector4 source) => this = Pack(source); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Rgba32 ToRgba32() => new(this.R, this.G, this.B, this.A); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly void CopyToRgba32(ref Rgba32 destination) { - return new Vector4(this.R, this.G, this.B, this.A); + destination.R = this.R; + destination.G = this.G; + destination.B = this.B; + destination.A = this.A; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void CopyToVector4(ref Vector4 dest) + public readonly Vector4 ToVector4() => new Vector4(this.R, this.G, this.B, this.A) / MaxBytes; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly void CopyToVector4(ref Vector4 destination) => destination = this.ToVector4(); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static TestArgb Pack(Vector4 vector) { - dest.X = this.R; - dest.Y = this.G; - dest.Z = this.B; - dest.W = this.A; + vector *= MaxBytes; + vector += Half; + vector = Numerics.Clamp(vector, Vector4.Zero, MaxBytes); + + Vector128 result = Vector128.ConvertToInt32(vector.AsVector128()).AsByte(); + return new(result.GetElement(0), result.GetElement(4), result.GetElement(8), result.GetElement(12)); } } diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/TestRgba.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/TestRgba.cs index 76449c9d95..1499fb7d3d 100644 --- a/tests/ImageSharp.Benchmarks/General/PixelConversion/TestRgba.cs +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/TestRgba.cs @@ -4,6 +4,7 @@ using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion; @@ -16,17 +17,29 @@ public struct TestRgba : ITestPixel public byte B; public byte A; + private static readonly Vector4 MaxBytes = Vector128.Create(255f).AsVector4(); + private static readonly Vector4 Half = Vector128.Create(.5f).AsVector4(); + [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void FromRgba32(Rgba32 source) + private TestRgba(byte r, byte g, byte b, byte a) { - this = Unsafe.As(ref source); + this.R = r; + this.G = g; + this.B = b; + this.A = a; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void FromRgba32(ref Rgba32 source) - { - this = Unsafe.As(ref source); - } + private TestRgba(Rgba32 source) => this = Unsafe.As(ref source); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void FromRgba32(Rgba32 source) => this = Unsafe.As(ref source); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TestRgba StaticFromRgba32(Rgba32 source) => new(source); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void FromRgba32(ref Rgba32 source) => this = Unsafe.As(ref source); [MethodImpl(MethodImplOptions.AggressiveInlining)] public void FromBytes(byte r, byte g, byte b, byte a) @@ -37,39 +50,35 @@ public void FromBytes(byte r, byte g, byte b, byte a) this.A = a; } - public void FromVector4(Vector4 source) - { - throw new System.NotImplementedException(); - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void FromVector4(Vector4 source) => this = Pack(source); - public void FromVector4(ref Vector4 source) - { - throw new System.NotImplementedException(); - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TestRgba StaticFromVector4(Vector4 source) => Pack(source); [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Rgba32 ToRgba32() - { - return Unsafe.As(ref this); - } + public void FromVector4(ref Vector4 source) => this = Pack(source); [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void CopyToRgba32(ref Rgba32 dest) - { - dest = Unsafe.As(ref this); - } + public Rgba32 ToRgba32() => Unsafe.As(ref this); [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToVector4() - { - return new Vector4(this.R, this.G, this.B, this.A) * new Vector4(1f / 255f); - } + public void CopyToRgba32(ref Rgba32 destination) => destination = Unsafe.As(ref this); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Vector4 ToVector4() => new Vector4(this.R, this.G, this.B, this.A) / MaxBytes; [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void CopyToVector4(ref Vector4 dest) + public readonly void CopyToVector4(ref Vector4 destination) => destination = this.ToVector4(); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static TestRgba Pack(Vector4 vector) { - var tmp = new Vector4(this.R, this.G, this.B, this.A); - tmp *= new Vector4(1f / 255f); - dest = tmp; + vector *= MaxBytes; + vector += Half; + vector = Numerics.Clamp(vector, Vector4.Zero, MaxBytes); + + Vector128 result = Vector128.ConvertToInt32(vector.AsVector128()).AsByte(); + return new(result.GetElement(0), result.GetElement(4), result.GetElement(8), result.GetElement(12)); } } diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/TestRgbaVector.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/TestRgbaVector.cs new file mode 100644 index 0000000000..07790ae998 --- /dev/null +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/TestRgbaVector.cs @@ -0,0 +1,51 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using SixLabors.ImageSharp.PixelFormats; + +namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion; + +[StructLayout(LayoutKind.Sequential)] +public struct TestRgbaVector : ITestPixel +{ + private Vector4 v; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private TestRgbaVector(Vector4 source) => this.v = source; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void FromVector4(Vector4 source) => this.v = source; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TestRgbaVector StaticFromVector4(Vector4 source) => new(source); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void FromVector4(ref Vector4 source) => this.v = source; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Vector4 ToVector4() => this.v; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly void CopyToVector4(ref Vector4 destination) => destination = this.v; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void FromRgba32(Rgba32 source) => this.v = source.ToScaledVector4(); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TestRgbaVector StaticFromRgba32(Rgba32 source) => new(source.ToScaledVector4()); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void FromRgba32(ref Rgba32 source) => this.v = source.ToScaledVector4(); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void FromBytes(byte r, byte g, byte b, byte a) => this.v = new Rgba32(r, g, b, a).ToScaledVector4(); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Rgba32 ToRgba32() => Rgba32.FromScaledVector4(this.v); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly void CopyToRgba32(ref Rgba32 destination) => destination = Rgba32.FromScaledVector4(this.v); +} diff --git a/tests/ImageSharp.Benchmarks/General/Vectorization/UInt32ToSingle.cs b/tests/ImageSharp.Benchmarks/General/Vectorization/UInt32ToSingle.cs index fc4dc1fa16..5f1f5666de 100644 --- a/tests/ImageSharp.Benchmarks/General/Vectorization/UInt32ToSingle.cs +++ b/tests/ImageSharp.Benchmarks/General/Vectorization/UInt32ToSingle.cs @@ -7,7 +7,7 @@ namespace SixLabors.ImageSharp.Benchmarks.General.Vectorization; -[Config(typeof(Config.ShortMultiFramework))] +[Config(typeof(Config.Short))] public class UInt32ToSingle { private float[] data; diff --git a/tests/ImageSharp.Benchmarks/General/Vectorization/WidenBytesToUInt32.cs b/tests/ImageSharp.Benchmarks/General/Vectorization/WidenBytesToUInt32.cs index f391e42012..da7ddae41e 100644 --- a/tests/ImageSharp.Benchmarks/General/Vectorization/WidenBytesToUInt32.cs +++ b/tests/ImageSharp.Benchmarks/General/Vectorization/WidenBytesToUInt32.cs @@ -9,7 +9,7 @@ namespace SixLabors.ImageSharp.Benchmarks.General.Vectorization; -[Config(typeof(Config.ShortMultiFramework))] +[Config(typeof(Config.Short))] public class WidenBytesToUInt32 { private byte[] source; diff --git a/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj b/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj index 0ba2f4b949..4408159ef4 100644 --- a/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj +++ b/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj @@ -11,7 +11,7 @@ false Debug;Release - + @@ -23,12 +23,12 @@ - net7.0;net6.0 + net8.0 - net6.0 + net8.0 @@ -41,8 +41,8 @@ - - + + diff --git a/tests/ImageSharp.Benchmarks/LoadResizeSave/LoadResizeSaveStressRunner.cs b/tests/ImageSharp.Benchmarks/LoadResizeSave/LoadResizeSaveStressRunner.cs index dd9b55e58d..a06784f1b1 100644 --- a/tests/ImageSharp.Benchmarks/LoadResizeSave/LoadResizeSaveStressRunner.cs +++ b/tests/ImageSharp.Benchmarks/LoadResizeSave/LoadResizeSaveStressRunner.cs @@ -269,9 +269,7 @@ public void MagicScalerResize(string input) Width = this.ThumbnailSize, Height = this.ThumbnailSize, ResizeMode = CropScaleMode.Max, - SaveFormat = FileFormat.Jpeg, - JpegQuality = Quality, - JpegSubsampleMode = ChromaSubsampleMode.Subsample420 + EncoderOptions = new JpegEncoderOptions(Quality, ChromaSubsampleMode.Subsample420, true) }; // TODO: Is there a way to capture input dimensions for IncreaseTotalMegapixels? @@ -343,6 +341,6 @@ public void NetVipsResize(string input) using var thumb = NetVipsImage.Thumbnail(input, this.ThumbnailSize, this.ThumbnailSize); // Save the results - thumb.Jpegsave(this.OutputPath(input), q: Quality, strip: true); + thumb.Jpegsave(this.OutputPath(input), q: Quality, keep: NetVips.Enums.ForeignKeep.None); } } diff --git a/tests/ImageSharp.Benchmarks/LoadResizeSave/README.md b/tests/ImageSharp.Benchmarks/LoadResizeSave/README.md index 6cb48eb48c..98f472241f 100644 --- a/tests/ImageSharp.Benchmarks/LoadResizeSave/README.md +++ b/tests/ImageSharp.Benchmarks/LoadResizeSave/README.md @@ -1,4 +1,4 @@ -The benchmarks have been adapted from the +The benchmarks have been adapted from the [PhotoSauce's MemoryStress project](https://github.com/saucecontrol/core-imaging-playground/tree/beeees/MemoryStress). ### Setup diff --git a/tests/ImageSharp.Benchmarks/Processing/BokehBlur.cs b/tests/ImageSharp.Benchmarks/Processing/BokehBlur.cs index 441500c88c..82fce7dad7 100644 --- a/tests/ImageSharp.Benchmarks/Processing/BokehBlur.cs +++ b/tests/ImageSharp.Benchmarks/Processing/BokehBlur.cs @@ -7,13 +7,13 @@ namespace SixLabors.ImageSharp.Benchmarks.Processing; -[Config(typeof(Config.MultiFramework))] +[Config(typeof(Config.Standard))] public class BokehBlur { [Benchmark] public void Blur() { - using Image image = new(Configuration.Default, 400, 400, Color.White); + using Image image = new(Configuration.Default, 400, 400, Color.White.ToPixel()); image.Mutate(c => c.BokehBlur()); } } diff --git a/tests/ImageSharp.Benchmarks/Processing/Crop.cs b/tests/ImageSharp.Benchmarks/Processing/Crop.cs index d802d3293a..0432b76249 100644 --- a/tests/ImageSharp.Benchmarks/Processing/Crop.cs +++ b/tests/ImageSharp.Benchmarks/Processing/Crop.cs @@ -11,7 +11,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Processing; -[Config(typeof(Config.MultiFramework))] +[Config(typeof(Config.Standard))] public class Crop { [Benchmark(Baseline = true, Description = "System.Drawing Crop")] diff --git a/tests/ImageSharp.Benchmarks/Processing/DetectEdges.cs b/tests/ImageSharp.Benchmarks/Processing/DetectEdges.cs index 9371906965..c48f3e4f49 100644 --- a/tests/ImageSharp.Benchmarks/Processing/DetectEdges.cs +++ b/tests/ImageSharp.Benchmarks/Processing/DetectEdges.cs @@ -8,7 +8,7 @@ namespace SixLabors.ImageSharp.Benchmarks; -[Config(typeof(Config.MultiFramework))] +[Config(typeof(Config.Standard))] public class DetectEdges { private Image image; diff --git a/tests/ImageSharp.Benchmarks/Processing/Diffuse.cs b/tests/ImageSharp.Benchmarks/Processing/Diffuse.cs index c74c4a858a..fae80fe841 100644 --- a/tests/ImageSharp.Benchmarks/Processing/Diffuse.cs +++ b/tests/ImageSharp.Benchmarks/Processing/Diffuse.cs @@ -7,13 +7,13 @@ namespace SixLabors.ImageSharp.Benchmarks.Processing; -[Config(typeof(Config.MultiFramework))] +[Config(typeof(Config.Standard))] public class Diffuse { [Benchmark] public Size DoDiffuse() { - using Image image = new(Configuration.Default, 800, 800, Color.BlanchedAlmond); + using Image image = new(Configuration.Default, 800, 800, Color.BlanchedAlmond.ToPixel()); image.Mutate(x => x.Dither(KnownDitherings.FloydSteinberg)); return image.Size; @@ -22,7 +22,7 @@ public Size DoDiffuse() [Benchmark] public Size DoDither() { - using Image image = new(Configuration.Default, 800, 800, Color.BlanchedAlmond); + using Image image = new(Configuration.Default, 800, 800, Color.BlanchedAlmond.ToPixel()); image.Mutate(x => x.Dither()); return image.Size; diff --git a/tests/ImageSharp.Benchmarks/Processing/GaussianBlur.cs b/tests/ImageSharp.Benchmarks/Processing/GaussianBlur.cs index 0123f4d3b8..462d83488d 100644 --- a/tests/ImageSharp.Benchmarks/Processing/GaussianBlur.cs +++ b/tests/ImageSharp.Benchmarks/Processing/GaussianBlur.cs @@ -7,13 +7,13 @@ namespace SixLabors.ImageSharp.Benchmarks.Samplers; -[Config(typeof(Config.MultiFramework))] +[Config(typeof(Config.Standard))] public class GaussianBlur { [Benchmark] public void Blur() { - using var image = new Image(Configuration.Default, 400, 400, Color.White); + using Image image = new(Configuration.Default, 400, 400, Color.White.ToPixel()); image.Mutate(c => c.GaussianBlur()); } } diff --git a/tests/ImageSharp.Benchmarks/Processing/HistogramEqualization.cs b/tests/ImageSharp.Benchmarks/Processing/HistogramEqualization.cs index 6292b793ec..135145a312 100644 --- a/tests/ImageSharp.Benchmarks/Processing/HistogramEqualization.cs +++ b/tests/ImageSharp.Benchmarks/Processing/HistogramEqualization.cs @@ -9,7 +9,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Processing; -[Config(typeof(Config.MultiFramework))] +[Config(typeof(Config.Standard))] public class HistogramEqualization { private Image image; diff --git a/tests/ImageSharp.Benchmarks/Processing/OilPaint.cs b/tests/ImageSharp.Benchmarks/Processing/OilPaint.cs index 239d5a93bc..e3e413fe49 100644 --- a/tests/ImageSharp.Benchmarks/Processing/OilPaint.cs +++ b/tests/ImageSharp.Benchmarks/Processing/OilPaint.cs @@ -7,7 +7,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Processing; -[Config(typeof(Config.MultiFramework))] +[Config(typeof(Config.Standard))] public class OilPaint { [Benchmark] diff --git a/tests/ImageSharp.Benchmarks/Processing/Resize.cs b/tests/ImageSharp.Benchmarks/Processing/Resize.cs index ae993cd25b..05baceb6a0 100644 --- a/tests/ImageSharp.Benchmarks/Processing/Resize.cs +++ b/tests/ImageSharp.Benchmarks/Processing/Resize.cs @@ -12,7 +12,7 @@ namespace SixLabors.ImageSharp.Benchmarks; -[Config(typeof(Config.MultiFramework))] +[Config(typeof(Config.Standard))] public abstract class Resize where TPixel : unmanaged, IPixel { diff --git a/tests/ImageSharp.Benchmarks/Processing/Rotate.cs b/tests/ImageSharp.Benchmarks/Processing/Rotate.cs index b9b0f6b3df..b041a9d57e 100644 --- a/tests/ImageSharp.Benchmarks/Processing/Rotate.cs +++ b/tests/ImageSharp.Benchmarks/Processing/Rotate.cs @@ -7,13 +7,13 @@ namespace SixLabors.ImageSharp.Benchmarks.Processing; -[Config(typeof(Config.MultiFramework))] +[Config(typeof(Config.Standard))] public class Rotate { [Benchmark] public Size DoRotate() { - using Image image = new(Configuration.Default, 400, 400, Color.BlanchedAlmond); + using Image image = new(Configuration.Default, 400, 400, Color.BlanchedAlmond.ToPixel()); image.Mutate(x => x.Rotate(37.5F)); return image.Size; diff --git a/tests/ImageSharp.Benchmarks/Processing/Skew.cs b/tests/ImageSharp.Benchmarks/Processing/Skew.cs index 26f2e7d2d6..9f0103fa6b 100644 --- a/tests/ImageSharp.Benchmarks/Processing/Skew.cs +++ b/tests/ImageSharp.Benchmarks/Processing/Skew.cs @@ -7,13 +7,13 @@ namespace SixLabors.ImageSharp.Benchmarks.Processing; -[Config(typeof(Config.MultiFramework))] +[Config(typeof(Config.Standard))] public class Skew { [Benchmark] public Size DoSkew() { - using Image image = new(Configuration.Default, 400, 400, Color.BlanchedAlmond); + using Image image = new(Configuration.Default, 400, 400, Color.BlanchedAlmond.ToPixel()); image.Mutate(x => x.Skew(20, 10)); return image.Size; diff --git a/tests/ImageSharp.Tests.ProfilingSandbox/ImageSharp.Tests.ProfilingSandbox.csproj b/tests/ImageSharp.Tests.ProfilingSandbox/ImageSharp.Tests.ProfilingSandbox.csproj index 492ce36b81..b93d011910 100644 --- a/tests/ImageSharp.Tests.ProfilingSandbox/ImageSharp.Tests.ProfilingSandbox.csproj +++ b/tests/ImageSharp.Tests.ProfilingSandbox/ImageSharp.Tests.ProfilingSandbox.csproj @@ -7,7 +7,7 @@ Exe false SixLabors.ImageSharp.Tests.ProfilingSandbox - win7-x64 + win-x64 SixLabors.ImageSharp.Tests.ProfilingSandbox.Program false @@ -19,12 +19,12 @@ - net7.0;net6.0 + net8.0 - net6.0 + net8.0 @@ -43,7 +43,7 @@ - + diff --git a/tests/ImageSharp.Tests/Color/ColorTests.CastFrom.cs b/tests/ImageSharp.Tests/Color/ColorTests.CastFrom.cs index 4091e0cd40..2eb821b61d 100644 --- a/tests/ImageSharp.Tests/Color/ColorTests.CastFrom.cs +++ b/tests/ImageSharp.Tests/Color/ColorTests.CastFrom.cs @@ -12,10 +12,10 @@ public class CastFrom [Fact] public void Rgba64() { - var source = new Rgba64(100, 2222, 3333, 4444); + Rgba64 source = new(100, 2222, 3333, 4444); // Act: - Color color = source; + Color color = Color.FromPixel(source); // Assert: Rgba64 data = color.ToPixel(); @@ -25,10 +25,10 @@ public void Rgba64() [Fact] public void Rgba32() { - var source = new Rgba32(1, 22, 33, 231); + Rgba32 source = new(1, 22, 33, 231); // Act: - Color color = source; + Color color = Color.FromPixel(source); // Assert: Rgba32 data = color.ToPixel(); @@ -38,10 +38,10 @@ public void Rgba32() [Fact] public void Argb32() { - var source = new Argb32(1, 22, 33, 231); + Argb32 source = new(1, 22, 33, 231); // Act: - Color color = source; + Color color = Color.FromPixel(source); // Assert: Argb32 data = color.ToPixel(); @@ -51,10 +51,10 @@ public void Argb32() [Fact] public void Bgra32() { - var source = new Bgra32(1, 22, 33, 231); + Bgra32 source = new(1, 22, 33, 231); // Act: - Color color = source; + Color color = Color.FromPixel(source); // Assert: Bgra32 data = color.ToPixel(); @@ -64,10 +64,10 @@ public void Bgra32() [Fact] public void Abgr32() { - var source = new Abgr32(1, 22, 33, 231); + Abgr32 source = new(1, 22, 33, 231); // Act: - Color color = source; + Color color = Color.FromPixel(source); // Assert: Abgr32 data = color.ToPixel(); @@ -77,10 +77,10 @@ public void Abgr32() [Fact] public void Rgb24() { - var source = new Rgb24(1, 22, 231); + Rgb24 source = new(1, 22, 231); // Act: - Color color = source; + Color color = Color.FromPixel(source); // Assert: Rgb24 data = color.ToPixel(); @@ -90,10 +90,10 @@ public void Rgb24() [Fact] public void Bgr24() { - var source = new Bgr24(1, 22, 231); + Bgr24 source = new(1, 22, 231); // Act: - Color color = source; + Color color = Color.FromPixel(source); // Assert: Bgr24 data = color.ToPixel(); diff --git a/tests/ImageSharp.Tests/Color/ColorTests.CastTo.cs b/tests/ImageSharp.Tests/Color/ColorTests.CastTo.cs index dacec71449..4247345c7b 100644 --- a/tests/ImageSharp.Tests/Color/ColorTests.CastTo.cs +++ b/tests/ImageSharp.Tests/Color/ColorTests.CastTo.cs @@ -16,10 +16,10 @@ public void Rgba64() var source = new Rgba64(100, 2222, 3333, 4444); // Act: - var color = new Color(source); + var color = Color.FromPixel(source); // Assert: - Rgba64 data = color; + Rgba64 data = color.ToPixel(); Assert.Equal(source, data); } @@ -29,10 +29,10 @@ public void Rgba32() var source = new Rgba32(1, 22, 33, 231); // Act: - var color = new Color(source); + var color = Color.FromPixel(source); // Assert: - Rgba32 data = color; + Rgba32 data = color.ToPixel(); Assert.Equal(source, data); } @@ -42,10 +42,10 @@ public void Argb32() var source = new Argb32(1, 22, 33, 231); // Act: - var color = new Color(source); + var color = Color.FromPixel(source); // Assert: - Argb32 data = color; + Argb32 data = color.ToPixel(); Assert.Equal(source, data); } @@ -55,10 +55,10 @@ public void Bgra32() var source = new Bgra32(1, 22, 33, 231); // Act: - var color = new Color(source); + var color = Color.FromPixel(source); // Assert: - Bgra32 data = color; + Bgra32 data = color.ToPixel(); Assert.Equal(source, data); } @@ -68,10 +68,10 @@ public void Abgr32() var source = new Abgr32(1, 22, 33, 231); // Act: - var color = new Color(source); + var color = Color.FromPixel(source); // Assert: - Abgr32 data = color; + Abgr32 data = color.ToPixel(); Assert.Equal(source, data); } @@ -81,10 +81,10 @@ public void Rgb24() var source = new Rgb24(1, 22, 231); // Act: - var color = new Color(source); + var color = Color.FromPixel(source); // Assert: - Rgb24 data = color; + Rgb24 data = color.ToPixel(); Assert.Equal(source, data); } @@ -94,10 +94,10 @@ public void Bgr24() var source = new Bgr24(1, 22, 231); // Act: - var color = new Color(source); + var color = Color.FromPixel(source); // Assert: - Bgr24 data = color; + Bgr24 data = color.ToPixel(); Assert.Equal(source, data); } @@ -105,7 +105,7 @@ public void Bgr24() public void Vector4Constructor() { // Act: - Color color = new(Vector4.One); + Color color = Color.FromScaledVector(Vector4.One); // Assert: Assert.Equal(new RgbaVector(1, 1, 1, 1), color.ToPixel()); @@ -117,7 +117,7 @@ public void Vector4Constructor() [Fact] public void GenericPixelRoundTrip() { - AssertGenericPixelRoundTrip(new RgbaVector(float.Epsilon, 2 * float.Epsilon, float.MaxValue, float.MinValue)); + AssertGenericPixelRoundTrip(new RgbaVector(0.5f, 0.75f, 1, 0)); AssertGenericPixelRoundTrip(new Rgba64(1, 2, ushort.MaxValue, ushort.MaxValue - 1)); AssertGenericPixelRoundTrip(new Rgb48(1, 2, ushort.MaxValue - 1)); AssertGenericPixelRoundTrip(new La32(1, ushort.MaxValue - 1)); diff --git a/tests/ImageSharp.Tests/Color/ColorTests.ConstructFrom.cs b/tests/ImageSharp.Tests/Color/ColorTests.ConstructFrom.cs index 3ea8623d94..9126543e55 100644 --- a/tests/ImageSharp.Tests/Color/ColorTests.ConstructFrom.cs +++ b/tests/ImageSharp.Tests/Color/ColorTests.ConstructFrom.cs @@ -12,10 +12,10 @@ public class ConstructFrom [Fact] public void Rgba64() { - var source = new Rgba64(100, 2222, 3333, 4444); + Rgba64 source = new(100, 2222, 3333, 4444); // Act: - var color = new Color(source); + Color color = Color.FromPixel(source); // Assert: Rgba64 data = color.ToPixel(); @@ -25,10 +25,10 @@ public void Rgba64() [Fact] public void Rgba32() { - var source = new Rgba32(1, 22, 33, 231); + Rgba32 source = new(1, 22, 33, 231); // Act: - var color = new Color(source); + Color color = Color.FromPixel(source); // Assert: Rgba32 data = color.ToPixel(); @@ -38,10 +38,10 @@ public void Rgba32() [Fact] public void Argb32() { - var source = new Argb32(1, 22, 33, 231); + Argb32 source = new(1, 22, 33, 231); // Act: - var color = new Color(source); + Color color = Color.FromPixel(source); // Assert: Argb32 data = color.ToPixel(); @@ -51,10 +51,10 @@ public void Argb32() [Fact] public void Bgra32() { - var source = new Bgra32(1, 22, 33, 231); + Bgra32 source = new(1, 22, 33, 231); // Act: - var color = new Color(source); + Color color = Color.FromPixel(source); // Assert: Bgra32 data = color.ToPixel(); @@ -64,10 +64,10 @@ public void Bgra32() [Fact] public void Abgr32() { - var source = new Abgr32(1, 22, 33, 231); + Abgr32 source = new(1, 22, 33, 231); // Act: - var color = new Color(source); + Color color = Color.FromPixel(source); // Assert: Abgr32 data = color.ToPixel(); @@ -77,10 +77,10 @@ public void Abgr32() [Fact] public void Rgb24() { - var source = new Rgb24(1, 22, 231); + Rgb24 source = new(1, 22, 231); // Act: - var color = new Color(source); + Color color = Color.FromPixel(source); // Assert: Rgb24 data = color.ToPixel(); @@ -90,10 +90,10 @@ public void Rgb24() [Fact] public void Bgr24() { - var source = new Bgr24(1, 22, 231); + Bgr24 source = new(1, 22, 231); // Act: - var color = new Color(source); + Color color = Color.FromPixel(source); // Assert: Bgr24 data = color.ToPixel(); diff --git a/tests/ImageSharp.Tests/Color/ColorTests.cs b/tests/ImageSharp.Tests/Color/ColorTests.cs index f7e2092176..d430df5b44 100644 --- a/tests/ImageSharp.Tests/Color/ColorTests.cs +++ b/tests/ImageSharp.Tests/Color/ColorTests.cs @@ -10,12 +10,12 @@ public partial class ColorTests [Fact] public void WithAlpha() { - var c1 = Color.FromRgba(111, 222, 55, 255); + Color c1 = Color.FromPixel(new Rgba32(111, 222, 55, 255)); Color c2 = c1.WithAlpha(0.5f); - var expected = new Rgba32(111, 222, 55, 128); + Rgba32 expected = new(111, 222, 55, 128); - Assert.Equal(expected, (Rgba32)c2); + Assert.Equal(expected, c2.ToPixel()); } [Theory] @@ -23,13 +23,13 @@ public void WithAlpha() [InlineData(true)] public void Equality_WhenTrue(bool highPrecision) { - Color c1 = new Rgba64(100, 2000, 3000, 40000); - Color c2 = new Rgba64(100, 2000, 3000, 40000); + Color c1 = Color.FromPixel(new Rgba64(100, 2000, 3000, 40000)); + Color c2 = Color.FromPixel(new Rgba64(100, 2000, 3000, 40000)); if (highPrecision) { - c1 = Color.FromPixel(c1.ToPixel()); - c2 = Color.FromPixel(c2.ToPixel()); + c1 = Color.FromPixel(c1.ToPixel()); + c2 = Color.FromPixel(c2.ToPixel()); } Assert.True(c1.Equals(c2)); @@ -43,15 +43,15 @@ public void Equality_WhenTrue(bool highPrecision) [InlineData(true)] public void Equality_WhenFalse(bool highPrecision) { - Color c1 = new Rgba64(100, 2000, 3000, 40000); - Color c2 = new Rgba64(101, 2000, 3000, 40000); - Color c3 = new Rgba64(100, 2000, 3000, 40001); + Color c1 = Color.FromPixel(new Rgba64(100, 2000, 3000, 40000)); + Color c2 = Color.FromPixel(new Rgba64(101, 2000, 3000, 40000)); + Color c3 = Color.FromPixel(new Rgba64(100, 2000, 3000, 40001)); if (highPrecision) { - c1 = Color.FromPixel(c1.ToPixel()); - c2 = Color.FromPixel(c2.ToPixel()); - c3 = Color.FromPixel(c3.ToPixel()); + c1 = Color.FromPixel(c1.ToPixel()); + c2 = Color.FromPixel(c2.ToPixel()); + c3 = Color.FromPixel(c3.ToPixel()); } Assert.False(c1.Equals(c2)); @@ -74,7 +74,7 @@ public void ToHex(bool highPrecision) if (highPrecision) { - color = Color.FromPixel(color.ToPixel()); + color = Color.FromPixel(color.ToPixel()); } string actual = color.ToHex(); @@ -84,22 +84,22 @@ public void ToHex(bool highPrecision) [Fact] public void WebSafePalette_IsCorrect() { - Rgba32[] actualPalette = Color.WebSafePalette.ToArray().Select(c => (Rgba32)c).ToArray(); + Rgba32[] actualPalette = Color.WebSafePalette.ToArray().Select(c => c.ToPixel()).ToArray(); for (int i = 0; i < ReferencePalette.WebSafeColors.Length; i++) { - Assert.Equal((Rgba32)ReferencePalette.WebSafeColors[i], actualPalette[i]); + Assert.Equal(ReferencePalette.WebSafeColors[i].ToPixel(), actualPalette[i]); } } [Fact] public void WernerPalette_IsCorrect() { - Rgba32[] actualPalette = Color.WernerPalette.ToArray().Select(c => (Rgba32)c).ToArray(); + Rgba32[] actualPalette = Color.WernerPalette.ToArray().Select(c => c.ToPixel()).ToArray(); for (int i = 0; i < ReferencePalette.WernerColors.Length; i++) { - Assert.Equal((Rgba32)ReferencePalette.WernerColors[i], actualPalette[i]); + Assert.Equal(ReferencePalette.WernerColors[i].ToPixel(), actualPalette[i]); } } @@ -108,66 +108,48 @@ public class FromHex [Fact] public void ShortHex() { - Assert.Equal(new Rgb24(255, 255, 255), (Rgb24)Color.ParseHex("#fff")); - Assert.Equal(new Rgb24(255, 255, 255), (Rgb24)Color.ParseHex("fff")); - Assert.Equal(new Rgba32(0, 0, 0, 255), (Rgba32)Color.ParseHex("000f")); + Assert.Equal(new Rgb24(255, 255, 255), Color.ParseHex("#fff").ToPixel()); + Assert.Equal(new Rgb24(255, 255, 255), Color.ParseHex("fff").ToPixel()); + Assert.Equal(new Rgba32(0, 0, 0, 255), Color.ParseHex("000f").ToPixel()); } [Fact] public void TryShortHex() { Assert.True(Color.TryParseHex("#fff", out Color actual)); - Assert.Equal(new Rgb24(255, 255, 255), (Rgb24)actual); + Assert.Equal(new Rgb24(255, 255, 255), actual.ToPixel()); Assert.True(Color.TryParseHex("fff", out actual)); - Assert.Equal(new Rgb24(255, 255, 255), (Rgb24)actual); + Assert.Equal(new Rgb24(255, 255, 255), actual.ToPixel()); Assert.True(Color.TryParseHex("000f", out actual)); - Assert.Equal(new Rgba32(0, 0, 0, 255), (Rgba32)actual); + Assert.Equal(new Rgba32(0, 0, 0, 255), actual.ToPixel()); } [Fact] public void LeadingPoundIsOptional() { - Assert.Equal(new Rgb24(0, 128, 128), (Rgb24)Color.ParseHex("#008080")); - Assert.Equal(new Rgb24(0, 128, 128), (Rgb24)Color.ParseHex("008080")); + Assert.Equal(new Rgb24(0, 128, 128), Color.ParseHex("#008080").ToPixel()); + Assert.Equal(new Rgb24(0, 128, 128), Color.ParseHex("008080").ToPixel()); } [Fact] - public void ThrowsOnEmpty() - { - Assert.Throws(() => Color.ParseHex(string.Empty)); - } + public void ThrowsOnEmpty() => Assert.Throws(() => Color.ParseHex(string.Empty)); [Fact] - public void ThrowsOnInvalid() - { - Assert.Throws(() => Color.ParseHex("!")); - } + public void ThrowsOnInvalid() => Assert.Throws(() => Color.ParseHex("!")); [Fact] - public void ThrowsOnNull() - { - Assert.Throws(() => Color.ParseHex(null)); - } + public void ThrowsOnNull() => Assert.Throws(() => Color.ParseHex(null)); [Fact] - public void FalseOnEmpty() - { - Assert.False(Color.TryParseHex(string.Empty, out Color _)); - } + public void FalseOnEmpty() => Assert.False(Color.TryParseHex(string.Empty, out Color _)); [Fact] - public void FalseOnInvalid() - { - Assert.False(Color.TryParseHex("!", out Color _)); - } + public void FalseOnInvalid() => Assert.False(Color.TryParseHex("!", out Color _)); [Fact] - public void FalseOnNull() - { - Assert.False(Color.TryParseHex(null, out Color _)); - } + public void FalseOnNull() => Assert.False(Color.TryParseHex(null, out Color _)); } public class FromString @@ -177,10 +159,10 @@ public void ColorNames() { foreach (string name in ReferencePalette.ColorNames.Keys) { - Rgba32 expected = ReferencePalette.ColorNames[name]; - Assert.Equal(expected, (Rgba32)Color.Parse(name)); - Assert.Equal(expected, (Rgba32)Color.Parse(name.ToLowerInvariant())); - Assert.Equal(expected, (Rgba32)Color.Parse(expected.ToHex())); + Rgba32 expected = ReferencePalette.ColorNames[name].ToPixel(); + Assert.Equal(expected, Color.Parse(name).ToPixel()); + Assert.Equal(expected, Color.Parse(name.ToLowerInvariant()).ToPixel()); + Assert.Equal(expected, Color.Parse(expected.ToHex()).ToPixel()); } } @@ -189,53 +171,35 @@ public void TryColorNames() { foreach (string name in ReferencePalette.ColorNames.Keys) { - Rgba32 expected = ReferencePalette.ColorNames[name]; + Rgba32 expected = ReferencePalette.ColorNames[name].ToPixel(); Assert.True(Color.TryParse(name, out Color actual)); - Assert.Equal(expected, (Rgba32)actual); + Assert.Equal(expected, actual.ToPixel()); Assert.True(Color.TryParse(name.ToLowerInvariant(), out actual)); - Assert.Equal(expected, (Rgba32)actual); + Assert.Equal(expected, actual.ToPixel()); Assert.True(Color.TryParse(expected.ToHex(), out actual)); - Assert.Equal(expected, (Rgba32)actual); + Assert.Equal(expected, actual.ToPixel()); } } [Fact] - public void ThrowsOnEmpty() - { - Assert.Throws(() => Color.Parse(string.Empty)); - } + public void ThrowsOnEmpty() => Assert.Throws(() => Color.Parse(string.Empty)); [Fact] - public void ThrowsOnInvalid() - { - Assert.Throws(() => Color.Parse("!")); - } + public void ThrowsOnInvalid() => Assert.Throws(() => Color.Parse("!")); [Fact] - public void ThrowsOnNull() - { - Assert.Throws(() => Color.Parse(null)); - } + public void ThrowsOnNull() => Assert.Throws(() => Color.Parse(null)); [Fact] - public void FalseOnEmpty() - { - Assert.False(Color.TryParse(string.Empty, out Color _)); - } + public void FalseOnEmpty() => Assert.False(Color.TryParse(string.Empty, out Color _)); [Fact] - public void FalseOnInvalid() - { - Assert.False(Color.TryParse("!", out Color _)); - } + public void FalseOnInvalid() => Assert.False(Color.TryParse("!", out Color _)); [Fact] - public void FalseOnNull() - { - Assert.False(Color.TryParse(null, out Color _)); - } + public void FalseOnNull() => Assert.False(Color.TryParse(null, out Color _)); } } diff --git a/tests/ImageSharp.Tests/Color/RgbaDouble.cs b/tests/ImageSharp.Tests/Color/RgbaDouble.cs new file mode 100644 index 0000000000..9a751e8791 --- /dev/null +++ b/tests/ImageSharp.Tests/Color/RgbaDouble.cs @@ -0,0 +1,189 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using SixLabors.ImageSharp.PixelFormats; + +namespace SixLabors.ImageSharp.Tests; + +/// +/// Unpacked pixel type containing four 64-bit floating-point values typically ranging from 0 to 1. +/// The color components are stored in red, green, blue, and alpha order. +/// +/// Ranges from [0, 0, 0, 0] to [1, 1, 1, 1] in vector form. +/// +/// +/// +/// This struct is fully mutable. This is done (against the guidelines) for the sake of performance, +/// as it avoids the need to create new values for modification operations. +/// +[StructLayout(LayoutKind.Sequential)] +public struct RgbaDouble : IPixel +{ + /// + /// Gets or sets the red component. + /// + public double R; + + /// + /// Gets or sets the green component. + /// + public double G; + + /// + /// Gets or sets the blue component. + /// + public double B; + + /// + /// Gets or sets the alpha component. + /// + public double A; + + private const float MaxBytes = byte.MaxValue; + private static readonly Vector4 Max = new(MaxBytes); + private static readonly Vector4 Half = new(0.5F); + + /// + /// Initializes a new instance of the struct. + /// + /// The red component. + /// The green component. + /// The blue component. + /// The alpha component. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public RgbaDouble(double r, double g, double b, double a = 1) + { + this.R = r; + this.G = g; + this.B = b; + this.A = a; + } + + /// + /// Compares two objects for equality. + /// + /// The on the left side of the operand. + /// The on the right side of the operand. + /// + /// True if the parameter is equal to the parameter; otherwise, false. + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(RgbaDouble left, RgbaDouble right) => left.Equals(right); + + /// + /// Compares two objects for equality. + /// + /// The on the left side of the operand. + /// The on the right side of the operand. + /// + /// True if the parameter is not equal to the parameter; otherwise, false. + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(RgbaDouble left, RgbaDouble right) => !left.Equals(right); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Rgba32 ToRgba32() => Rgba32.FromScaledVector4(this.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Vector4 ToScaledVector4() => this.ToVector4(); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Vector4 ToVector4() => new((float)this.R, (float)this.G, (float)this.B, (float)this.A); + + /// + public static PixelTypeInfo GetPixelTypeInfo() + => PixelTypeInfo.Create( + PixelComponentInfo.Create(4, 64, 64, 64, 64), + PixelColorType.RGB | PixelColorType.Alpha, + PixelAlphaRepresentation.Unassociated); + + /// + public static PixelOperations CreatePixelOperations() => new(); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static RgbaDouble FromScaledVector4(Vector4 source) => FromVector4(source); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static RgbaDouble FromVector4(Vector4 source) + { + source = Numerics.Clamp(source, Vector4.Zero, Vector4.One); + return new(source.X, source.Y, source.Z, source.W); + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static RgbaDouble FromAbgr32(Abgr32 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static RgbaDouble FromArgb32(Argb32 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static RgbaDouble FromBgra5551(Bgra5551 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static RgbaDouble FromBgr24(Bgr24 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static RgbaDouble FromBgra32(Bgra32 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static RgbaDouble FromL8(L8 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static RgbaDouble FromL16(L16 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static RgbaDouble FromLa16(La16 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static RgbaDouble FromLa32(La32 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static RgbaDouble FromRgb24(Rgb24 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static RgbaDouble FromRgba32(Rgba32 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static RgbaDouble FromRgb48(Rgb48 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static RgbaDouble FromRgba64(Rgba64 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + public override readonly bool Equals(object obj) => obj is RgbaDouble other && this.Equals(other); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public readonly bool Equals(RgbaDouble other) => + this.R.Equals(other.R) + && this.G.Equals(other.G) + && this.B.Equals(other.B) + && this.A.Equals(other.A); + + /// + public override readonly string ToString() => FormattableString.Invariant($"RgbaDouble({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/tests/ImageSharp.Tests/ColorProfiles/ApproximateColorProfileComparer.cs b/tests/ImageSharp.Tests/ColorProfiles/ApproximateColorProfileComparer.cs new file mode 100644 index 0000000000..56d495a87a --- /dev/null +++ b/tests/ImageSharp.Tests/ColorProfiles/ApproximateColorProfileComparer.cs @@ -0,0 +1,92 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Diagnostics.CodeAnalysis; +using SixLabors.ImageSharp.ColorProfiles; + +namespace SixLabors.ImageSharp.Tests.ColorProfiles; + +/// +/// Allows the approximate comparison of color profile component values. +/// +internal readonly struct ApproximateColorProfileComparer : + IEqualityComparer, + IEqualityComparer, + IEqualityComparer, + IEqualityComparer, + IEqualityComparer, + IEqualityComparer, + IEqualityComparer, + IEqualityComparer, + IEqualityComparer, + IEqualityComparer, + IEqualityComparer, + IEqualityComparer, + IEqualityComparer +{ + private readonly float epsilon; + + /// + /// Initializes a new instance of the struct. + /// + /// The comparison error difference epsilon to use. + public ApproximateColorProfileComparer(float epsilon = 1f) => this.epsilon = epsilon; + + public bool Equals(CieLab x, CieLab y) => this.Equals(x.L, y.L) && this.Equals(x.A, y.A) && this.Equals(x.B, y.B); + + public bool Equals(CieXyz x, CieXyz y) => this.Equals(x.X, y.X) && this.Equals(x.Y, y.Y) && this.Equals(x.Z, y.Z); + + public bool Equals(Lms x, Lms y) => this.Equals(x.L, y.L) && this.Equals(x.M, y.M) && this.Equals(x.S, y.S); + + public bool Equals(CieLch x, CieLch y) => this.Equals(x.L, y.L) && this.Equals(x.C, y.C) && this.Equals(x.H, y.H); + + public bool Equals(Rgb x, Rgb y) => this.Equals(x.R, y.R) && this.Equals(x.G, y.G) && this.Equals(x.B, y.B); + + public bool Equals(YCbCr x, YCbCr y) => this.Equals(x.Y, y.Y) && this.Equals(x.Cb, y.Cb) && this.Equals(x.Cr, y.Cr); + + public bool Equals(CieLchuv x, CieLchuv y) => this.Equals(x.L, y.L) && this.Equals(x.C, y.C) && this.Equals(x.H, y.H); + + public bool Equals(CieLuv x, CieLuv y) => this.Equals(x.L, y.L) && this.Equals(x.U, y.U) && this.Equals(x.V, y.V); + + public bool Equals(CieXyy x, CieXyy y) => this.Equals(x.X, y.X) && this.Equals(x.Y, y.Y) && this.Equals(x.Yl, y.Yl); + + public bool Equals(Cmyk x, Cmyk y) => this.Equals(x.C, y.C) && this.Equals(x.M, y.M) && this.Equals(x.Y, y.Y) && this.Equals(x.K, y.K); + + public bool Equals(Hsl x, Hsl y) => this.Equals(x.H, y.H) && this.Equals(x.S, y.S) && this.Equals(x.L, y.L); + + public bool Equals(Hsv x, Hsv y) => this.Equals(x.H, y.H) && this.Equals(x.S, y.S) && this.Equals(x.V, y.V); + + public bool Equals(HunterLab x, HunterLab y) => this.Equals(x.L, y.L) && this.Equals(x.A, y.A) && this.Equals(x.B, y.B); + + public int GetHashCode([DisallowNull] CieLab obj) => obj.GetHashCode(); + + public int GetHashCode([DisallowNull] CieXyz obj) => obj.GetHashCode(); + + public int GetHashCode([DisallowNull] Lms obj) => obj.GetHashCode(); + + public int GetHashCode([DisallowNull] CieLch obj) => obj.GetHashCode(); + + public int GetHashCode([DisallowNull] Rgb obj) => obj.GetHashCode(); + + public int GetHashCode([DisallowNull] YCbCr obj) => obj.GetHashCode(); + + public int GetHashCode([DisallowNull] CieLchuv obj) => obj.GetHashCode(); + + public int GetHashCode([DisallowNull] CieLuv obj) => obj.GetHashCode(); + + public int GetHashCode([DisallowNull] CieXyy obj) => obj.GetHashCode(); + + public int GetHashCode([DisallowNull] Cmyk obj) => obj.GetHashCode(); + + public int GetHashCode([DisallowNull] Hsl obj) => obj.GetHashCode(); + + public int GetHashCode([DisallowNull] Hsv obj) => obj.GetHashCode(); + + public int GetHashCode([DisallowNull] HunterLab obj) => obj.GetHashCode(); + + private bool Equals(float x, float y) + { + float d = x - y; + return d >= -this.epsilon && d <= this.epsilon; + } +} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieLchConversionTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CieLabAndCieLchConversionTests.cs similarity index 61% rename from tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieLchConversionTests.cs rename to tests/ImageSharp.Tests/ColorProfiles/CieLabAndCieLchConversionTests.cs index d71f0fa5e0..9a894c7760 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieLchConversionTests.cs +++ b/tests/ImageSharp.Tests/ColorProfiles/CieLabAndCieLchConversionTests.cs @@ -1,10 +1,9 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; +using SixLabors.ImageSharp.ColorProfiles; -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; +namespace SixLabors.ImageSharp.Tests.ColorProfiles; /// /// Tests - conversions. @@ -15,12 +14,8 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; /// public class CieLabAndCieLchConversionTests { - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0001F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); + private static readonly ApproximateColorProfileComparer Comparer = new(.0001f); - /// - /// Tests conversion from to . - /// [Theory] [InlineData(0, 0, 0, 0, 0, 0)] [InlineData(54.2917, 106.8391, 40.8526, 54.2917, 80.8125, 69.8851)] @@ -33,8 +28,10 @@ public class CieLabAndCieLchConversionTests public void Convert_Lch_to_Lab(float l, float c, float h, float l2, float a, float b) { // Arrange - var input = new CieLch(l, c, h); - var expected = new CieLab(l2, a, b); + CieLch input = new(l, c, h); + CieLab expected = new(l2, a, b); + ColorConversionOptions options = new() { WhitePoint = KnownIlluminants.D50, TargetWhitePoint = KnownIlluminants.D50 }; + ColorProfileConverter converter = new(options); Span inputSpan = new CieLch[5]; inputSpan.Fill(input); @@ -42,21 +39,18 @@ public void Convert_Lch_to_Lab(float l, float c, float h, float l2, float a, flo Span actualSpan = new CieLab[5]; // Act - var actual = Converter.ToCieLab(input); - Converter.Convert(inputSpan, actualSpan); + CieLab actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); + Assert.Equal(expected, actual, Comparer); for (int i = 0; i < actualSpan.Length; i++) { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + Assert.Equal(expected, actualSpan[i], Comparer); } } - /// - /// Tests conversion from to . - /// [Theory] [InlineData(0, 0, 0, 0, 0, 0)] [InlineData(54.2917, 80.8125, 69.8851, 54.2917, 106.8391, 40.8526)] @@ -69,8 +63,10 @@ public void Convert_Lch_to_Lab(float l, float c, float h, float l2, float a, flo public void Convert_Lab_to_Lch(float l, float a, float b, float l2, float c, float h) { // Arrange - var input = new CieLab(l, a, b); - var expected = new CieLch(l2, c, h); + CieLab input = new(l, a, b); + CieLch expected = new(l2, c, h); + ColorConversionOptions options = new() { WhitePoint = KnownIlluminants.D50, TargetWhitePoint = KnownIlluminants.D50 }; + ColorProfileConverter converter = new(options); Span inputSpan = new CieLab[5]; inputSpan.Fill(input); @@ -78,15 +74,15 @@ public void Convert_Lab_to_Lch(float l, float a, float b, float l2, float c, flo Span actualSpan = new CieLch[5]; // Act - var actual = Converter.ToCieLch(input); - Converter.Convert(inputSpan, actualSpan); + CieLch actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); + Assert.Equal(expected, actual, Comparer); for (int i = 0; i < actualSpan.Length; i++) { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + Assert.Equal(expected, actualSpan[i], Comparer); } } } diff --git a/tests/ImageSharp.Tests/ColorProfiles/CieLabAndCieLchuvConversionTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CieLabAndCieLchuvConversionTests.cs new file mode 100644 index 0000000000..4b1b5e1a56 --- /dev/null +++ b/tests/ImageSharp.Tests/ColorProfiles/CieLabAndCieLchuvConversionTests.cs @@ -0,0 +1,76 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.ColorProfiles; + +namespace SixLabors.ImageSharp.Tests.ColorProfiles; + +/// +/// Tests - conversions. +/// +/// +/// Test data generated using: +/// +/// +public class CieLabAndCieLchuvConversionTests +{ + private static readonly ApproximateColorProfileComparer Comparer = new(.0002F); + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(30.66194, 200, 352.7564, 31.95653, 116.8745, 2.388602)] + public void Convert_Lchuv_To_Lab(float l, float c, float h, float l2, float a, float b) + { + // Arrange + CieLchuv input = new(l, c, h); + CieLab expected = new(l2, a, b); + ColorConversionOptions options = new() { WhitePoint = KnownIlluminants.D65, TargetWhitePoint = KnownIlluminants.D50 }; + ColorProfileConverter converter = new(options); + + Span inputSpan = new CieLchuv[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLab[5]; + + // Act + CieLab actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(36.0555, 303.6901, 10.01514, 29.4713573, 200, 352.6346)] + public void Convert_Lab_To_Lchuv(float l, float a, float b, float l2, float c, float h) + { + // Arrange + CieLab input = new(l, a, b); + CieLchuv expected = new(l2, c, h); + ColorConversionOptions options = new() { WhitePoint = KnownIlluminants.D50, TargetWhitePoint = KnownIlluminants.D65 }; + ColorProfileConverter converter = new(options); + + Span inputSpan = new CieLab[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLchuv[5]; + + // Act + CieLchuv actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } +} diff --git a/tests/ImageSharp.Tests/ColorProfiles/CieLabAndCieLuvConversionTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CieLabAndCieLuvConversionTests.cs new file mode 100644 index 0000000000..44756c779a --- /dev/null +++ b/tests/ImageSharp.Tests/ColorProfiles/CieLabAndCieLuvConversionTests.cs @@ -0,0 +1,76 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.ColorProfiles; + +namespace SixLabors.ImageSharp.Tests.ColorProfiles; + +/// +/// Tests - conversions. +/// +/// +/// Test data generated using: +/// +/// +public class CieLabAndCieLuvConversionTests +{ + private static readonly ApproximateColorProfileComparer Comparer = new(.0002F); + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(10, 36.0555, 303.6901, 10.6006718, -17.24077, 82.8835)] + public void Convert_CieLuv_To_CieLab(float l, float u, float v, float l2, float a, float b) + { + // Arrange + CieLuv input = new(l, u, v); + CieLab expected = new(l2, a, b); + ColorConversionOptions options = new() { WhitePoint = KnownIlluminants.D65, TargetWhitePoint = KnownIlluminants.D50 }; + ColorProfileConverter converter = new(options); + + Span inputSpan = new CieLuv[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLab[5]; + + // Act + CieLab actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(10.0151367, -23.9644356, 17.0226, 10.0000038, -12.830183, 15.1829338)] + public void Convert_CieLab_To_CieLuv(float l, float a, float b, float l2, float u, float v) + { + // Arrange + CieLab input = new(l, a, b); + CieLuv expected = new(l2, u, v); + ColorConversionOptions options = new() { WhitePoint = KnownIlluminants.D50, TargetWhitePoint = KnownIlluminants.D65 }; + ColorProfileConverter converter = new(options); + + Span inputSpan = new CieLab[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLuv[5]; + + // Act + CieLuv actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } +} diff --git a/tests/ImageSharp.Tests/ColorProfiles/CieLabAndCieXyyConversionTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CieLabAndCieXyyConversionTests.cs new file mode 100644 index 0000000000..a464eeca11 --- /dev/null +++ b/tests/ImageSharp.Tests/ColorProfiles/CieLabAndCieXyyConversionTests.cs @@ -0,0 +1,70 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.ColorProfiles; + +namespace SixLabors.ImageSharp.Tests.ColorProfiles; + +/// +/// Tests - conversions. +/// +public class CieLabAndCieXyyConversionTests +{ + private static readonly ApproximateColorProfileComparer Comparer = new(.0002F); + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(0.8644734, 0.06098868, 0.06509002, 30.6619, 291.5721, -11.2526)] + public void Convert_CieXyy_To_CieLab(float x, float y, float yl, float l, float a, float b) + { + // Arrange + CieXyy input = new(x, y, yl); + CieLab expected = new(l, a, b); + ColorProfileConverter converter = new(); + + Span inputSpan = new CieXyy[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLab[5]; + + // Act + CieLab actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(30.6619, 291.5721, -11.2526, 0.8644734, 0.06098868, 0.06509002)] + public void Convert_CieLab_To_CieXyy(float l, float a, float b, float x, float y, float yl) + { + // Arrange + CieLab input = new(l, a, b); + CieXyy expected = new(x, y, yl); + ColorProfileConverter converter = new(); + + Span inputSpan = new CieLab[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieXyy[5]; + + // Act + CieXyy actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } +} diff --git a/tests/ImageSharp.Tests/ColorProfiles/CieLabAndCmykConversionTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CieLabAndCmykConversionTests.cs new file mode 100644 index 0000000000..746671c4a7 --- /dev/null +++ b/tests/ImageSharp.Tests/ColorProfiles/CieLabAndCmykConversionTests.cs @@ -0,0 +1,70 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.ColorProfiles; + +namespace SixLabors.ImageSharp.Tests.ColorProfiles; + +/// +/// Tests - conversions. +/// +public class CieLabAndCmykConversionTests +{ + private static readonly ApproximateColorProfileComparer Comparer = new(.0002F); + + [Theory] + [InlineData(0, 0, 0, 1, 0, 0, 0)] + [InlineData(0, 1, 0.6156551, 5.960464E-08, 55.063, 82.54871, 23.16506)] + public void Convert_Cmyk_to_CieLab(float c, float m, float y, float k, float l, float a, float b) + { + // Arrange + Cmyk input = new(c, m, y, k); + CieLab expected = new(l, a, b); + ColorProfileConverter converter = new(); + + Span inputSpan = new Cmyk[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLab[5]; + + // Act + CieLab actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0, 1)] + [InlineData(36.0555, 303.6901, 10.01514, 0, 1, 0.597665966, 0)] + public void Convert_CieLab_to_Cmyk(float l, float a, float b, float c, float m, float y, float k) + { + // Arrange + CieLab input = new(l, a, b); + Cmyk expected = new(c, m, y, k); + ColorProfileConverter converter = new(); + + Span inputSpan = new CieLab[5]; + inputSpan.Fill(input); + + Span actualSpan = new Cmyk[5]; + + // Act + Cmyk actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } +} diff --git a/tests/ImageSharp.Tests/ColorProfiles/CieLabAndHslConversionTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CieLabAndHslConversionTests.cs new file mode 100644 index 0000000000..96779f1896 --- /dev/null +++ b/tests/ImageSharp.Tests/ColorProfiles/CieLabAndHslConversionTests.cs @@ -0,0 +1,70 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.ColorProfiles; + +namespace SixLabors.ImageSharp.Tests.ColorProfiles; + +/// +/// Tests - conversions. +/// +public class CieLabAndHslConversionTests +{ + private static readonly ApproximateColorProfileComparer Comparer = new(.0002f); + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(336.9393, 1, 0.5, 55.063, 82.54868, 23.16508)] + public void Convert_Hsl_to_CieLab(float h, float s, float ll, float l, float a, float b) + { + // Arrange + Hsl input = new(h, s, ll); + CieLab expected = new(l, a, b); + ColorProfileConverter converter = new(); + + Span inputSpan = new Hsl[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLab[5]; + + // Act + CieLab actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(55.063, 82.54868, 23.16508, 336.9393, 1, 0.5)] + public void Convert_CieLab_to_Hsl(float l, float a, float b, float h, float s, float ll) + { + // Arrange + CieLab input = new(l, a, b); + Hsl expected = new(h, s, ll); + ColorProfileConverter converter = new(); + + Span inputSpan = new CieLab[5]; + inputSpan.Fill(input); + + Span actualSpan = new Hsl[5]; + + // Act + Hsl actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } +} diff --git a/tests/ImageSharp.Tests/ColorProfiles/CieLabAndHsvConversionTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CieLabAndHsvConversionTests.cs new file mode 100644 index 0000000000..3389da9815 --- /dev/null +++ b/tests/ImageSharp.Tests/ColorProfiles/CieLabAndHsvConversionTests.cs @@ -0,0 +1,70 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.ColorProfiles; + +namespace SixLabors.ImageSharp.Tests.ColorProfiles; + +/// +/// Tests - conversions. +/// +public class CieLabAndHsvConversionTests +{ + private static readonly ApproximateColorProfileComparer Comparer = new(.0002f); + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(336.9393, 1, 0.9999999, 55.063, 82.54871, 23.16504)] + public void Convert_Hsv_to_CieLab(float h, float s, float v, float l, float a, float b) + { + // Arrange + Hsv input = new(h, s, v); + CieLab expected = new(l, a, b); + ColorProfileConverter converter = new(); + + Span inputSpan = new Hsv[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLab[5]; + + // Act + CieLab actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(55.063, 82.54871, 23.16504, 336.9393, 1, 0.9999999)] + public void Convert_CieLab_to_Hsv(float l, float a, float b, float h, float s, float v) + { + // Arrange + CieLab input = new(l, a, b); + Hsv expected = new(h, s, v); + ColorProfileConverter converter = new(); + + Span inputSpan = new CieLab[5]; + inputSpan.Fill(input); + + Span actualSpan = new Hsv[5]; + + // Act + Hsv actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } +} diff --git a/tests/ImageSharp.Tests/ColorProfiles/CieLabAndHunterLabConversionTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CieLabAndHunterLabConversionTests.cs new file mode 100644 index 0000000000..1054d537ac --- /dev/null +++ b/tests/ImageSharp.Tests/ColorProfiles/CieLabAndHunterLabConversionTests.cs @@ -0,0 +1,70 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.ColorProfiles; + +namespace SixLabors.ImageSharp.Tests.ColorProfiles; + +/// +/// Tests - conversions. +/// +public class CieLabAndHunterLabConversionTests +{ + private static readonly ApproximateColorProfileComparer Comparer = new(.0002f); + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(27.51646, 556.9392, -0.03974226, 33.074177, 281.48329, -0.06948)] + public void Convert_HunterLab_to_CieLab(float l2, float a2, float b2, float l, float a, float b) + { + // Arrange + HunterLab input = new(l2, a2, b2); + CieLab expected = new(l, a, b); + ColorProfileConverter converter = new(); + + Span inputSpan = new HunterLab[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLab[5]; + + // Act + CieLab actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(33.074177, 281.48329, -0.06948, 27.51646, 556.9392, -0.03974226)] + public void Convert_CieLab_to_HunterLab(float l, float a, float b, float l2, float a2, float b2) + { + // Arrange + CieLab input = new(l, a, b); + HunterLab expected = new(l2, a2, b2); + ColorProfileConverter converter = new(); + + Span inputSpan = new CieLab[5]; + inputSpan.Fill(input); + + Span actualSpan = new HunterLab[5]; + + // Act + HunterLab actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } +} diff --git a/tests/ImageSharp.Tests/ColorProfiles/CieLabAndLmsConversionTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CieLabAndLmsConversionTests.cs new file mode 100644 index 0000000000..77243268fd --- /dev/null +++ b/tests/ImageSharp.Tests/ColorProfiles/CieLabAndLmsConversionTests.cs @@ -0,0 +1,70 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.ColorProfiles; + +namespace SixLabors.ImageSharp.Tests.ColorProfiles; + +/// +/// Tests - conversions. +/// +public class CieLabAndLmsConversionTests +{ + private static readonly ApproximateColorProfileComparer Comparer = new(.0002f); + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(0.8303261, -0.5776886, 0.1133359, 30.66193, 291.57209, -11.25262)] + public void Convert_Lms_to_CieLab(float l2, float m, float s, float l, float a, float b) + { + // Arrange + Lms input = new(l2, m, s); + CieLab expected = new(l, a, b); + ColorProfileConverter converter = new(); + + Span inputSpan = new Lms[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLab[5]; + + // Act + CieLab actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(30.66193, 291.57209, -11.25262, 0.8303261, -0.5776886, 0.1133359)] + public void Convert_CieLab_to_Lms(float l, float a, float b, float l2, float m, float s) + { + // Arrange + CieLab input = new(l, a, b); + Lms expected = new(l2, m, s); + ColorProfileConverter converter = new(); + + Span inputSpan = new CieLab[5]; + inputSpan.Fill(input); + + Span actualSpan = new Lms[5]; + + // Act + Lms actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } +} diff --git a/tests/ImageSharp.Tests/ColorProfiles/CieLabAndRgbConversionTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CieLabAndRgbConversionTests.cs new file mode 100644 index 0000000000..0a0453bc62 --- /dev/null +++ b/tests/ImageSharp.Tests/ColorProfiles/CieLabAndRgbConversionTests.cs @@ -0,0 +1,71 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.ColorProfiles; + +namespace SixLabors.ImageSharp.Tests.ColorProfiles; + +/// +/// Tests - conversions. +/// +public class CieLabAndRgbConversionTests +{ + private static readonly ApproximateColorProfileComparer Comparer = new(.0002F); + private static readonly ColorProfileConverter Converter = new(); + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(0.9999999, 0, 0.384345, 55.063, 82.54871, 23.16505)] + public void Convert_Rgb_to_CieLab(float r, float g, float b2, float l, float a, float b) + { + // Arrange + Rgb input = new(r, g, b2); + CieLab expected = new(l, a, b); + ColorProfileConverter converter = new(); + + Span inputSpan = new Rgb[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLab[5]; + + // Act + CieLab actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(55.063, 82.54871, 23.16505, 0.9999999, 0, 0.384345)] + public void Convert_CieLab_to_Rgb(float l, float a, float b, float r, float g, float b2) + { + // Arrange + CieLab input = new(l, a, b); + Rgb expected = new(r, g, b2); + ColorProfileConverter converter = new(); + + Span inputSpan = new CieLab[5]; + inputSpan.Fill(input); + + Span actualSpan = new Rgb[5]; + + // Act + Rgb actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } +} diff --git a/tests/ImageSharp.Tests/ColorProfiles/CieLabAndYCbCrConversionTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CieLabAndYCbCrConversionTests.cs new file mode 100644 index 0000000000..9a29b15398 --- /dev/null +++ b/tests/ImageSharp.Tests/ColorProfiles/CieLabAndYCbCrConversionTests.cs @@ -0,0 +1,70 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.ColorProfiles; + +namespace SixLabors.ImageSharp.Tests.ColorProfiles; + +/// +/// Tests - conversions. +/// +public class CieLabAndYCbCrConversionTests +{ + private static readonly ApproximateColorProfileComparer Comparer = new(.0002F); + + [Theory] + [InlineData(0, 128, 128, 0, 0, 0)] + [InlineData(87.4179, 133.9763, 247.5308, 55.06287, 82.54838, 23.1697)] + public void Convert_YCbCr_to_CieLab(float y, float cb, float cr, float l, float a, float b) + { + // Arrange + YCbCr input = new(y, cb, cr); + CieLab expected = new(l, a, b); + ColorProfileConverter converter = new(); + + Span inputSpan = new YCbCr[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLab[5]; + + // Act + CieLab actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } + + [Theory] + [InlineData(0, 0, 0, 0, 128, 128)] + [InlineData(55.06287, 82.54838, 23.1697, 87.41701, 133.97232, 247.5314)] + public void Convert_CieLab_to_YCbCr(float l, float a, float b, float y, float cb, float cr) + { + // Arrange + CieLab input = new(l, a, b); + YCbCr expected = new(y, cb, cr); + ColorProfileConverter converter = new(); + + Span inputSpan = new CieLab[5]; + inputSpan.Fill(input); + + Span actualSpan = new YCbCr[5]; + + // Act + YCbCr actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } +} diff --git a/tests/ImageSharp.Tests/Colorspaces/CieLabTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CieLabTests.cs similarity index 61% rename from tests/ImageSharp.Tests/Colorspaces/CieLabTests.cs rename to tests/ImageSharp.Tests/ColorProfiles/CieLabTests.cs index 52cb63d217..3c015259b1 100644 --- a/tests/ImageSharp.Tests/Colorspaces/CieLabTests.cs +++ b/tests/ImageSharp.Tests/ColorProfiles/CieLabTests.cs @@ -2,9 +2,9 @@ // Licensed under the Six Labors Split License. using System.Numerics; -using SixLabors.ImageSharp.ColorSpaces; +using SixLabors.ImageSharp.ColorProfiles; -namespace SixLabors.ImageSharp.Tests.Colorspaces; +namespace SixLabors.ImageSharp.Tests.ColorProfiles; /// /// Tests the struct. @@ -17,7 +17,7 @@ public void CieLabConstructorAssignsFields() const float l = 75F; const float a = -64F; const float b = 87F; - var cieLab = new CieLab(l, a, b); + CieLab cieLab = new(l, a, b); Assert.Equal(l, cieLab.L); Assert.Equal(a, cieLab.A); @@ -27,17 +27,17 @@ public void CieLabConstructorAssignsFields() [Fact] public void CieLabEquality() { - var x = default(CieLab); - var y = new CieLab(Vector3.One); + CieLab x = default; + CieLab y = new(Vector3.One); - Assert.True(default(CieLab) == default(CieLab)); - Assert.True(new CieLab(1, 0, 1) != default(CieLab)); - Assert.False(new CieLab(1, 0, 1) == default(CieLab)); - Assert.Equal(default(CieLab), default(CieLab)); + Assert.True(default == default(CieLab)); + Assert.True(new CieLab(1, 0, 1) != default); + Assert.False(new CieLab(1, 0, 1) == default); + Assert.Equal(default, default(CieLab)); Assert.Equal(new CieLab(1, 0, 1), new CieLab(1, 0, 1)); Assert.Equal(new CieLab(Vector3.One), new CieLab(Vector3.One)); Assert.False(x.Equals(y)); - Assert.False(new CieLab(1, 0, 1) == default(CieLab)); + Assert.False(new CieLab(1, 0, 1) == default); Assert.False(x.Equals((object)y)); Assert.False(x.GetHashCode().Equals(y.GetHashCode())); } diff --git a/tests/ImageSharp.Tests/ColorProfiles/CieLchAndCieLuvConversionTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CieLchAndCieLuvConversionTests.cs new file mode 100644 index 0000000000..598d4af335 --- /dev/null +++ b/tests/ImageSharp.Tests/ColorProfiles/CieLchAndCieLuvConversionTests.cs @@ -0,0 +1,71 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.ColorProfiles; + +namespace SixLabors.ImageSharp.Tests.ColorProfiles; + +/// +/// Tests - conversions. +/// +public class CieLchAndCieLuvConversionTests +{ + private static readonly ApproximateColorProfileComparer Comparer = new(.0002f); + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(36.0555, 103.6901, 10.01514, 34.89777, 187.6642, -7.181467)] + public void Convert_CieLch_to_CieLuv(float l, float c, float h, float l2, float u, float v) + { + // Arrange + CieLch input = new(l, c, h); + CieLuv expected = new(l2, u, v); + ColorConversionOptions options = new() { WhitePoint = KnownIlluminants.D50, TargetWhitePoint = KnownIlluminants.D65 }; + ColorProfileConverter converter = new(options); + + Span inputSpan = new CieLch[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLuv[5]; + + // Act + CieLuv actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } + + [Theory] + [InlineData(34.89777, 187.6642, -7.181467, 36.0555, 103.6901, 10.01514)] + public void Convert_CieLuv_to_CieLch(float l2, float u, float v, float l, float c, float h) + { + // Arrange + CieLuv input = new(l2, u, v); + CieLch expected = new(l, c, h); + ColorConversionOptions options = new() { WhitePoint = KnownIlluminants.D65, TargetWhitePoint = KnownIlluminants.D50 }; + ColorProfileConverter converter = new(options); + + Span inputSpan = new CieLuv[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLch[5]; + + // Act + CieLch actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } +} diff --git a/tests/ImageSharp.Tests/ColorProfiles/CieLchAndCieXyyConversionTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CieLchAndCieXyyConversionTests.cs new file mode 100644 index 0000000000..94f5515bff --- /dev/null +++ b/tests/ImageSharp.Tests/ColorProfiles/CieLchAndCieXyyConversionTests.cs @@ -0,0 +1,70 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.ColorProfiles; + +namespace SixLabors.ImageSharp.Tests.ColorProfiles; + +/// +/// Tests - conversions. +/// +public class CieLchAndCieXyyConversionTests +{ + private static readonly ApproximateColorProfileComparer Comparer = new(.0003f); + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(36.0555, 103.6901, 10.01514, 0.67641, 0.22770, 0.09037)] + public void Convert_CieLch_to_CieXyy(float l, float c, float h, float x, float y, float yl) + { + // Arrange + CieLch input = new(l, c, h); + CieXyy expected = new(x, y, yl); + ColorProfileConverter converter = new(); + + Span inputSpan = new CieLch[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieXyy[5]; + + // Act + CieXyy actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(0.67641, 0.22770, 0.09037, 36.05544, 103.691315, 10.012783)] + public void Convert_CieXyy_to_CieLch(float x, float y, float yl, float l, float c, float h) + { + // Arrange + CieXyy input = new(x, y, yl); + CieLch expected = new(l, c, h); + ColorProfileConverter converter = new(); + + Span inputSpan = new CieXyy[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLch[5]; + + // Act + CieLch actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } +} diff --git a/tests/ImageSharp.Tests/Colorspaces/CieLchTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CieLchTests.cs similarity index 65% rename from tests/ImageSharp.Tests/Colorspaces/CieLchTests.cs rename to tests/ImageSharp.Tests/ColorProfiles/CieLchTests.cs index 83e4d8a59a..484db3e8cf 100644 --- a/tests/ImageSharp.Tests/Colorspaces/CieLchTests.cs +++ b/tests/ImageSharp.Tests/ColorProfiles/CieLchTests.cs @@ -1,10 +1,10 @@ -// Copyright (c) Six Labors. +// Copyright (c) Six Labors. // Licensed under the Six Labors Split License. using System.Numerics; -using SixLabors.ImageSharp.ColorSpaces; +using SixLabors.ImageSharp.ColorProfiles; -namespace SixLabors.ImageSharp.Tests.Colorspaces; +namespace SixLabors.ImageSharp.Tests.ColorProfiles; /// /// Tests the struct. @@ -17,7 +17,7 @@ public void CieLchConstructorAssignsFields() const float l = 75F; const float c = 64F; const float h = 287F; - var cieLch = new CieLch(l, c, h); + CieLch cieLch = new(l, c, h); Assert.Equal(l, cieLch.L); Assert.Equal(c, cieLch.C); @@ -27,12 +27,12 @@ public void CieLchConstructorAssignsFields() [Fact] public void CieLchEquality() { - var x = default(CieLch); - var y = new CieLch(Vector3.One); + CieLch x = default; + CieLch y = new(Vector3.One); - Assert.True(default(CieLch) == default(CieLch)); - Assert.False(default(CieLch) != default(CieLch)); - Assert.Equal(default(CieLch), default(CieLch)); + Assert.True(default == default(CieLch)); + Assert.False(default != default(CieLch)); + Assert.Equal(default, default(CieLch)); Assert.Equal(new CieLch(1, 0, 1), new CieLch(1, 0, 1)); Assert.Equal(new CieLch(Vector3.One), new CieLch(Vector3.One)); Assert.False(x.Equals(y)); diff --git a/tests/ImageSharp.Tests/ColorProfiles/CieLchuvAndCieLchConversionTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CieLchuvAndCieLchConversionTests.cs new file mode 100644 index 0000000000..a3e0b45e0d --- /dev/null +++ b/tests/ImageSharp.Tests/ColorProfiles/CieLchuvAndCieLchConversionTests.cs @@ -0,0 +1,71 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.ColorProfiles; + +namespace SixLabors.ImageSharp.Tests.ColorProfiles; + +/// +/// Tests - conversions. +/// +public class CieLchuvAndCieLchConversionTests +{ + private static readonly ApproximateColorProfileComparer Comparer = new(.0002F); + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(36.73742, 64.79149, 30.1786, 36.0555, 103.6901, 10.01513)] + public void Convert_CieLch_To_CieLchuv(float l2, float c2, float h2, float l, float c, float h) + { + // Arrange + CieLch input = new(l2, c2, h2); + CieLchuv expected = new(l, c, h); + ColorConversionOptions options = new() { WhitePoint = KnownIlluminants.D50, TargetWhitePoint = KnownIlluminants.D65 }; + ColorProfileConverter converter = new(options); + + Span inputSpan = new CieLch[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLchuv[5]; + + // Act + CieLchuv actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } + + [Theory] + [InlineData(36.0555, 103.6901, 10.01514, 36.73742, 64.79149, 30.1786)] + public void Convert_CieLchuv_To_CieLch(float l, float c, float h, float l2, float c2, float h2) + { + // Arrange + CieLchuv input = new(l, c, h); + CieLch expected = new(l2, c2, h2); + ColorConversionOptions options = new() { WhitePoint = KnownIlluminants.D65, TargetWhitePoint = KnownIlluminants.D50 }; + ColorProfileConverter converter = new(options); + + Span inputSpan = new CieLchuv[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLch[5]; + + // Act + CieLch actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } +} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchuvAndCieLuvConversionTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CieLchuvAndCieLuvConversionTests.cs similarity index 62% rename from tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchuvAndCieLuvConversionTests.cs rename to tests/ImageSharp.Tests/ColorProfiles/CieLchuvAndCieLuvConversionTests.cs index ba3bc9e799..465237490d 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchuvAndCieLuvConversionTests.cs +++ b/tests/ImageSharp.Tests/ColorProfiles/CieLchuvAndCieLuvConversionTests.cs @@ -1,10 +1,9 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; +using SixLabors.ImageSharp.ColorProfiles; -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; +namespace SixLabors.ImageSharp.Tests.ColorProfiles; /// /// Tests - conversions. @@ -15,12 +14,8 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; /// public class CieLchuvAndCieLuvConversionTests { - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0001F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); + private static readonly ApproximateColorProfileComparer Comparer = new(.0001F); - /// - /// Tests conversion from to . - /// [Theory] [InlineData(0, 0, 0, 0, 0, 0)] [InlineData(54.2917, 106.8391, 40.8526, 54.2917, 80.8125, 69.8851)] @@ -33,8 +28,10 @@ public class CieLchuvAndCieLuvConversionTests public void Convert_CieLchuv_to_CieLuv(float l, float c, float h, float l2, float u, float v) { // Arrange - var input = new CieLchuv(l, c, h); - var expected = new CieLuv(l2, u, v); + CieLchuv input = new(l, c, h); + CieLuv expected = new(l2, u, v); + ColorConversionOptions options = new() { WhitePoint = KnownIlluminants.D65, TargetWhitePoint = KnownIlluminants.D65 }; + ColorProfileConverter converter = new(options); Span inputSpan = new CieLchuv[5]; inputSpan.Fill(input); @@ -42,21 +39,18 @@ public void Convert_CieLchuv_to_CieLuv(float l, float c, float h, float l2, floa Span actualSpan = new CieLuv[5]; // Act - var actual = Converter.ToCieLuv(input); - Converter.Convert(inputSpan, actualSpan); + CieLuv actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); + Assert.Equal(expected, actual, Comparer); for (int i = 0; i < actualSpan.Length; i++) { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + Assert.Equal(expected, actualSpan[i], Comparer); } } - /// - /// Tests conversion from to . - /// [Theory] [InlineData(0, 0, 0, 0, 0, 0)] [InlineData(54.2917, 80.8125, 69.8851, 54.2917, 106.8391, 40.8526)] @@ -70,8 +64,10 @@ public void Convert_CieLchuv_to_CieLuv(float l, float c, float h, float l2, floa public void Convert_CieLuv_to_CieLchuv(float l, float u, float v, float l2, float c, float h) { // Arrange - var input = new CieLuv(l, u, v); - var expected = new CieLchuv(l2, c, h); + CieLuv input = new(l, u, v); + CieLchuv expected = new(l2, c, h); + ColorConversionOptions options = new() { WhitePoint = KnownIlluminants.D65, TargetWhitePoint = KnownIlluminants.D65 }; + ColorProfileConverter converter = new(options); Span inputSpan = new CieLuv[5]; inputSpan.Fill(input); @@ -79,15 +75,15 @@ public void Convert_CieLuv_to_CieLchuv(float l, float u, float v, float l2, floa Span actualSpan = new CieLchuv[5]; // Act - var actual = Converter.ToCieLchuv(input); - Converter.Convert(inputSpan, actualSpan); + CieLchuv actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); + Assert.Equal(expected, actual, Comparer); for (int i = 0; i < actualSpan.Length; i++) { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + Assert.Equal(expected, actualSpan[i], Comparer); } } } diff --git a/tests/ImageSharp.Tests/ColorProfiles/CieLchuvAndCmykConversionTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CieLchuvAndCmykConversionTests.cs new file mode 100644 index 0000000000..60ac3da16e --- /dev/null +++ b/tests/ImageSharp.Tests/ColorProfiles/CieLchuvAndCmykConversionTests.cs @@ -0,0 +1,72 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.ColorProfiles; + +namespace SixLabors.ImageSharp.Tests.ColorProfiles; + +/// +/// Tests - conversions. +/// +public class CieLchuvAndCmykConversionTests +{ + private static readonly ApproximateColorProfileComparer Comparer = new(.0001F); + + [Theory] + [InlineData(0, 0, 0, 1, 0, 0, 0)] + [InlineData(0, 0.8576171, 0.7693201, 0.3440427, 36.0555, 103.6901, 10.01514)] + public void Convert_Cmyk_to_CieLchuv(float c2, float m, float y, float k, float l, float c, float h) + { + // Arrange + Cmyk input = new(c2, m, y, k); + CieLchuv expected = new(l, c, h); + ColorConversionOptions options = new() { WhitePoint = KnownIlluminants.D65, TargetWhitePoint = KnownIlluminants.D65 }; + ColorProfileConverter converter = new(options); + + Span inputSpan = new Cmyk[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLchuv[5]; + + // Act + CieLchuv actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0, 1)] + [InlineData(36.0555, 103.6901, 10.01514, 0, 0.8576171, 0.7693201, 0.3440427)] + public void Convert_CieLchuv_to_Cmyk(float l, float c, float h, float c2, float m, float y, float k) + { + // Arrange + CieLchuv input = new(l, c, h); + Cmyk expected = new(c2, m, y, k); + ColorConversionOptions options = new() { WhitePoint = KnownIlluminants.D65, TargetWhitePoint = KnownIlluminants.D65 }; + ColorProfileConverter converter = new(options); + + Span inputSpan = new CieLchuv[5]; + inputSpan.Fill(input); + + Span actualSpan = new Cmyk[5]; + + // Act + Cmyk actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } +} diff --git a/tests/ImageSharp.Tests/Colorspaces/CieLchuvTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CieLchuvTests.cs similarity index 65% rename from tests/ImageSharp.Tests/Colorspaces/CieLchuvTests.cs rename to tests/ImageSharp.Tests/ColorProfiles/CieLchuvTests.cs index f6c68aae91..0b737cdfca 100644 --- a/tests/ImageSharp.Tests/Colorspaces/CieLchuvTests.cs +++ b/tests/ImageSharp.Tests/ColorProfiles/CieLchuvTests.cs @@ -1,10 +1,10 @@ -// Copyright (c) Six Labors. +// Copyright (c) Six Labors. // Licensed under the Six Labors Split License. using System.Numerics; -using SixLabors.ImageSharp.ColorSpaces; +using SixLabors.ImageSharp.ColorProfiles; -namespace SixLabors.ImageSharp.Tests.Colorspaces; +namespace SixLabors.ImageSharp.Tests.ColorProfiles; /// /// Tests the struct. @@ -17,7 +17,7 @@ public void CieLchuvConstructorAssignsFields() const float l = 75F; const float c = 64F; const float h = 287F; - var cieLchuv = new CieLchuv(l, c, h); + CieLchuv cieLchuv = new(l, c, h); Assert.Equal(l, cieLchuv.L); Assert.Equal(c, cieLchuv.C); @@ -27,12 +27,12 @@ public void CieLchuvConstructorAssignsFields() [Fact] public void CieLchuvEquality() { - var x = default(CieLchuv); - var y = new CieLchuv(Vector3.One); + CieLchuv x = default; + CieLchuv y = new(Vector3.One); - Assert.True(default(CieLchuv) == default(CieLchuv)); - Assert.False(default(CieLchuv) != default(CieLchuv)); - Assert.Equal(default(CieLchuv), default(CieLchuv)); + Assert.True(default == default(CieLchuv)); + Assert.False(default != default(CieLchuv)); + Assert.Equal(default, default(CieLchuv)); Assert.Equal(new CieLchuv(1, 0, 1), new CieLchuv(1, 0, 1)); Assert.Equal(new CieLchuv(Vector3.One), new CieLchuv(Vector3.One)); Assert.False(x.Equals(y)); diff --git a/tests/ImageSharp.Tests/ColorProfiles/CieLuvAndCieXyyConversionTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CieLuvAndCieXyyConversionTests.cs new file mode 100644 index 0000000000..e73edcda7c --- /dev/null +++ b/tests/ImageSharp.Tests/ColorProfiles/CieLuvAndCieXyyConversionTests.cs @@ -0,0 +1,72 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.ColorProfiles; + +namespace SixLabors.ImageSharp.Tests.ColorProfiles; + +/// +/// Tests - conversions. +/// +public class CieLuvAndCieXyyConversionTests +{ + private static readonly ApproximateColorProfileComparer Comparer = new(.0002F); + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(36.0555, 103.6901, 10.01514, 0.5646762, 0.2932749, 0.09037033)] + public void Convert_CieLuv_to_CieXyy(float l, float u, float v, float x, float y, float yl) + { + // Arrange + CieLuv input = new(l, u, v); + CieXyy expected = new(x, y, yl); + ColorConversionOptions options = new() { WhitePoint = KnownIlluminants.D65, TargetWhitePoint = KnownIlluminants.D65 }; + ColorProfileConverter converter = new(options); + + Span inputSpan = new CieLuv[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieXyy[5]; + + // Act + CieXyy actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(0.5646762, 0.2932749, 0.09037033, 36.0555, 103.6901, 10.01514)] + public void Convert_CieXyy_to_CieLuv(float x, float y, float yl, float l, float u, float v) + { + // Arrange + CieXyy input = new(x, y, yl); + CieLuv expected = new(l, u, v); + ColorConversionOptions options = new() { WhitePoint = KnownIlluminants.D65, TargetWhitePoint = KnownIlluminants.D65 }; + ColorProfileConverter converter = new(options); + + Span inputSpan = new CieXyy[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLuv[5]; + + // Act + CieLuv actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } +} diff --git a/tests/ImageSharp.Tests/ColorProfiles/CieLuvAndHslConversionTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CieLuvAndHslConversionTests.cs new file mode 100644 index 0000000000..b178b22b20 --- /dev/null +++ b/tests/ImageSharp.Tests/ColorProfiles/CieLuvAndHslConversionTests.cs @@ -0,0 +1,72 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.ColorProfiles; + +namespace SixLabors.ImageSharp.Tests.ColorProfiles; + +/// +/// Tests - conversions. +/// +public class CieLuvAndHslConversionTests +{ + private static readonly ApproximateColorProfileComparer Comparer = new(.0002F); + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(36.0555, 93.6901, 10.01514, 347.3767, 0.7115612, 0.3765343)] + public void Convert_CieLuv_to_Hsl(float l, float u, float v, float h, float s, float l2) + { + // Arrange + CieLuv input = new(l, u, v); + Hsl expected = new(h, s, l2); + ColorConversionOptions options = new() { WhitePoint = KnownIlluminants.D65, TargetWhitePoint = KnownIlluminants.D65 }; + ColorProfileConverter converter = new(options); + + Span inputSpan = new CieLuv[5]; + inputSpan.Fill(input); + + Span actualSpan = new Hsl[5]; + + // Act + Hsl actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(347.3767, 0.7115612, 0.3765343, 36.0555, 93.69012, 10.01514)] + public void Convert_Hsl_to_CieLuv(float h, float s, float l2, float l, float u, float v) + { + // Arrange + Hsl input = new(h, s, l2); + CieLuv expected = new(l, u, v); + ColorConversionOptions options = new() { WhitePoint = KnownIlluminants.D65, TargetWhitePoint = KnownIlluminants.D65 }; + ColorProfileConverter converter = new(options); + + Span inputSpan = new Hsl[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLuv[5]; + + // Act + CieLuv actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } +} diff --git a/tests/ImageSharp.Tests/ColorProfiles/CieLuvAndHsvConversionTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CieLuvAndHsvConversionTests.cs new file mode 100644 index 0000000000..2866093377 --- /dev/null +++ b/tests/ImageSharp.Tests/ColorProfiles/CieLuvAndHsvConversionTests.cs @@ -0,0 +1,72 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.ColorProfiles; + +namespace SixLabors.ImageSharp.Tests.ColorProfiles; + +/// +/// Tests - conversions. +/// +public class CieLuvAndHsvConversionTests +{ + private static readonly ApproximateColorProfileComparer Comparer = new(.0002F); + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(36.0555, 93.6901, 10.01514, 347.3767, 0.8314762, 0.6444615)] + public void Convert_CieLuv_to_Hsv(float l, float u, float v, float h, float s, float v2) + { + // Arrange + CieLuv input = new(l, u, v); + Hsv expected = new(h, s, v2); + ColorConversionOptions options = new() { WhitePoint = KnownIlluminants.D65, TargetWhitePoint = KnownIlluminants.D65 }; + ColorProfileConverter converter = new(options); + + Span inputSpan = new CieLuv[5]; + inputSpan.Fill(input); + + Span actualSpan = new Hsv[5]; + + // Act + Hsv actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(347.3767, 0.8314762, 0.6444615, 36.0555, 93.69012, 10.01514)] + public void Convert_Hsv_to_CieLuv(float h, float s, float v2, float l, float u, float v) + { + // Arrange + Hsv input = new(h, s, v2); + CieLuv expected = new(l, u, v); + ColorConversionOptions options = new() { WhitePoint = KnownIlluminants.D65, TargetWhitePoint = KnownIlluminants.D65 }; + ColorProfileConverter converter = new(options); + + Span inputSpan = new Hsv[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLuv[5]; + + // Act + CieLuv actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } +} diff --git a/tests/ImageSharp.Tests/ColorProfiles/CieLuvAndHunterLabConversionTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CieLuvAndHunterLabConversionTests.cs new file mode 100644 index 0000000000..73b605fb62 --- /dev/null +++ b/tests/ImageSharp.Tests/ColorProfiles/CieLuvAndHunterLabConversionTests.cs @@ -0,0 +1,72 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.ColorProfiles; + +namespace SixLabors.ImageSharp.Tests.ColorProfiles; + +/// +/// Tests - conversions. +/// +public class CieLuvAndHunterLabConversionTests +{ + private static readonly ApproximateColorProfileComparer Comparer = new(.0002F); + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(36.0555, 93.6901, 10.01514, 30.59289, 48.55542, 9.80487)] + public void Convert_CieLuv_To_HunterLab(float l, float u, float v, float l2, float a, float b) + { + // Arrange + CieLuv input = new(l, u, v); + HunterLab expected = new(l2, a, b); + ColorConversionOptions options = new() { WhitePoint = KnownIlluminants.D65, TargetWhitePoint = KnownIlluminants.D50 }; + ColorProfileConverter converter = new(options); + + Span inputSpan = new CieLuv[5]; + inputSpan.Fill(input); + + Span actualSpan = new HunterLab[5]; + + // Act + HunterLab actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(30.59289, 48.55542, 9.80487, 36.0555, 93.6901, 10.01514)] + public void Convert_HunterLab_To_CieLuv(float l2, float a, float b, float l, float u, float v) + { + // Arrange + HunterLab input = new(l2, a, b); + CieLuv expected = new(l, u, v); + ColorConversionOptions options = new() { WhitePoint = KnownIlluminants.D50, TargetWhitePoint = KnownIlluminants.D65 }; + ColorProfileConverter converter = new(options); + + Span inputSpan = new HunterLab[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLuv[5]; + + // Act + CieLuv actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } +} diff --git a/tests/ImageSharp.Tests/ColorProfiles/CieLuvAndLmsConversionTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CieLuvAndLmsConversionTests.cs new file mode 100644 index 0000000000..812ca44ddc --- /dev/null +++ b/tests/ImageSharp.Tests/ColorProfiles/CieLuvAndLmsConversionTests.cs @@ -0,0 +1,72 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.ColorProfiles; + +namespace SixLabors.ImageSharp.Tests.ColorProfiles; + +/// +/// Tests - conversions. +/// +public class CieLuvAndLmsConversionTests +{ + private static readonly ApproximateColorProfileComparer Comparer = new(.0002F); + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(36.0555, 93.6901, 10.01514, 0.164352, 0.03267485, 0.0483408)] + public void Convert_CieLuv_to_Lms(float l, float u, float v, float l2, float m, float s) + { + // Arrange + CieLuv input = new(l, u, v); + Lms expected = new(l2, m, s); + ColorConversionOptions options = new() { WhitePoint = KnownIlluminants.D65, TargetWhitePoint = KnownIlluminants.D65 }; + ColorProfileConverter converter = new(options); + + Span inputSpan = new CieLuv[5]; + inputSpan.Fill(input); + + Span actualSpan = new Lms[5]; + + // Act + Lms actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(0.164352, 0.03267485, 0.0483408, 36.0555, 93.69009, 10.01514)] + public void Convert_Lms_to_CieLuv(float l2, float m, float s, float l, float u, float v) + { + // Arrange + Lms input = new(l2, m, s); + CieLuv expected = new(l, u, v); + ColorConversionOptions options = new() { WhitePoint = KnownIlluminants.D65, TargetWhitePoint = KnownIlluminants.D65 }; + ColorProfileConverter converter = new(options); + + Span inputSpan = new Lms[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLuv[5]; + + // Act + CieLuv actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } +} diff --git a/tests/ImageSharp.Tests/ColorProfiles/CieLuvAndRgbConversionTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CieLuvAndRgbConversionTests.cs new file mode 100644 index 0000000000..f1da6e33fd --- /dev/null +++ b/tests/ImageSharp.Tests/ColorProfiles/CieLuvAndRgbConversionTests.cs @@ -0,0 +1,72 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.ColorProfiles; + +namespace SixLabors.ImageSharp.Tests.ColorProfiles; + +/// +/// Tests - conversions. +/// +public class CieLuvAndRgbConversionTests +{ + private static readonly ApproximateColorProfileComparer Comparer = new(.0002F); + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(36.0555, 93.6901, 10.01514, 0.6444615, 0.1086071, 0.2213444)] + public void Convert_CieLuv_to_Rgb(float l, float u, float v, float r, float g, float b) + { + // Arrange + CieLuv input = new(l, u, v); + Rgb expected = new(r, g, b); + ColorConversionOptions options = new() { WhitePoint = KnownIlluminants.D65, TargetWhitePoint = KnownIlluminants.D65 }; + ColorProfileConverter converter = new(options); + + Span inputSpan = new CieLuv[5]; + inputSpan.Fill(input); + + Span actualSpan = new Rgb[5]; + + // Act + Rgb actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(0.6444615, 0.1086071, 0.2213444, 36.0555, 93.69012, 10.01514)] + public void Convert_Rgb_to_CieLuv(float r, float g, float b, float l, float u, float v) + { + // Arrange + Rgb input = new(r, g, b); + CieLuv expected = new(l, u, v); + ColorConversionOptions options = new() { WhitePoint = KnownIlluminants.D65, TargetWhitePoint = KnownIlluminants.D65 }; + ColorProfileConverter converter = new(options); + + Span inputSpan = new Rgb[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLuv[5]; + + // Act + CieLuv actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } +} diff --git a/tests/ImageSharp.Tests/ColorProfiles/CieLuvAndYCbCrConversionTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CieLuvAndYCbCrConversionTests.cs new file mode 100644 index 0000000000..fa7e2ece3f --- /dev/null +++ b/tests/ImageSharp.Tests/ColorProfiles/CieLuvAndYCbCrConversionTests.cs @@ -0,0 +1,72 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.ColorProfiles; + +namespace SixLabors.ImageSharp.Tests.ColorProfiles; + +/// +/// Tests - conversions. +/// +public class CieLuvAndYCbCrConversionTests +{ + private static readonly ApproximateColorProfileComparer Comparer = new(.0002F); + + [Theory] + [InlineData(0, 0, 0, 0, 128, 128)] + [InlineData(36.0555, 93.6901, 10.01514, 71.8283, 119.3174, 193.9839)] + public void Convert_CieLuv_to_YCbCr(float l, float u, float v, float y, float cb, float cr) + { + // Arrange + CieLuv input = new(l, u, v); + YCbCr expected = new(y, cb, cr); + ColorConversionOptions options = new() { WhitePoint = KnownIlluminants.D65, TargetWhitePoint = KnownIlluminants.D65 }; + ColorProfileConverter converter = new(options); + + Span inputSpan = new CieLuv[5]; + inputSpan.Fill(input); + + Span actualSpan = new YCbCr[5]; + + // Act + YCbCr actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } + + [Theory] + [InlineData(0, 128, 128, 0, 0, 0)] + [InlineData(71.8283, 119.3174, 193.9839, 36.00565, 93.44593, 10.2234)] + public void Convert_YCbCr_to_CieLuv(float y, float cb, float cr, float l, float u, float v) + { + // Arrange + YCbCr input = new(y, cb, cr); + CieLuv expected = new(l, u, v); + ColorConversionOptions options = new() { WhitePoint = KnownIlluminants.D65, TargetWhitePoint = KnownIlluminants.D65 }; + ColorProfileConverter converter = new(options); + + Span inputSpan = new YCbCr[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLuv[5]; + + // Act + CieLuv actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } +} diff --git a/tests/ImageSharp.Tests/Colorspaces/CieLuvTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CieLuvTests.cs similarity index 65% rename from tests/ImageSharp.Tests/Colorspaces/CieLuvTests.cs rename to tests/ImageSharp.Tests/ColorProfiles/CieLuvTests.cs index 0ebf1bdeaa..db903a0bf5 100644 --- a/tests/ImageSharp.Tests/Colorspaces/CieLuvTests.cs +++ b/tests/ImageSharp.Tests/ColorProfiles/CieLuvTests.cs @@ -1,10 +1,10 @@ -// Copyright (c) Six Labors. +// Copyright (c) Six Labors. // Licensed under the Six Labors Split License. using System.Numerics; -using SixLabors.ImageSharp.ColorSpaces; +using SixLabors.ImageSharp.ColorProfiles; -namespace SixLabors.ImageSharp.Tests.Colorspaces; +namespace SixLabors.ImageSharp.Tests.ColorProfiles; /// /// Tests the struct. @@ -17,7 +17,7 @@ public void CieLuvConstructorAssignsFields() const float l = 75F; const float c = -64F; const float h = 87F; - var cieLuv = new CieLuv(l, c, h); + CieLuv cieLuv = new(l, c, h); Assert.Equal(l, cieLuv.L); Assert.Equal(c, cieLuv.U); @@ -27,12 +27,12 @@ public void CieLuvConstructorAssignsFields() [Fact] public void CieLuvEquality() { - var x = default(CieLuv); - var y = new CieLuv(Vector3.One); + CieLuv x = default; + CieLuv y = new(Vector3.One); - Assert.True(default(CieLuv) == default(CieLuv)); - Assert.False(default(CieLuv) != default(CieLuv)); - Assert.Equal(default(CieLuv), default(CieLuv)); + Assert.True(default == default(CieLuv)); + Assert.False(default != default(CieLuv)); + Assert.Equal(default, default(CieLuv)); Assert.Equal(new CieLuv(1, 0, 1), new CieLuv(1, 0, 1)); Assert.Equal(new CieLuv(Vector3.One), new CieLuv(Vector3.One)); Assert.False(x.Equals(y)); diff --git a/tests/ImageSharp.Tests/Colorspaces/CieXyChromaticityCoordinatesTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CieXyChromaticityCoordinatesTests.cs similarity index 64% rename from tests/ImageSharp.Tests/Colorspaces/CieXyChromaticityCoordinatesTests.cs rename to tests/ImageSharp.Tests/ColorProfiles/CieXyChromaticityCoordinatesTests.cs index 061d6c432f..a85a08a21e 100644 --- a/tests/ImageSharp.Tests/Colorspaces/CieXyChromaticityCoordinatesTests.cs +++ b/tests/ImageSharp.Tests/ColorProfiles/CieXyChromaticityCoordinatesTests.cs @@ -1,9 +1,9 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.ColorSpaces.Conversion; +using SixLabors.ImageSharp.ColorProfiles; -namespace SixLabors.ImageSharp.Tests.Colorspaces; +namespace SixLabors.ImageSharp.Tests.ColorProfiles; /// /// Tests the struct. @@ -15,7 +15,7 @@ public void CieXyChromaticityCoordinatesConstructorAssignsFields() { const float x = .75F; const float y = .64F; - var coordinates = new CieXyChromaticityCoordinates(x, y); + CieXyChromaticityCoordinates coordinates = new(x, y); Assert.Equal(x, coordinates.X); Assert.Equal(y, coordinates.Y); @@ -24,17 +24,17 @@ public void CieXyChromaticityCoordinatesConstructorAssignsFields() [Fact] public void CieXyChromaticityCoordinatesEquality() { - var x = default(CieXyChromaticityCoordinates); - var y = new CieXyChromaticityCoordinates(1, 1); + CieXyChromaticityCoordinates x = default; + CieXyChromaticityCoordinates y = new(1, 1); - Assert.True(default(CieXyChromaticityCoordinates) == default(CieXyChromaticityCoordinates)); - Assert.True(new CieXyChromaticityCoordinates(1, 0) != default(CieXyChromaticityCoordinates)); - Assert.False(new CieXyChromaticityCoordinates(1, 0) == default(CieXyChromaticityCoordinates)); - Assert.Equal(default(CieXyChromaticityCoordinates), default(CieXyChromaticityCoordinates)); + Assert.True(default == default(CieXyChromaticityCoordinates)); + Assert.True(new CieXyChromaticityCoordinates(1, 0) != default); + Assert.False(new CieXyChromaticityCoordinates(1, 0) == default); + Assert.Equal(default, default(CieXyChromaticityCoordinates)); Assert.Equal(new CieXyChromaticityCoordinates(1, 0), new CieXyChromaticityCoordinates(1, 0)); Assert.Equal(new CieXyChromaticityCoordinates(1, 1), new CieXyChromaticityCoordinates(1, 1)); Assert.False(x.Equals(y)); - Assert.False(new CieXyChromaticityCoordinates(1, 0) == default(CieXyChromaticityCoordinates)); + Assert.False(new CieXyChromaticityCoordinates(1, 0) == default); Assert.False(x.Equals((object)y)); Assert.False(x.GetHashCode().Equals(y.GetHashCode())); } diff --git a/tests/ImageSharp.Tests/ColorProfiles/CieXyyAndHslConversionTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CieXyyAndHslConversionTests.cs new file mode 100644 index 0000000000..3e93206ce4 --- /dev/null +++ b/tests/ImageSharp.Tests/ColorProfiles/CieXyyAndHslConversionTests.cs @@ -0,0 +1,70 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.ColorProfiles; + +namespace SixLabors.ImageSharp.Tests.ColorProfiles; + +/// +/// Tests - conversions. +/// +public class CieXyyAndHslConversionTests +{ + private static readonly ApproximateColorProfileComparer Comparer = new(.0002F); + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(0.360555, 0.936901, 0.1001514, 120, 1, 0.2138507)] + public void Convert_CieXyy_to_Hsl(float x, float y, float yl, float h, float s, float l) + { + // Arrange + CieXyy input = new(x, y, yl); + Hsl expected = new(h, s, l); + ColorProfileConverter converter = new(); + + Span inputSpan = new CieXyy[5]; + inputSpan.Fill(input); + + Span actualSpan = new Hsl[5]; + + // Act + Hsl actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(120, 1, 0.2138507, 0.32114, 0.59787, 0.10976)] + public void Convert_Hsl_to_CieXyy(float h, float s, float l, float x, float y, float yl) + { + // Arrange + Hsl input = new(h, s, l); + CieXyy expected = new(x, y, yl); + ColorProfileConverter converter = new(); + + Span inputSpan = new Hsl[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieXyy[5]; + + // Act + CieXyy actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } +} diff --git a/tests/ImageSharp.Tests/ColorProfiles/CieXyyAndHsvConversionTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CieXyyAndHsvConversionTests.cs new file mode 100644 index 0000000000..c2547ca847 --- /dev/null +++ b/tests/ImageSharp.Tests/ColorProfiles/CieXyyAndHsvConversionTests.cs @@ -0,0 +1,70 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.ColorProfiles; + +namespace SixLabors.ImageSharp.Tests.ColorProfiles; + +/// +/// Tests - conversions. +/// +public class CieXyyAndHsvConversionTests +{ + private static readonly ApproximateColorProfileComparer Comparer = new(.0002F); + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(0.360555, 0.936901, 0.1001514, 120, 1, 0.42770)] + public void Convert_CieXyy_To_Hsv(float x, float y, float yl, float h, float s, float v) + { + // Arrange + CieXyy input = new(x, y, yl); + Hsv expected = new(h, s, v); + ColorProfileConverter converter = new(); + + Span inputSpan = new CieXyy[5]; + inputSpan.Fill(input); + + Span actualSpan = new Hsv[5]; + + // Act + Hsv actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(120, 1, 0.42770, 0.32114, 0.59787, 0.10976)] + public void Convert_Hsv_To_CieXyy(float h, float s, float v, float x, float y, float yl) + { + // Arrange + Hsv input = new(h, s, v); + CieXyy expected = new(x, y, yl); + ColorProfileConverter converter = new(); + + Span inputSpan = new Hsv[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieXyy[5]; + + // Act + CieXyy actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } +} diff --git a/tests/ImageSharp.Tests/ColorProfiles/CieXyyAndHunterLabConversionTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CieXyyAndHunterLabConversionTests.cs new file mode 100644 index 0000000000..4f66538f0f --- /dev/null +++ b/tests/ImageSharp.Tests/ColorProfiles/CieXyyAndHunterLabConversionTests.cs @@ -0,0 +1,70 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.ColorProfiles; + +namespace SixLabors.ImageSharp.Tests.ColorProfiles; + +/// +/// Tests - conversions. +/// +public class CieXyyAndHunterLabConversionTests +{ + private static readonly ApproximateColorProfileComparer Comparer = new(.0002f); + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(0.360555, 0.936901, 0.1001514, 31.6467056, -33.00599, 25.67032)] + public void Convert_CieXyy_To_HunterLab(float x, float y, float yl, float l, float a, float b) + { + // Arrange + CieXyy input = new(x, y, yl); + HunterLab expected = new(l, a, b); + ColorProfileConverter converter = new(); + + Span inputSpan = new CieXyy[5]; + inputSpan.Fill(input); + + Span actualSpan = new HunterLab[5]; + + // Act + HunterLab actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(31.6467056, -33.00599, 25.67032, 0.360555, 0.936901, 0.1001514)] + public void Convert_HunterLab_To_CieXyy(float l, float a, float b, float x, float y, float yl) + { + // Arrange + HunterLab input = new(l, a, b); + CieXyy expected = new(x, y, yl); + ColorProfileConverter converter = new(); + + Span inputSpan = new HunterLab[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieXyy[5]; + + // Act + CieXyy actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } +} diff --git a/tests/ImageSharp.Tests/ColorProfiles/CieXyyAndLmsConversionTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CieXyyAndLmsConversionTests.cs new file mode 100644 index 0000000000..1a89cb26dc --- /dev/null +++ b/tests/ImageSharp.Tests/ColorProfiles/CieXyyAndLmsConversionTests.cs @@ -0,0 +1,70 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.ColorProfiles; + +namespace SixLabors.ImageSharp.Tests.ColorProfiles; + +/// +/// Tests - conversions. +/// +public class CieXyyAndLmsConversionTests +{ + private static readonly ApproximateColorProfileComparer Comparer = new(.0002f); + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(0.360555, 0.936901, 0.1001514, 0.06631134, 0.1415282, -0.03809926)] + public void Convert_CieXyy_to_Lms(float x, float y, float yl, float l, float m, float s) + { + // Arrange + CieXyy input = new(x, y, yl); + Lms expected = new(l, m, s); + ColorProfileConverter converter = new(); + + Span inputSpan = new CieXyy[5]; + inputSpan.Fill(input); + + Span actualSpan = new Lms[5]; + + // Act + Lms actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(0.06631134, 0.1415282, -0.03809926, 0.360555, 0.936901, 0.1001514)] + public void Convert_Lms_to_CieXyy(float l, float m, float s, float x, float y, float yl) + { + // Arrange + Lms input = new(l, m, s); + CieXyy expected = new(x, y, yl); + ColorProfileConverter converter = new(); + + Span inputSpan = new Lms[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieXyy[5]; + + // Act + CieXyy actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } +} diff --git a/tests/ImageSharp.Tests/ColorProfiles/CieXyyAndRgbConversionTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CieXyyAndRgbConversionTests.cs new file mode 100644 index 0000000000..18df2ce145 --- /dev/null +++ b/tests/ImageSharp.Tests/ColorProfiles/CieXyyAndRgbConversionTests.cs @@ -0,0 +1,70 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.ColorProfiles; + +namespace SixLabors.ImageSharp.Tests.ColorProfiles; + +/// +/// Tests - conversions. +/// +public class CieXyyAndRgbConversionTests +{ + private static readonly ApproximateColorProfileComparer Comparer = new(.0002f); + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(0.360555, 0.936901, 0.1001514, 0, 0.4277014, 0)] + public void Convert_CieXyy_to_Rgb(float x, float y, float yl, float r, float g, float b) + { + // Arrange + CieXyy input = new(x, y, yl); + Rgb expected = new(r, g, b); + ColorProfileConverter converter = new(); + + Span inputSpan = new CieXyy[5]; + inputSpan.Fill(input); + + Span actualSpan = new Rgb[5]; + + // Act + Rgb actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(0, 0.4277014, 0, 0.32114, 0.59787, 0.10976)] + public void Convert_Rgb_to_CieXyy(float r, float g, float b, float x, float y, float yl) + { + // Arrange + Rgb input = new(r, g, b); + CieXyy expected = new(x, y, yl); + ColorProfileConverter converter = new(); + + Span inputSpan = new Rgb[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieXyy[5]; + + // Act + CieXyy actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } +} diff --git a/tests/ImageSharp.Tests/ColorProfiles/CieXyyAndYCbCrConversionTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CieXyyAndYCbCrConversionTests.cs new file mode 100644 index 0000000000..1fe3596036 --- /dev/null +++ b/tests/ImageSharp.Tests/ColorProfiles/CieXyyAndYCbCrConversionTests.cs @@ -0,0 +1,70 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.ColorProfiles; + +namespace SixLabors.ImageSharp.Tests.ColorProfiles; + +/// +/// Tests - conversions. +/// +public class CieXyyAndYCbCrConversionTests +{ + private static readonly ApproximateColorProfileComparer Comparer = new(.0002f); + + [Theory] + [InlineData(0, 0, 0, 0, 128, 128)] + [InlineData(0.360555, 0.936901, 0.1001514, 64.0204849, 91.87107, 82.33627)] + public void Convert_CieXyy_to_YCbCr(float x, float y, float yl, float y2, float cb, float cr) + { + // Arrange + CieXyy input = new(x, y, yl); + YCbCr expected = new(y2, cb, cr); + ColorProfileConverter converter = new(); + + Span inputSpan = new CieXyy[5]; + inputSpan.Fill(input); + + Span actualSpan = new YCbCr[5]; + + // Act + YCbCr actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } + + [Theory] + [InlineData(0, 128, 128, 0, 0, 0)] + [InlineData(64.0204849, 91.87107, 82.33627, 0.32114, 0.59787, 0.10976)] + public void Convert_YCbCr_to_CieXyy(float y2, float cb, float cr, float x, float y, float yl) + { + // Arrange + YCbCr input = new(y2, cb, cr); + CieXyy expected = new(x, y, yl); + ColorProfileConverter converter = new(); + + Span inputSpan = new YCbCr[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieXyy[5]; + + // Act + CieXyy actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } +} diff --git a/tests/ImageSharp.Tests/Colorspaces/CieXyyTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CieXyyTests.cs similarity index 65% rename from tests/ImageSharp.Tests/Colorspaces/CieXyyTests.cs rename to tests/ImageSharp.Tests/ColorProfiles/CieXyyTests.cs index f1eb126401..245512f8a8 100644 --- a/tests/ImageSharp.Tests/Colorspaces/CieXyyTests.cs +++ b/tests/ImageSharp.Tests/ColorProfiles/CieXyyTests.cs @@ -1,10 +1,10 @@ -// Copyright (c) Six Labors. +// Copyright (c) Six Labors. // Licensed under the Six Labors Split License. using System.Numerics; -using SixLabors.ImageSharp.ColorSpaces; +using SixLabors.ImageSharp.ColorProfiles; -namespace SixLabors.ImageSharp.Tests.Colorspaces; +namespace SixLabors.ImageSharp.Tests.ColorProfiles; /// /// Tests the struct. @@ -17,7 +17,7 @@ public void CieXyyConstructorAssignsFields() const float x = 75F; const float y = 64F; const float yl = 287F; - var cieXyy = new CieXyy(x, y, yl); + CieXyy cieXyy = new(x, y, yl); Assert.Equal(x, cieXyy.X); Assert.Equal(y, cieXyy.Y); @@ -27,12 +27,12 @@ public void CieXyyConstructorAssignsFields() [Fact] public void CieXyyEquality() { - var x = default(CieXyy); - var y = new CieXyy(Vector3.One); + CieXyy x = default; + CieXyy y = new(Vector3.One); - Assert.True(default(CieXyy) == default(CieXyy)); - Assert.False(default(CieXyy) != default(CieXyy)); - Assert.Equal(default(CieXyy), default(CieXyy)); + Assert.True(default == default(CieXyy)); + Assert.False(default != default(CieXyy)); + Assert.Equal(default, default(CieXyy)); Assert.Equal(new CieXyy(1, 0, 1), new CieXyy(1, 0, 1)); Assert.Equal(new CieXyy(Vector3.One), new CieXyy(Vector3.One)); Assert.False(x.Equals(y)); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLabConversionTest.cs b/tests/ImageSharp.Tests/ColorProfiles/CieXyzAndCieLabConversionTest.cs similarity index 51% rename from tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLabConversionTest.cs rename to tests/ImageSharp.Tests/ColorProfiles/CieXyzAndCieLabConversionTest.cs index 3ea4228e5e..cb4d028895 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLabConversionTest.cs +++ b/tests/ImageSharp.Tests/ColorProfiles/CieXyzAndCieLabConversionTest.cs @@ -1,10 +1,9 @@ -// Copyright (c) Six Labors. +// Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; +using SixLabors.ImageSharp.ColorProfiles; -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; +namespace SixLabors.ImageSharp.Tests.ColorProfiles; /// /// Tests - conversions. @@ -15,11 +14,8 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; /// public class CieXyzAndCieLabConversionTest { - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0001F); + private static readonly ApproximateColorProfileComparer Comparer = new(.0001f); - /// - /// Tests conversion from to (). - /// [Theory] [InlineData(100, 0, 0, 0.95047, 1, 1.08883)] [InlineData(0, 0, 0, 0, 0, 0)] @@ -28,14 +24,14 @@ public class CieXyzAndCieLabConversionTest [InlineData(0, 0, -172.4138, 0, 0, 1.08883)] [InlineData(45.6398, 39.8753, 35.2091, 0.216938, 0.150041, 0.048850)] [InlineData(77.1234, -40.1235, 78.1120, 0.358530, 0.517372, 0.076273)] - [InlineData(10, -400, 20, 0, 0.011260, 0)] + [InlineData(10, -400, 20, -0.08712, 0.01126, -0.00192)] public void Convert_Lab_to_Xyz(float l, float a, float b, float x, float y, float z) { // Arrange - var input = new CieLab(l, a, b, Illuminants.D65); - var options = new ColorSpaceConverterOptions { WhitePoint = Illuminants.D65, TargetLabWhitePoint = Illuminants.D65 }; - var converter = new ColorSpaceConverter(options); - var expected = new CieXyz(x, y, z); + CieLab input = new(l, a, b); + ColorConversionOptions options = new() { WhitePoint = KnownIlluminants.D65, TargetWhitePoint = KnownIlluminants.D65 }; + ColorProfileConverter converter = new(options); + CieXyz expected = new(x, y, z); Span inputSpan = new CieLab[5]; inputSpan.Fill(input); @@ -43,21 +39,18 @@ public void Convert_Lab_to_Xyz(float l, float a, float b, float x, float y, floa Span actualSpan = new CieXyz[5]; // Act - var actual = converter.ToCieXyz(input); - converter.Convert(inputSpan, actualSpan); + CieXyz actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); + Assert.Equal(expected, actual, Comparer); for (int i = 0; i < actualSpan.Length; i++) { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + Assert.Equal(expected, actualSpan[i], Comparer); } } - /// - /// Tests conversion from () to . - /// [Theory] [InlineData(0.95047, 1, 1.08883, 100, 0, 0)] [InlineData(0, 0, 0, 0, 0, 0)] @@ -68,10 +61,10 @@ public void Convert_Lab_to_Xyz(float l, float a, float b, float x, float y, floa public void Convert_Xyz_to_Lab(float x, float y, float z, float l, float a, float b) { // Arrange - var input = new CieXyz(x, y, z); - var options = new ColorSpaceConverterOptions { WhitePoint = Illuminants.D65, TargetLabWhitePoint = Illuminants.D65 }; - var converter = new ColorSpaceConverter(options); - var expected = new CieLab(l, a, b); + CieXyz input = new(x, y, z); + ColorConversionOptions options = new() { WhitePoint = KnownIlluminants.D65, TargetWhitePoint = KnownIlluminants.D65 }; + ColorProfileConverter converter = new(options); + CieLab expected = new(l, a, b); Span inputSpan = new CieXyz[5]; inputSpan.Fill(input); @@ -79,15 +72,15 @@ public void Convert_Xyz_to_Lab(float x, float y, float z, float l, float a, floa Span actualSpan = new CieLab[5]; // Act - var actual = converter.ToCieLab(input); - converter.Convert(inputSpan, actualSpan); + CieLab actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); + Assert.Equal(expected, actual, Comparer); for (int i = 0; i < actualSpan.Length; i++) { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + Assert.Equal(expected, actualSpan[i], Comparer); } } } diff --git a/tests/ImageSharp.Tests/ColorProfiles/CieXyzAndCieLchConversionTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CieXyzAndCieLchConversionTests.cs new file mode 100644 index 0000000000..bde3b8e17b --- /dev/null +++ b/tests/ImageSharp.Tests/ColorProfiles/CieXyzAndCieLchConversionTests.cs @@ -0,0 +1,70 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.ColorProfiles; + +namespace SixLabors.ImageSharp.Tests.ColorProfiles; + +/// +/// Tests - conversions. +/// +public class CieXyzAndCieLchConversionTests +{ + private static readonly ApproximateColorProfileComparer Comparer = new(.0002f); + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(0.360555, 0.936901, 0.1001514, 97.50697, 161.235321, 143.157)] + public void Convert_CieXyz_to_CieLch(float x, float y, float yl, float l, float c, float h) + { + // Arrange + CieXyz input = new(x, y, yl); + CieLch expected = new(l, c, h); + ColorProfileConverter converter = new(); + + Span inputSpan = new CieXyz[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLch[5]; + + // Act + CieLch actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(97.50697, 161.235321, 143.157, 0.3605551, 0.936901, 0.1001514)] + public void Convert_CieLch_to_CieXyz(float l, float c, float h, float x, float y, float yl) + { + // Arrange + CieLch input = new(l, c, h); + CieXyz expected = new(x, y, yl); + ColorProfileConverter converter = new(); + + Span inputSpan = new CieLch[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieXyz[5]; + + // Act + CieXyz actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } +} diff --git a/tests/ImageSharp.Tests/ColorProfiles/CieXyzAndCieLchuvConversionTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CieXyzAndCieLchuvConversionTests.cs new file mode 100644 index 0000000000..fa604250f2 --- /dev/null +++ b/tests/ImageSharp.Tests/ColorProfiles/CieXyzAndCieLchuvConversionTests.cs @@ -0,0 +1,69 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.ColorProfiles; + +namespace SixLabors.ImageSharp.Tests.ColorProfiles; + +/// +/// Tests - conversions. +/// +public class CieXyzAndCieLchuvConversionTests +{ + private static readonly ApproximateColorProfileComparer Comparer = new(.0002f); + + [Theory] + [InlineData(0.360555, 0.936901, 0.1001514, 97.50697, 177.345169, 142.601547)] + public void Convert_CieXyz_to_CieLchuv(float x, float y, float yl, float l, float c, float h) + { + // Arrange + CieXyz input = new(x, y, yl); + CieLchuv expected = new(l, c, h); + ColorProfileConverter converter = new(); + + Span inputSpan = new CieXyz[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLchuv[5]; + + // Act + CieLchuv actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(97.50697, 177.345169, 142.601547, 0.360555, 0.936901, 0.1001514)] + public void Convert_CieLchuv_to_CieXyz(float l, float c, float h, float x, float y, float yl) + { + // Arrange + CieLchuv input = new(l, c, h); + CieXyz expected = new(x, y, yl); + ColorProfileConverter converter = new(); + + Span inputSpan = new CieLchuv[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieXyz[5]; + + // Act + CieXyz actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } +} diff --git a/tests/ImageSharp.Tests/ColorProfiles/CieXyzAndCieLuvConversionTest.cs b/tests/ImageSharp.Tests/ColorProfiles/CieXyzAndCieLuvConversionTest.cs new file mode 100644 index 0000000000..944b990054 --- /dev/null +++ b/tests/ImageSharp.Tests/ColorProfiles/CieXyzAndCieLuvConversionTest.cs @@ -0,0 +1,87 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.ColorProfiles; + +namespace SixLabors.ImageSharp.Tests.ColorProfiles; + +/// +/// Tests - conversions. +/// +/// +/// Test data generated using: +/// +/// +public class CieXyzAndCieLuvConversionTest +{ + private static readonly ApproximateColorProfileComparer Comparer = new(.0002f); + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(0.000493, 0.000111, 0, 0.10026589, 0.9332349, -0.00704865158)] + [InlineData(0.569310, 0.407494, 0.365843, 70.0000, 86.3524, 2.8240)] + [InlineData(0.012191, 0.011260, 0.025939, 9.9998, -1.2343, -9.9999)] + [InlineData(0.950470, 1.000000, 1.088830, 100, 0, 0)] + [InlineData(0.001255, 0.001107, 0.000137, 0.9999, 0.9998, 1.0004)] + public void Convert_Xyz_To_Luv(float x, float y, float z, float l, float u, float v) + { + // Arrange + CieXyz input = new(x, y, z); + CieLuv expected = new(l, u, v); + + ColorConversionOptions options = new() { WhitePoint = KnownIlluminants.D65, TargetWhitePoint = KnownIlluminants.D65 }; + ColorProfileConverter converter = new(options); + + Span inputSpan = new CieXyz[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLuv[5]; + + // Act + CieLuv actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(0, 100, 50, 0, 0, 0)] + [InlineData(0.1, 100, 50, 0.000493, 0.000111, -0.000709)] + [InlineData(70.0000, 86.3525, 2.8240, 0.569310, 0.407494, 0.365843)] + [InlineData(10.0000, -1.2345, -10.0000, 0.012191, 0.011260, 0.025939)] + [InlineData(100, 0, 0, 0.950470, 1.000000, 1.088830)] + [InlineData(1, 1, 1, 0.001255, 0.001107, 0.000137)] + public void Convert_Luv_To_Xyz(float l, float u, float v, float x, float y, float z) + { + // Arrange + CieLuv input = new(l, u, v); + CieXyz expected = new(x, y, z); + + ColorConversionOptions options = new() { WhitePoint = KnownIlluminants.D65, TargetWhitePoint = KnownIlluminants.D65 }; + ColorProfileConverter converter = new(options); + + Span inputSpan = new CieLuv[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieXyz[5]; + + // Act + CieXyz actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } +} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieXyyConversionTest.cs b/tests/ImageSharp.Tests/ColorProfiles/CieXyzAndCieXyyConversionTest.cs similarity index 55% rename from tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieXyyConversionTest.cs rename to tests/ImageSharp.Tests/ColorProfiles/CieXyzAndCieXyyConversionTest.cs index 5ef5c4d21a..7b1d0ac781 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieXyyConversionTest.cs +++ b/tests/ImageSharp.Tests/ColorProfiles/CieXyzAndCieXyyConversionTest.cs @@ -1,10 +1,9 @@ -// Copyright (c) Six Labors. +// Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; +using SixLabors.ImageSharp.ColorProfiles; -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; +namespace SixLabors.ImageSharp.Tests.ColorProfiles; /// /// Tests - conversions. @@ -15,18 +14,18 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; /// public class CieXyzAndCieXyyConversionTest { - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0001F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); + private static readonly ApproximateColorProfileComparer Comparer = new(.0001F); [Theory] [InlineData(0.436075, 0.222504, 0.013932, 0.648427, 0.330856, 0.222504)] [InlineData(0.964220, 1.000000, 0.825210, 0.345669, 0.358496, 1.000000)] [InlineData(0.434119, 0.356820, 0.369447, 0.374116, 0.307501, 0.356820)] [InlineData(0, 0, 0, 0.538842, 0.000000, 0.000000)] - public void Convert_xyY_to_XYZ(float xyzX, float xyzY, float xyzZ, float x, float y, float yl) + public void Convert_Xyy_To_Xyz(float xyzX, float xyzY, float xyzZ, float x, float y, float yl) { - var input = new CieXyy(x, y, yl); - var expected = new CieXyz(xyzX, xyzY, xyzZ); + CieXyy input = new(x, y, yl); + CieXyz expected = new(xyzX, xyzY, xyzZ); + ColorProfileConverter converter = new(); Span inputSpan = new CieXyy[5]; inputSpan.Fill(input); @@ -34,15 +33,15 @@ public void Convert_xyY_to_XYZ(float xyzX, float xyzY, float xyzZ, float x, floa Span actualSpan = new CieXyz[5]; // Act - var actual = ColorSpaceConverter.ToCieXyz(input); - ColorSpaceConverter.Convert(inputSpan, actualSpan); + CieXyz actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); + Assert.Equal(expected, actual, Comparer); for (int i = 0; i < actualSpan.Length; i++) { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + Assert.Equal(expected, actualSpan[i], Comparer); } } @@ -51,10 +50,11 @@ public void Convert_xyY_to_XYZ(float xyzX, float xyzY, float xyzZ, float x, floa [InlineData(0.964220, 1.000000, 0.825210, 0.345669, 0.358496, 1.000000)] [InlineData(0.434119, 0.356820, 0.369447, 0.374116, 0.307501, 0.356820)] [InlineData(0.231809, 0, 0.077528, 0.749374, 0.000000, 0.000000)] - public void Convert_XYZ_to_xyY(float xyzX, float xyzY, float xyzZ, float x, float y, float yl) + public void Convert_Xyz_to_Xyy(float xyzX, float xyzY, float xyzZ, float x, float y, float yl) { - var input = new CieXyz(xyzX, xyzY, xyzZ); - var expected = new CieXyy(x, y, yl); + CieXyz input = new(xyzX, xyzY, xyzZ); + CieXyy expected = new(x, y, yl); + ColorProfileConverter converter = new(); Span inputSpan = new CieXyz[5]; inputSpan.Fill(input); @@ -62,15 +62,15 @@ public void Convert_XYZ_to_xyY(float xyzX, float xyzY, float xyzZ, float x, floa Span actualSpan = new CieXyy[5]; // Act - var actual = ColorSpaceConverter.ToCieXyy(input); - ColorSpaceConverter.Convert(inputSpan, actualSpan); + CieXyy actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); + Assert.Equal(expected, actual, Comparer); for (int i = 0; i < actualSpan.Length; i++) { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + Assert.Equal(expected, actualSpan[i], Comparer); } } } diff --git a/tests/ImageSharp.Tests/ColorProfiles/CieXyzAndHslConversionTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CieXyzAndHslConversionTests.cs new file mode 100644 index 0000000000..cffdb008b8 --- /dev/null +++ b/tests/ImageSharp.Tests/ColorProfiles/CieXyzAndHslConversionTests.cs @@ -0,0 +1,70 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.ColorProfiles; + +namespace SixLabors.ImageSharp.Tests.ColorProfiles; + +/// +/// Tests - conversions. +/// +public class CieXyzAndHslConversionTests +{ + private static readonly ApproximateColorProfileComparer Comparer = new(.0002F); + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(0.360555, 0.936901, 0.1001514, 120, 1, 0.5)] + public void Convert_CieXyz_to_Hsl(float x, float y, float yl, float h, float s, float l) + { + // Arrange + CieXyz input = new(x, y, yl); + Hsl expected = new(h, s, l); + ColorProfileConverter converter = new(); + + Span inputSpan = new CieXyz[5]; + inputSpan.Fill(input); + + Span actualSpan = new Hsl[5]; + + // Act + Hsl actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(120, 1, 0.5, 0.38506496, 0.716878653, 0.09710451)] + public void Convert_Hsl_to_CieXyz(float h, float s, float l, float x, float y, float yl) + { + // Arrange + Hsl input = new(h, s, l); + CieXyz expected = new(x, y, yl); + ColorProfileConverter converter = new(); + + Span inputSpan = new Hsl[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieXyz[5]; + + // Act + CieXyz actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } +} diff --git a/tests/ImageSharp.Tests/ColorProfiles/CieXyzAndHsvConversionTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CieXyzAndHsvConversionTests.cs new file mode 100644 index 0000000000..d4a0022a47 --- /dev/null +++ b/tests/ImageSharp.Tests/ColorProfiles/CieXyzAndHsvConversionTests.cs @@ -0,0 +1,70 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.ColorProfiles; + +namespace SixLabors.ImageSharp.Tests.ColorProfiles; + +/// +/// Tests - conversions. +/// +public class CieXyzAndHsvConversionTests +{ + private static readonly ApproximateColorProfileComparer Comparer = new(.0002F); + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(0.360555, 0.936901, 0.1001514, 120, 1, 0.9999999)] + public void Convert_CieXyz_to_Hsv(float x, float y, float yl, float h, float s, float v) + { + // Arrange + CieXyz input = new(x, y, yl); + Hsv expected = new(h, s, v); + ColorProfileConverter converter = new(); + + Span inputSpan = new CieXyz[5]; + inputSpan.Fill(input); + + Span actualSpan = new Hsv[5]; + + // Act + Hsv actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(120, 1, 0.9999999, 0.3850648, 0.7168785, 0.09710446)] + public void Convert_Hsv_to_CieXyz(float h, float s, float v, float x, float y, float yl) + { + // Arrange + Hsv input = new(h, s, v); + CieXyz expected = new(x, y, yl); + ColorProfileConverter converter = new(); + + Span inputSpan = new Hsv[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieXyz[5]; + + // Act + CieXyz actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } +} diff --git a/tests/ImageSharp.Tests/ColorProfiles/CieXyzAndHunterLabConversionTest.cs b/tests/ImageSharp.Tests/ColorProfiles/CieXyzAndHunterLabConversionTest.cs new file mode 100644 index 0000000000..aef26fe9a3 --- /dev/null +++ b/tests/ImageSharp.Tests/ColorProfiles/CieXyzAndHunterLabConversionTest.cs @@ -0,0 +1,74 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.ColorProfiles; + +namespace SixLabors.ImageSharp.Tests.ColorProfiles; + +/// +/// Tests - conversions. +/// +/// +/// Test data generated using: +/// +/// +public class CieXyzAndHunterLabConversionTest +{ + private static readonly ApproximateColorProfileComparer Comparer = new(.0002f); + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(0.360555, 0.936901, 0.1001514, 96.79365, -100.951096, 49.35507)] + public void Convert_Xyz_To_HunterLab(float x, float y, float z, float l, float a, float b) + { + // Arrange + CieXyz input = new(x, y, z); + HunterLab expected = new(l, a, b); + ColorProfileConverter converter = new(); + + Span inputSpan = new CieXyz[5]; + inputSpan.Fill(input); + + Span actualSpan = new HunterLab[5]; + + // Act + HunterLab actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(31.6467056, -33.00599, 25.67032, 0.0385420471, 0.10015139, -0.0317969956)] + public void Convert_HunterLab_To_Xyz(float l, float a, float b, float x, float y, float z) + { + // Arrange + HunterLab input = new(l, a, b); + CieXyz expected = new(x, y, z); + ColorProfileConverter converter = new(); + + Span inputSpan = new HunterLab[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieXyz[5]; + + // Act + CieXyz actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } +} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndLmsConversionTest.cs b/tests/ImageSharp.Tests/ColorProfiles/CieXyzAndLmsConversionTest.cs similarity index 53% rename from tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndLmsConversionTest.cs rename to tests/ImageSharp.Tests/ColorProfiles/CieXyzAndLmsConversionTest.cs index 33bdc6e935..185fcd256c 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndLmsConversionTest.cs +++ b/tests/ImageSharp.Tests/ColorProfiles/CieXyzAndLmsConversionTest.cs @@ -1,10 +1,9 @@ -// Copyright (c) Six Labors. +// Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; +using SixLabors.ImageSharp.ColorProfiles; -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; +namespace SixLabors.ImageSharp.Tests.ColorProfiles; /// /// Tests - conversions. @@ -14,11 +13,8 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; /// public class CieXyzAndLmsConversionTest { - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0001F); + private static readonly ApproximateColorProfileComparer Comparer = new(.0001f); - /// - /// Tests conversion from () to . - /// [Theory] [InlineData(0.941428535, 1.040417467, 1.089532651, 0.95047, 1, 1.08883)] [InlineData(0, 0, 0, 0, 0, 0)] @@ -26,12 +22,12 @@ public class CieXyzAndLmsConversionTest [InlineData(0.2664, 1.7135, -0.0685, 0, 1, 0)] [InlineData(-0.175737162, 0.039960061, 1.121059368, 0, 0, 1.08883)] [InlineData(0.2262677362, 0.0961411609, 0.0484570397, 0.216938, 0.150041, 0.048850)] - public void Convert_Lms_to_CieXyz(float l, float m, float s, float x, float y, float z) + public void Convert_Lms_To_CieXyz(float l, float m, float s, float x, float y, float z) { // Arrange - var input = new Lms(l, m, s); - var converter = new ColorSpaceConverter(); - var expected = new CieXyz(x, y, z); + Lms input = new(l, m, s); + ColorProfileConverter converter = new(); + CieXyz expected = new(x, y, z); Span inputSpan = new Lms[5]; inputSpan.Fill(input); @@ -39,21 +35,18 @@ public void Convert_Lms_to_CieXyz(float l, float m, float s, float x, float y, f Span actualSpan = new CieXyz[5]; // Act - var actual = converter.ToCieXyz(input); - converter.Convert(inputSpan, actualSpan); + CieXyz actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); + Assert.Equal(expected, actual, Comparer); for (int i = 0; i < actualSpan.Length; i++) { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + Assert.Equal(expected, actualSpan[i], Comparer); } } - /// - /// Tests conversion from () to . - /// [Theory] [InlineData(0.95047, 1, 1.08883, 0.941428535, 1.040417467, 1.089532651)] [InlineData(0, 0, 0, 0, 0, 0)] @@ -61,12 +54,12 @@ public void Convert_Lms_to_CieXyz(float l, float m, float s, float x, float y, f [InlineData(0, 1, 0, 0.2664, 1.7135, -0.0685)] [InlineData(0, 0, 1.08883, -0.175737162, 0.039960061, 1.121059368)] [InlineData(0.216938, 0.150041, 0.048850, 0.2262677362, 0.0961411609, 0.0484570397)] - public void Convert_CieXyz_to_Lms(float x, float y, float z, float l, float m, float s) + public void Convert_CieXyz_To_Lms(float x, float y, float z, float l, float m, float s) { // Arrange - var input = new CieXyz(x, y, z); - var converter = new ColorSpaceConverter(); - var expected = new Lms(l, m, s); + CieXyz input = new(x, y, z); + ColorProfileConverter converter = new(); + Lms expected = new(l, m, s); Span inputSpan = new CieXyz[5]; inputSpan.Fill(input); @@ -74,15 +67,15 @@ public void Convert_CieXyz_to_Lms(float x, float y, float z, float l, float m, f Span actualSpan = new Lms[5]; // Act - var actual = converter.ToLms(input); - converter.Convert(inputSpan, actualSpan); + Lms actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); + Assert.Equal(expected, actual, Comparer); for (int i = 0; i < actualSpan.Length; i++) { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + Assert.Equal(expected, actualSpan[i], Comparer); } } } diff --git a/tests/ImageSharp.Tests/ColorProfiles/CieXyzAndYCbCrConversionTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CieXyzAndYCbCrConversionTests.cs new file mode 100644 index 0000000000..475673da84 --- /dev/null +++ b/tests/ImageSharp.Tests/ColorProfiles/CieXyzAndYCbCrConversionTests.cs @@ -0,0 +1,70 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.ColorProfiles; + +namespace SixLabors.ImageSharp.Tests.ColorProfiles; + +/// +/// Tests - conversions. +/// +public class CieXyzAndYCbCrConversionTests +{ + private static readonly ApproximateColorProfileComparer Comparer = new(.0002f); + + [Theory] + [InlineData(0, 0, 0, 0, 128, 128)] + [InlineData(0.360555, 0.936901, 0.1001514, 149.685, 43.52769, 21.23457)] + public void Convert_CieXyz_to_YCbCr(float x, float y, float z, float y2, float cb, float cr) + { + // Arrange + CieXyz input = new(x, y, z); + YCbCr expected = new(y2, cb, cr); + ColorProfileConverter converter = new(); + + Span inputSpan = new CieXyz[5]; + inputSpan.Fill(input); + + Span actualSpan = new YCbCr[5]; + + // Act + YCbCr actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } + + [Theory] + [InlineData(0, 128, 128, 0, 0, 0)] + [InlineData(149.685, 43.52769, 21.23457, 0.38506496, 0.716878653, 0.0971045)] + public void Convert_YCbCr_to_CieXyz(float y2, float cb, float cr, float x, float y, float z) + { + // Arrange + YCbCr input = new(y2, cb, cr); + CieXyz expected = new(x, y, z); + ColorProfileConverter converter = new(); + + Span inputSpan = new YCbCr[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieXyz[5]; + + // Act + CieXyz actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } +} diff --git a/tests/ImageSharp.Tests/Colorspaces/CieXyzTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CieXyzTests.cs similarity index 65% rename from tests/ImageSharp.Tests/Colorspaces/CieXyzTests.cs rename to tests/ImageSharp.Tests/ColorProfiles/CieXyzTests.cs index 6de961cf1b..88138304a8 100644 --- a/tests/ImageSharp.Tests/Colorspaces/CieXyzTests.cs +++ b/tests/ImageSharp.Tests/ColorProfiles/CieXyzTests.cs @@ -1,10 +1,10 @@ -// Copyright (c) Six Labors. +// Copyright (c) Six Labors. // Licensed under the Six Labors Split License. using System.Numerics; -using SixLabors.ImageSharp.ColorSpaces; +using SixLabors.ImageSharp.ColorProfiles; -namespace SixLabors.ImageSharp.Tests.Colorspaces; +namespace SixLabors.ImageSharp.Tests.ColorProfiles; /// /// Tests the struct. @@ -17,7 +17,7 @@ public void CieXyzConstructorAssignsFields() const float x = 75F; const float y = 64F; const float z = 287F; - var cieXyz = new CieXyz(x, y, z); + CieXyz cieXyz = new(x, y, z); Assert.Equal(x, cieXyz.X); Assert.Equal(y, cieXyz.Y); @@ -27,12 +27,12 @@ public void CieXyzConstructorAssignsFields() [Fact] public void CieXyzEquality() { - var x = default(CieXyz); - var y = new CieXyz(Vector3.One); + CieXyz x = default; + CieXyz y = new(Vector3.One); - Assert.True(default(CieXyz) == default(CieXyz)); - Assert.False(default(CieXyz) != default(CieXyz)); - Assert.Equal(default(CieXyz), default(CieXyz)); + Assert.True(default == default(CieXyz)); + Assert.False(default != default(CieXyz)); + Assert.Equal(default, default(CieXyz)); Assert.Equal(new CieXyz(1, 0, 1), new CieXyz(1, 0, 1)); Assert.Equal(new CieXyz(Vector3.One), new CieXyz(Vector3.One)); Assert.False(x.Equals(y)); diff --git a/tests/ImageSharp.Tests/ColorProfiles/CmykAndCieLchConversionTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CmykAndCieLchConversionTests.cs new file mode 100644 index 0000000000..a5230eb312 --- /dev/null +++ b/tests/ImageSharp.Tests/ColorProfiles/CmykAndCieLchConversionTests.cs @@ -0,0 +1,69 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.ColorProfiles; + +namespace SixLabors.ImageSharp.Tests.ColorProfiles; + +/// +/// Tests - conversions. +/// +public class CmykAndCieLchConversionTests +{ + private static readonly ApproximateColorProfileComparer Comparer = new(.0002f); + + [Theory] + [InlineData(0.360555, 0.1036901, 0.818514, 0.274615, 62.85025, 64.77041, 118.2425)] + public void Convert_Cmyk_To_CieLch(float c, float m, float y, float k, float l, float c2, float h) + { + // Arrange + Cmyk input = new(c, m, y, k); + CieLch expected = new(l, c2, h); + ColorProfileConverter converter = new(); + + Span inputSpan = new Cmyk[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLch[5]; + + // Act + CieLch actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } + + [Theory] + [InlineData(100, 3.81656E-05, 218.6598, 0, 1.192093E-07, 0, 5.960464E-08)] + [InlineData(62.85025, 64.77041, 118.2425, 0.286581, 0, 0.7975187, 0.34983)] + public void Convert_CieLch_To_Cmyk(float l, float c2, float h, float c, float m, float y, float k) + { + // Arrange + CieLch input = new(l, c2, h); + Cmyk expected = new(c, m, y, k); + ColorProfileConverter converter = new(); + + Span inputSpan = new CieLch[5]; + inputSpan.Fill(input); + + Span actualSpan = new Cmyk[5]; + + // Act + Cmyk actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } +} diff --git a/tests/ImageSharp.Tests/ColorProfiles/CmykAndCieLuvConversionTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CmykAndCieLuvConversionTests.cs new file mode 100644 index 0000000000..cfbd080541 --- /dev/null +++ b/tests/ImageSharp.Tests/ColorProfiles/CmykAndCieLuvConversionTests.cs @@ -0,0 +1,70 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.ColorProfiles; + +namespace SixLabors.ImageSharp.Tests.ColorProfiles; + +/// +/// Tests - conversions. +/// +public class CmykAndCieLuvConversionTests +{ + private static readonly ApproximateColorProfileComparer Comparer = new(.0002f); + + [Theory] + [InlineData(0, 0, 0, 0, 100, -1.937151E-05, -3.874302E-05)] + [InlineData(0.360555, 0.1036901, 0.818514, 0.274615, 62.85024, -24.4844189, 54.8588524)] + public void Convert_Cmyk_To_CieLuv(float c, float m, float y, float k, float l, float u, float v) + { + // Arrange + Cmyk input = new(c, m, y, k); + CieLuv expected = new(l, u, v); + ColorProfileConverter converter = new(); + + Span inputSpan = new Cmyk[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLuv[5]; + + // Act + CieLuv actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } + + [Theory] + [InlineData(100, -1.937151E-05, -3.874302E-05, 0, 5.96046448E-08, 0, 0)] + [InlineData(62.85024, -24.4844189, 54.8588524, 0.2865809, 0, 0.797518551, 0.3498301)] + public void Convert_CieLuv_To_Cmyk(float l, float u, float v, float c, float m, float y, float k) + { + // Arrange + CieLuv input = new(l, u, v); + Cmyk expected = new(c, m, y, k); + ColorProfileConverter converter = new(); + + Span inputSpan = new CieLuv[5]; + inputSpan.Fill(input); + + Span actualSpan = new Cmyk[5]; + + // Act + Cmyk actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } +} diff --git a/tests/ImageSharp.Tests/ColorProfiles/CmykAndYCbCrConversionTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CmykAndYCbCrConversionTests.cs new file mode 100644 index 0000000000..64b47e2b97 --- /dev/null +++ b/tests/ImageSharp.Tests/ColorProfiles/CmykAndYCbCrConversionTests.cs @@ -0,0 +1,70 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.ColorProfiles; + +namespace SixLabors.ImageSharp.Tests.ColorProfiles; + +/// +/// Tests - conversions. +/// +public class CmykAndYCbCrConversionTests +{ + private static readonly ApproximateColorProfileComparer Comparer = new(.0002F); + + [Theory] + [InlineData(0, 0, 0, 0, 255, 128, 128)] + [InlineData(0.360555, 0.1036901, 0.818514, 0.274615, 136.5134, 69.90555, 114.9948)] + public void Convert_Cmyk_To_YCbCr(float c, float m, float y, float k, float y2, float cb, float cr) + { + // Arrange + Cmyk input = new(c, m, y, k); + YCbCr expected = new(y2, cb, cr); + ColorProfileConverter converter = new(); + + Span inputSpan = new Cmyk[5]; + inputSpan.Fill(input); + + Span actualSpan = new YCbCr[5]; + + // Act + YCbCr actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } + + [Theory] + [InlineData(255, 128, 128, 0, 0, 0, 5.960464E-08)] + [InlineData(136.5134, 69.90555, 114.9948, 0.2891567, 0, 0.7951807, 0.3490196)] + public void Convert_YCbCr_To_Cmyk(float y2, float cb, float cr, float c, float m, float y, float k) + { + // Arrange + YCbCr input = new(y2, cb, cr); + Cmyk expected = new(c, m, y, k); + ColorProfileConverter converter = new(); + + Span inputSpan = new YCbCr[5]; + inputSpan.Fill(input); + + Span actualSpan = new Cmyk[5]; + + // Act + Cmyk actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } +} diff --git a/tests/ImageSharp.Tests/Colorspaces/CmykTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CmykTests.cs similarity index 67% rename from tests/ImageSharp.Tests/Colorspaces/CmykTests.cs rename to tests/ImageSharp.Tests/ColorProfiles/CmykTests.cs index b4e55ed24c..e2044a75d0 100644 --- a/tests/ImageSharp.Tests/Colorspaces/CmykTests.cs +++ b/tests/ImageSharp.Tests/ColorProfiles/CmykTests.cs @@ -1,10 +1,10 @@ -// Copyright (c) Six Labors. +// Copyright (c) Six Labors. // Licensed under the Six Labors Split License. using System.Numerics; -using SixLabors.ImageSharp.ColorSpaces; +using SixLabors.ImageSharp.ColorProfiles; -namespace SixLabors.ImageSharp.Tests.Colorspaces; +namespace SixLabors.ImageSharp.Tests.ColorProfiles; /// /// Tests the struct. @@ -18,7 +18,7 @@ public void CmykConstructorAssignsFields() const float m = .64F; const float y = .87F; const float k = .334F; - var cmyk = new Cmyk(c, m, y, k); + Cmyk cmyk = new(c, m, y, k); Assert.Equal(c, cmyk.C); Assert.Equal(m, cmyk.M); @@ -29,12 +29,12 @@ public void CmykConstructorAssignsFields() [Fact] public void CmykEquality() { - var x = default(Cmyk); - var y = new Cmyk(Vector4.One); + Cmyk x = default; + Cmyk y = new(Vector4.One); - Assert.True(default(Cmyk) == default(Cmyk)); - Assert.False(default(Cmyk) != default(Cmyk)); - Assert.Equal(default(Cmyk), default(Cmyk)); + Assert.True(default == default(Cmyk)); + Assert.False(default != default(Cmyk)); + Assert.Equal(default, default(Cmyk)); Assert.Equal(new Cmyk(1, 0, 1, 0), new Cmyk(1, 0, 1, 0)); Assert.Equal(new Cmyk(Vector4.One), new Cmyk(Vector4.One)); Assert.False(x.Equals(y)); diff --git a/tests/ImageSharp.Tests/ColorProfiles/ColorProfileConverterChomaticAdaptationTests.cs b/tests/ImageSharp.Tests/ColorProfiles/ColorProfileConverterChomaticAdaptationTests.cs new file mode 100644 index 0000000000..a90e5b9e86 --- /dev/null +++ b/tests/ImageSharp.Tests/ColorProfiles/ColorProfileConverterChomaticAdaptationTests.cs @@ -0,0 +1,203 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.ColorProfiles; + +namespace SixLabors.ImageSharp.Tests.ColorProfiles; + +/// +/// Tests chromatic adaptation within the . +/// Test data generated using: +/// +/// +/// +public class ColorProfileConverterChomaticAdaptationTests +{ + private static readonly ApproximateColorProfileComparer Comparer = new(.0001F); + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(1, 1, 1, 1, 1, 1)] + [InlineData(0.206162, 0.260277, 0.746717, 0.220000, 0.130000, 0.780000)] + public void Adapt_RGB_WideGamutRGB_To_sRGB(float r1, float g1, float b1, float r2, float g2, float b2) + { + // Arrange + Rgb input = new(r1, g1, b1); + Rgb expected = new(r2, g2, b2); + ColorConversionOptions options = new() + { + RgbWorkingSpace = KnownRgbWorkingSpaces.WideGamutRgb, + TargetRgbWorkingSpace = KnownRgbWorkingSpaces.SRgb + }; + ColorProfileConverter converter = new(options); + + // Action + Rgb actual = converter.Convert(input); + + // Assert + Assert.Equal(expected, actual, Comparer); + } + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(1, 1, 1, 1, 1, 1)] + [InlineData(0.220000, 0.130000, 0.780000, 0.206162, 0.260277, 0.746717)] + public void Adapt_RGB_SRGB_To_WideGamutRGB(float r1, float g1, float b1, float r2, float g2, float b2) + { + // Arrange + Rgb input = new(r1, g1, b1); + Rgb expected = new(r2, g2, b2); + ColorConversionOptions options = new() + { + RgbWorkingSpace = KnownRgbWorkingSpaces.SRgb, + TargetRgbWorkingSpace = KnownRgbWorkingSpaces.WideGamutRgb + }; + ColorProfileConverter converter = new(options); + + // Action + Rgb actual = converter.Convert(input); + + // Assert + Assert.Equal(expected, actual, Comparer); + } + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(22, 33, 1, 22.269869, 32.841164, 1.633926)] + public void Adapt_Lab_D65_To_D50(float l1, float a1, float b1, float l2, float a2, float b2) + { + // Arrange + CieLab input = new(l1, a1, b1); + CieLab expected = new(l2, a2, b2); + ColorConversionOptions options = new() + { + WhitePoint = KnownIlluminants.D65, + TargetWhitePoint = KnownIlluminants.D50 + }; + ColorProfileConverter converter = new(options); + + // Action + CieLab actual = converter.Convert(input); + + // Assert + Assert.Equal(expected, actual, Comparer); + } + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(0.5, 0.5, 0.5, 0.510286, 0.501489, 0.378970)] + public void Adapt_Xyz_D65_To_D50_Bradford(float x1, float y1, float z1, float x2, float y2, float z2) + { + // Arrange + CieXyz input = new(x1, y1, z1); + CieXyz expected = new(x2, y2, z2); + ColorConversionOptions options = new() + { + WhitePoint = KnownIlluminants.D65, + TargetWhitePoint = KnownIlluminants.D50, + AdaptationMatrix = KnownChromaticAdaptationMatrices.Bradford + }; + + ColorProfileConverter converter = new(options); + + // Action + CieXyz actual = converter.Convert(input); + + // Assert + Assert.Equal(expected, actual, Comparer); + } + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(0.5, 0.5, 0.5, 0.507233, 0.500000, 0.378943)] + public void Adapt_Xyz_D65_To_D50_XyzScaling(float x1, float y1, float z1, float x2, float y2, float z2) + { + // Arrange + CieXyz input = new(x1, y1, z1); + CieXyz expected = new(x2, y2, z2); + ColorConversionOptions options = new() + { + WhitePoint = KnownIlluminants.D65, + TargetWhitePoint = KnownIlluminants.D50, + AdaptationMatrix = KnownChromaticAdaptationMatrices.XyzScaling + }; + + ColorProfileConverter converter = new(options); + + // Action + CieXyz actual = converter.Convert(input); + + // Assert + Assert.Equal(expected, actual, Comparer); + } + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(22, 33, 1, 22.28086, 33.0681534, 1.30099022)] + public void Adapt_HunterLab_D65_To_D50(float l1, float a1, float b1, float l2, float a2, float b2) + { + // Arrange + HunterLab input = new(l1, a1, b1); + HunterLab expected = new(l2, a2, b2); + ColorConversionOptions options = new() + { + WhitePoint = KnownIlluminants.D65, + TargetWhitePoint = KnownIlluminants.D50, + }; + + ColorProfileConverter converter = new(options); + + // Action + HunterLab actual = converter.Convert(input); + + // Assert + Assert.Equal(expected, actual, Comparer); + } + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(22, 33, 1, 22, 34.0843468, 359.009)] + public void Adapt_CieLchuv_D65_To_D50_XyzScaling(float l1, float c1, float h1, float l2, float c2, float h2) + { + // Arrange + CieLchuv input = new(l1, c1, h1); + CieLchuv expected = new(l2, c2, h2); + ColorConversionOptions options = new() + { + WhitePoint = KnownIlluminants.D65, + TargetWhitePoint = KnownIlluminants.D50, + AdaptationMatrix = KnownChromaticAdaptationMatrices.XyzScaling + }; + + ColorProfileConverter converter = new(options); + + // Action + CieLchuv actual = converter.Convert(input); + + // Assert + Assert.Equal(expected, actual, Comparer); + } + + [Theory] + [InlineData(22, 33, 1, 22, 33, 0.9999999)] + public void Adapt_CieLch_D65_To_D50_XyzScaling(float l1, float c1, float h1, float l2, float c2, float h2) + { + // Arrange + CieLch input = new(l1, c1, h1); + CieLch expected = new(l2, c2, h2); + ColorConversionOptions options = new() + { + WhitePoint = KnownIlluminants.D65, + TargetWhitePoint = KnownIlluminants.D50, + AdaptationMatrix = KnownChromaticAdaptationMatrices.XyzScaling + }; + + ColorProfileConverter converter = new(options); + + // Action + CieLch actual = converter.Convert(input); + + // Assert + Assert.Equal(expected, actual, Comparer); + } +} diff --git a/tests/ImageSharp.Tests/ColorProfiles/CompandingTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CompandingTests.cs new file mode 100644 index 0000000000..1bdefa1095 --- /dev/null +++ b/tests/ImageSharp.Tests/ColorProfiles/CompandingTests.cs @@ -0,0 +1,108 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Numerics; +using SixLabors.ImageSharp.ColorProfiles.Companding; + +namespace SixLabors.ImageSharp.Tests.ColorProfiles; + +/// +/// Tests various companding algorithms. Expanded numbers are hand calculated from formulas online. +/// +public class CompandingTests +{ + private static readonly ApproximateFloatComparer Comparer = new(.000001F); + + [Fact] + public void Rec2020Companding_IsCorrect() + { + Vector4 input = new(.667F); + Vector4 e = Rec2020Companding.Expand(input); + Vector4 c = Rec2020Companding.Compress(e); + CompandingIsCorrectImpl(e, c, .44847462F, input); + } + + [Fact] + public void Rec709Companding_IsCorrect() + { + Vector4 input = new(.667F); + Vector4 e = Rec709Companding.Expand(input); + Vector4 c = Rec709Companding.Compress(e); + CompandingIsCorrectImpl(e, c, .4483577F, input); + } + + [Fact] + public void SRgbCompanding_IsCorrect() + { + Vector4 input = new(.667F); + Vector4 e = SRgbCompanding.Expand(input); + Vector4 c = SRgbCompanding.Compress(e); + CompandingIsCorrectImpl(e, c, .40242353F, input); + } + + [Theory] + [InlineData(0)] + [InlineData(1)] + [InlineData(30)] + public void SRgbCompanding_Expand_VectorSpan(int length) + { + Random rnd = new(42); + Vector4[] source = rnd.GenerateRandomVectorArray(length, 0, 1); + Vector4[] expected = new Vector4[source.Length]; + + for (int i = 0; i < source.Length; i++) + { + expected[i] = SRgbCompanding.Expand(source[i]); + } + + SRgbCompanding.Expand(source); + + Assert.Equal(expected, source, Comparer); + } + + [Theory] + [InlineData(0)] + [InlineData(1)] + [InlineData(30)] + public void SRgbCompanding_Compress_VectorSpan(int length) + { + Random rnd = new(42); + Vector4[] source = rnd.GenerateRandomVectorArray(length, 0, 1); + Vector4[] expected = new Vector4[source.Length]; + + for (int i = 0; i < source.Length; i++) + { + expected[i] = SRgbCompanding.Compress(source[i]); + } + + SRgbCompanding.Compress(source); + + Assert.Equal(expected, source, Comparer); + } + + [Fact] + public void GammaCompanding_IsCorrect() + { + const double gamma = 2.2; + Vector4 input = new(.667F); + Vector4 e = GammaCompanding.Expand(input, gamma); + Vector4 c = GammaCompanding.Compress(e, gamma); + CompandingIsCorrectImpl(e, c, .41027668F, input); + } + + [Fact] + public void LCompanding_IsCorrect() + { + Vector4 input = new(.667F); + Vector4 e = LCompanding.Expand(input); + Vector4 c = LCompanding.Compress(e); + CompandingIsCorrectImpl(e, c, .36236193F, input); + } + + private static void CompandingIsCorrectImpl(Vector4 e, Vector4 c, float expanded, Vector4 compressed) + { + // W (alpha) is already the linear representation of the color. + Assert.Equal(new Vector4(expanded, expanded, expanded, e.W), e, Comparer); + Assert.Equal(compressed, c, Comparer); + } +} diff --git a/tests/ImageSharp.Tests/Colorspaces/HslTests.cs b/tests/ImageSharp.Tests/ColorProfiles/HslTests.cs similarity index 66% rename from tests/ImageSharp.Tests/Colorspaces/HslTests.cs rename to tests/ImageSharp.Tests/ColorProfiles/HslTests.cs index a8702488a6..d18e65117e 100644 --- a/tests/ImageSharp.Tests/Colorspaces/HslTests.cs +++ b/tests/ImageSharp.Tests/ColorProfiles/HslTests.cs @@ -1,10 +1,10 @@ -// Copyright (c) Six Labors. +// Copyright (c) Six Labors. // Licensed under the Six Labors Split License. using System.Numerics; -using SixLabors.ImageSharp.ColorSpaces; +using SixLabors.ImageSharp.ColorProfiles; -namespace SixLabors.ImageSharp.Tests.Colorspaces; +namespace SixLabors.ImageSharp.Tests.ColorProfiles; /// /// Tests the struct. @@ -17,7 +17,7 @@ public void HslConstructorAssignsFields() const float h = 275F; const float s = .64F; const float l = .87F; - var hsl = new Hsl(h, s, l); + Hsl hsl = new(h, s, l); Assert.Equal(h, hsl.H); Assert.Equal(s, hsl.S); @@ -27,12 +27,12 @@ public void HslConstructorAssignsFields() [Fact] public void HslEquality() { - var x = default(Hsl); - var y = new Hsl(Vector3.One); + Hsl x = default; + Hsl y = new(Vector3.One); - Assert.True(default(Hsl) == default(Hsl)); - Assert.False(default(Hsl) != default(Hsl)); - Assert.Equal(default(Hsl), default(Hsl)); + Assert.True(default == default(Hsl)); + Assert.False(default != default(Hsl)); + Assert.Equal(default, default(Hsl)); Assert.Equal(new Hsl(1, 0, 1), new Hsl(1, 0, 1)); Assert.Equal(new Hsl(Vector3.One), new Hsl(Vector3.One)); Assert.False(x.Equals(y)); diff --git a/tests/ImageSharp.Tests/Colorspaces/HsvTests.cs b/tests/ImageSharp.Tests/ColorProfiles/HsvTests.cs similarity index 66% rename from tests/ImageSharp.Tests/Colorspaces/HsvTests.cs rename to tests/ImageSharp.Tests/ColorProfiles/HsvTests.cs index caedd3f171..46f58b18e2 100644 --- a/tests/ImageSharp.Tests/Colorspaces/HsvTests.cs +++ b/tests/ImageSharp.Tests/ColorProfiles/HsvTests.cs @@ -1,10 +1,10 @@ -// Copyright (c) Six Labors. +// Copyright (c) Six Labors. // Licensed under the Six Labors Split License. using System.Numerics; -using SixLabors.ImageSharp.ColorSpaces; +using SixLabors.ImageSharp.ColorProfiles; -namespace SixLabors.ImageSharp.Tests.Colorspaces; +namespace SixLabors.ImageSharp.Tests.ColorProfiles; /// /// Tests the struct. @@ -17,7 +17,7 @@ public void HsvConstructorAssignsFields() const float h = 275F; const float s = .64F; const float v = .87F; - var hsv = new Hsv(h, s, v); + Hsv hsv = new(h, s, v); Assert.Equal(h, hsv.H); Assert.Equal(s, hsv.S); @@ -27,12 +27,12 @@ public void HsvConstructorAssignsFields() [Fact] public void HsvEquality() { - var x = default(Hsv); - var y = new Hsv(Vector3.One); + Hsv x = default; + Hsv y = new(Vector3.One); - Assert.True(default(Hsv) == default(Hsv)); - Assert.False(default(Hsv) != default(Hsv)); - Assert.Equal(default(Hsv), default(Hsv)); + Assert.True(default == default(Hsv)); + Assert.False(default != default(Hsv)); + Assert.Equal(default, default(Hsv)); Assert.Equal(new Hsv(1, 0, 1), new Hsv(1, 0, 1)); Assert.Equal(new Hsv(Vector3.One), new Hsv(Vector3.One)); Assert.False(x.Equals(y)); diff --git a/tests/ImageSharp.Tests/Colorspaces/HunterLabTests.cs b/tests/ImageSharp.Tests/ColorProfiles/HunterLabTests.cs similarity index 63% rename from tests/ImageSharp.Tests/Colorspaces/HunterLabTests.cs rename to tests/ImageSharp.Tests/ColorProfiles/HunterLabTests.cs index 9c97c4c91b..5fbdd0788f 100644 --- a/tests/ImageSharp.Tests/Colorspaces/HunterLabTests.cs +++ b/tests/ImageSharp.Tests/ColorProfiles/HunterLabTests.cs @@ -2,9 +2,9 @@ // Licensed under the Six Labors Split License. using System.Numerics; -using SixLabors.ImageSharp.ColorSpaces; +using SixLabors.ImageSharp.ColorProfiles; -namespace SixLabors.ImageSharp.Tests.Colorspaces; +namespace SixLabors.ImageSharp.Tests.ColorProfiles; /// /// Tests the struct. @@ -17,7 +17,7 @@ public void HunterLabConstructorAssignsFields() const float l = 75F; const float a = -64F; const float b = 87F; - var hunterLab = new HunterLab(l, a, b); + HunterLab hunterLab = new(l, a, b); Assert.Equal(l, hunterLab.L); Assert.Equal(a, hunterLab.A); @@ -27,13 +27,13 @@ public void HunterLabConstructorAssignsFields() [Fact] public void HunterLabEquality() { - var x = default(HunterLab); - var y = new HunterLab(Vector3.One); + HunterLab x = default; + HunterLab y = new(Vector3.One); - Assert.True(default(HunterLab) == default(HunterLab)); - Assert.True(new HunterLab(1, 0, 1) != default(HunterLab)); - Assert.False(new HunterLab(1, 0, 1) == default(HunterLab)); - Assert.Equal(default(HunterLab), default(HunterLab)); + Assert.True(default == default(HunterLab)); + Assert.True(new HunterLab(1, 0, 1) != default); + Assert.False(new HunterLab(1, 0, 1) == default); + Assert.Equal(default, default(HunterLab)); Assert.Equal(new HunterLab(1, 0, 1), new HunterLab(1, 0, 1)); Assert.Equal(new HunterLab(Vector3.One), new HunterLab(Vector3.One)); Assert.False(x.Equals(y)); diff --git a/tests/ImageSharp.Tests/Colorspaces/LmsTests.cs b/tests/ImageSharp.Tests/ColorProfiles/LmsTests.cs similarity index 65% rename from tests/ImageSharp.Tests/Colorspaces/LmsTests.cs rename to tests/ImageSharp.Tests/ColorProfiles/LmsTests.cs index 5e8840664e..138fd544da 100644 --- a/tests/ImageSharp.Tests/Colorspaces/LmsTests.cs +++ b/tests/ImageSharp.Tests/ColorProfiles/LmsTests.cs @@ -2,9 +2,9 @@ // Licensed under the Six Labors Split License. using System.Numerics; -using SixLabors.ImageSharp.ColorSpaces; +using SixLabors.ImageSharp.ColorProfiles; -namespace SixLabors.ImageSharp.Tests.Colorspaces; +namespace SixLabors.ImageSharp.Tests.ColorProfiles; /// /// Tests the struct. @@ -17,7 +17,7 @@ public void LmsConstructorAssignsFields() const float l = 75F; const float m = -64F; const float s = 87F; - var lms = new Lms(l, m, s); + Lms lms = new(l, m, s); Assert.Equal(l, lms.L); Assert.Equal(m, lms.M); @@ -27,13 +27,13 @@ public void LmsConstructorAssignsFields() [Fact] public void LmsEquality() { - var x = default(Lms); - var y = new Lms(Vector3.One); + Lms x = default; + Lms y = new(Vector3.One); - Assert.True(default(Lms) == default(Lms)); - Assert.True(new Lms(1, 0, 1) != default(Lms)); - Assert.False(new Lms(1, 0, 1) == default(Lms)); - Assert.Equal(default(Lms), default(Lms)); + Assert.True(default == default(Lms)); + Assert.True(new Lms(1, 0, 1) != default); + Assert.False(new Lms(1, 0, 1) == default); + Assert.Equal(default, default(Lms)); Assert.Equal(new Lms(1, 0, 1), new Lms(1, 0, 1)); Assert.Equal(new Lms(Vector3.One), new Lms(Vector3.One)); Assert.False(x.Equals(y)); diff --git a/tests/ImageSharp.Tests/ColorProfiles/RgbAndCieXyzConversionTest.cs b/tests/ImageSharp.Tests/ColorProfiles/RgbAndCieXyzConversionTest.cs new file mode 100644 index 0000000000..c10aa2c3c5 --- /dev/null +++ b/tests/ImageSharp.Tests/ColorProfiles/RgbAndCieXyzConversionTest.cs @@ -0,0 +1,150 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.ColorProfiles; + +namespace SixLabors.ImageSharp.Tests.ColorProfiles; + +/// +/// Tests - conversions. +/// +/// +/// Test data generated using: +/// +/// +public class RgbAndCieXyzConversionTest +{ + private static readonly ApproximateColorProfileComparer Comparer = new(.0001F); + + [Theory] + [InlineData(0.96422, 1.00000, 0.82521, 1, 1, 1)] + [InlineData(0.00000, 1.00000, 0.00000, 0, 1, 0)] + [InlineData(0.96422, 0.00000, 0.00000, 1, 0, 0.292064)] + [InlineData(0.00000, 0.00000, 0.82521, 0, 0.181415, 1)] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(0.297676, 0.267854, 0.045504, 0.720315, 0.509999, 0.168112)] + public void Convert_XYZ_D50_To_SRGB(float x, float y, float z, float r, float g, float b) + { + // Arrange + CieXyz input = new(x, y, z); + ColorConversionOptions options = new() { WhitePoint = KnownIlluminants.D50, TargetRgbWorkingSpace = KnownRgbWorkingSpaces.SRgb }; + ColorProfileConverter converter = new(options); + Rgb expected = new(r, g, b); + + Span inputSpan = new CieXyz[5]; + inputSpan.Fill(input); + + Span actualSpan = new Rgb[5]; + + // Act + Rgb actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } + + [Theory] + [InlineData(0.950470, 1.000000, 1.088830, 1, 1, 1)] + [InlineData(0, 1.000000, 0, 0, 1, 0)] + [InlineData(0.950470, 0, 0, 1, 0, 0.254967)] + [InlineData(0, 0, 1.088830, 0, 0.235458, 1)] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(0.297676, 0.267854, 0.045504, 0.754903, 0.501961, 0.099998)] + public void Convert_XYZ_D65_To_SRGB(float x, float y, float z, float r, float g, float b) + { + // Arrange + CieXyz input = new(x, y, z); + ColorConversionOptions options = new() { WhitePoint = KnownIlluminants.D65, TargetRgbWorkingSpace = KnownRgbWorkingSpaces.SRgb }; + ColorProfileConverter converter = new(options); + Rgb expected = new(r, g, b); + + Span inputSpan = new CieXyz[5]; + inputSpan.Fill(input); + + Span actualSpan = new Rgb[5]; + + // Act + Rgb actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } + + [Theory] + [InlineData(1, 1, 1, 0.964220, 1.000000, 0.825210)] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(1, 0, 0, 0.436075, 0.222504, 0.013932)] + [InlineData(0, 1, 0, 0.385065, 0.716879, 0.0971045)] + [InlineData(0, 0, 1, 0.143080, 0.060617, 0.714173)] + [InlineData(0.754902, 0.501961, 0.100000, 0.315757, 0.273323, 0.035506)] + public void Convert_SRGB_To_XYZ_D50(float r, float g, float b, float x, float y, float z) + { + // Arrange + Rgb input = new(r, g, b); + ColorConversionOptions options = new() { TargetWhitePoint = KnownIlluminants.D50, RgbWorkingSpace = KnownRgbWorkingSpaces.SRgb }; + ColorProfileConverter converter = new(options); + CieXyz expected = new(x, y, z); + + Span inputSpan = new Rgb[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieXyz[5]; + + // Act + CieXyz actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } + + [Theory] + [InlineData(1, 1, 1, 0.950470, 1.000000, 1.088830)] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(1, 0, 0, 0.412456, 0.212673, 0.019334)] + [InlineData(0, 1, 0, 0.357576, 0.715152, 0.119192)] + [InlineData(0, 0, 1, 0.1804375, 0.072175, 0.950304)] + [InlineData(0.754902, 0.501961, 0.100000, 0.297676, 0.267854, 0.045504)] + public void Convert_SRGB_To_XYZ_D65(float r, float g, float b, float x, float y, float z) + { + // Arrange + Rgb input = new(r, g, b); + ColorConversionOptions options = new() { TargetWhitePoint = KnownIlluminants.D65, RgbWorkingSpace = KnownRgbWorkingSpaces.SRgb }; + ColorProfileConverter converter = new(options); + CieXyz expected = new(x, y, z); + + Span inputSpan = new Rgb[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieXyz[5]; + + // Act + CieXyz actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } +} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndCmykConversionTest.cs b/tests/ImageSharp.Tests/ColorProfiles/RgbAndCmykConversionTest.cs similarity index 50% rename from tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndCmykConversionTest.cs rename to tests/ImageSharp.Tests/ColorProfiles/RgbAndCmykConversionTest.cs index 942b34db33..4f4ecb70be 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndCmykConversionTest.cs +++ b/tests/ImageSharp.Tests/ColorProfiles/RgbAndCmykConversionTest.cs @@ -1,10 +1,9 @@ -// Copyright (c) Six Labors. +// Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; +using SixLabors.ImageSharp.ColorProfiles; -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; +namespace SixLabors.ImageSharp.Tests.ColorProfiles; /// /// Tests - conversions. @@ -16,12 +15,8 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; /// public class RgbAndCmykConversionTest { - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0001F); + private static readonly ApproximateColorProfileComparer Comparer = new(.0001F); - /// - /// Tests conversion from to . - /// [Theory] [InlineData(1, 1, 1, 1, 0, 0, 0)] [InlineData(0, 0, 0, 0, 1, 1, 1)] @@ -29,8 +24,9 @@ public class RgbAndCmykConversionTest public void Convert_Cmyk_To_Rgb(float c, float m, float y, float k, float r, float g, float b) { // Arrange - var input = new Cmyk(c, m, y, k); - var expected = new Rgb(r, g, b); + Cmyk input = new(c, m, y, k); + Rgb expected = new(r, g, b); + ColorProfileConverter converter = new(); Span inputSpan = new Cmyk[5]; inputSpan.Fill(input); @@ -38,22 +34,18 @@ public void Convert_Cmyk_To_Rgb(float c, float m, float y, float k, float r, flo Span actualSpan = new Rgb[5]; // Act - var actual = ColorSpaceConverter.ToRgb(input); - ColorSpaceConverter.Convert(inputSpan, actualSpan); + Rgb actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); // Assert - Assert.Equal(Rgb.DefaultWorkingSpace, actual.WorkingSpace, ColorSpaceComparer); - Assert.Equal(expected, actual, ColorSpaceComparer); + Assert.Equal(expected, actual, Comparer); for (int i = 0; i < actualSpan.Length; i++) { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + Assert.Equal(expected, actualSpan[i], Comparer); } } - /// - /// Tests conversion from to . - /// [Theory] [InlineData(1, 1, 1, 0, 0, 0, 0)] [InlineData(0, 0, 0, 0, 0, 0, 1)] @@ -61,8 +53,9 @@ public void Convert_Cmyk_To_Rgb(float c, float m, float y, float k, float r, flo public void Convert_Rgb_To_Cmyk(float r, float g, float b, float c, float m, float y, float k) { // Arrange - var input = new Rgb(r, g, b); - var expected = new Cmyk(c, m, y, k); + Rgb input = new(r, g, b); + Cmyk expected = new(c, m, y, k); + ColorProfileConverter converter = new(); Span inputSpan = new Rgb[5]; inputSpan.Fill(input); @@ -70,15 +63,15 @@ public void Convert_Rgb_To_Cmyk(float r, float g, float b, float c, float m, flo Span actualSpan = new Cmyk[5]; // Act - var actual = ColorSpaceConverter.ToCmyk(input); - ColorSpaceConverter.Convert(inputSpan, actualSpan); + Cmyk actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); + Assert.Equal(expected, actual, Comparer); for (int i = 0; i < actualSpan.Length; i++) { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + Assert.Equal(expected, actualSpan[i], Comparer); } } } diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndHslConversionTest.cs b/tests/ImageSharp.Tests/ColorProfiles/RgbAndHslConversionTest.cs similarity index 54% rename from tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndHslConversionTest.cs rename to tests/ImageSharp.Tests/ColorProfiles/RgbAndHslConversionTest.cs index 8b448a0426..0dc95628b9 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndHslConversionTest.cs +++ b/tests/ImageSharp.Tests/ColorProfiles/RgbAndHslConversionTest.cs @@ -1,10 +1,9 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; +using SixLabors.ImageSharp.ColorProfiles; -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; +namespace SixLabors.ImageSharp.Tests.ColorProfiles; /// /// Tests - conversions. @@ -16,12 +15,8 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; /// public class RgbAndHslConversionTest { - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0001F); + private static readonly ApproximateColorProfileComparer Comparer = new(.0001f); - /// - /// Tests conversion from to . - /// [Theory] [InlineData(0, 0, 0, 0, 0, 0)] [InlineData(0, 1, 1, 1, 1, 1)] @@ -32,8 +27,9 @@ public class RgbAndHslConversionTest public void Convert_Hsl_To_Rgb(float h, float s, float l, float r, float g, float b) { // Arrange - var input = new Hsl(h, s, l); - var expected = new Rgb(r, g, b); + Hsl input = new(h, s, l); + Rgb expected = new(r, g, b); + ColorProfileConverter converter = new(); Span inputSpan = new Hsl[5]; inputSpan.Fill(input); @@ -41,22 +37,18 @@ public void Convert_Hsl_To_Rgb(float h, float s, float l, float r, float g, floa Span actualSpan = new Rgb[5]; // Act - var actual = ColorSpaceConverter.ToRgb(input); - ColorSpaceConverter.Convert(inputSpan, actualSpan); + Rgb actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); // Assert - Assert.Equal(Rgb.DefaultWorkingSpace, actual.WorkingSpace, ColorSpaceComparer); - Assert.Equal(expected, actual, ColorSpaceComparer); + Assert.Equal(expected, actual, Comparer); for (int i = 0; i < actualSpan.Length; i++) { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + Assert.Equal(expected, actualSpan[i], Comparer); } } - /// - /// Tests conversion from to . - /// [Theory] [InlineData(0, 0, 0, 0, 0, 0)] [InlineData(1, 1, 1, 0, 0, 1)] @@ -67,8 +59,9 @@ public void Convert_Hsl_To_Rgb(float h, float s, float l, float r, float g, floa public void Convert_Rgb_To_Hsl(float r, float g, float b, float h, float s, float l) { // Arrange - var input = new Rgb(r, g, b); - var expected = new Hsl(h, s, l); + Rgb input = new(r, g, b); + Hsl expected = new(h, s, l); + ColorProfileConverter converter = new(); Span inputSpan = new Rgb[5]; inputSpan.Fill(input); @@ -76,15 +69,15 @@ public void Convert_Rgb_To_Hsl(float r, float g, float b, float h, float s, floa Span actualSpan = new Hsl[5]; // Act - var actual = ColorSpaceConverter.ToHsl(input); - ColorSpaceConverter.Convert(inputSpan, actualSpan); + Hsl actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); + Assert.Equal(expected, actual, Comparer); for (int i = 0; i < actualSpan.Length; i++) { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + Assert.Equal(expected, actualSpan[i], Comparer); } } } diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndHsvConversionTest.cs b/tests/ImageSharp.Tests/ColorProfiles/RgbAndHsvConversionTest.cs similarity index 50% rename from tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndHsvConversionTest.cs rename to tests/ImageSharp.Tests/ColorProfiles/RgbAndHsvConversionTest.cs index d80aa6c329..b89b576b6c 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndHsvConversionTest.cs +++ b/tests/ImageSharp.Tests/ColorProfiles/RgbAndHsvConversionTest.cs @@ -1,10 +1,9 @@ -// Copyright (c) Six Labors. +// Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; +using SixLabors.ImageSharp.ColorProfiles; -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; +namespace SixLabors.ImageSharp.Tests.ColorProfiles; /// /// Tests - conversions. @@ -15,12 +14,8 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; /// public class RgbAndHsvConversionTest { - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0001F); + private static readonly ApproximateColorProfileComparer Comparer = new(.0001f); - /// - /// Tests conversion from to . - /// [Theory] [InlineData(0, 0, 0, 0, 0, 0)] [InlineData(0, 0, 1, 1, 1, 1)] @@ -31,8 +26,9 @@ public class RgbAndHsvConversionTest public void Convert_Hsv_To_Rgb(float h, float s, float v, float r, float g, float b) { // Arrange - var input = new Hsv(h, s, v); - var expected = new Rgb(r, g, b); + Hsv input = new(h, s, v); + Rgb expected = new(r, g, b); + ColorProfileConverter converter = new(); Span inputSpan = new Hsv[5]; inputSpan.Fill(input); @@ -40,22 +36,18 @@ public void Convert_Hsv_To_Rgb(float h, float s, float v, float r, float g, floa Span actualSpan = new Rgb[5]; // Act - var actual = ColorSpaceConverter.ToRgb(input); - ColorSpaceConverter.Convert(inputSpan, actualSpan); + Rgb actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); // Assert - Assert.Equal(Rgb.DefaultWorkingSpace, actual.WorkingSpace, ColorSpaceComparer); - Assert.Equal(expected, actual, ColorSpaceComparer); + Assert.Equal(expected, actual, Comparer); for (int i = 0; i < actualSpan.Length; i++) { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + Assert.Equal(expected, actualSpan[i], Comparer); } } - /// - /// Tests conversion from to . - /// [Theory] [InlineData(0, 0, 0, 0, 0, 0)] [InlineData(1, 1, 1, 0, 0, 1)] @@ -65,8 +57,9 @@ public void Convert_Hsv_To_Rgb(float h, float s, float v, float r, float g, floa public void Convert_Rgb_To_Hsv(float r, float g, float b, float h, float s, float v) { // Arrange - var input = new Rgb(r, g, b); - var expected = new Hsv(h, s, v); + Rgb input = new(r, g, b); + Hsv expected = new(h, s, v); + ColorProfileConverter converter = new(); Span inputSpan = new Rgb[5]; inputSpan.Fill(input); @@ -74,15 +67,15 @@ public void Convert_Rgb_To_Hsv(float r, float g, float b, float h, float s, floa Span actualSpan = new Hsv[5]; // Act - var actual = ColorSpaceConverter.ToHsv(input); - ColorSpaceConverter.Convert(inputSpan, actualSpan); + Hsv actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); + Assert.Equal(expected, actual, Comparer); for (int i = 0; i < actualSpan.Length; i++) { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + Assert.Equal(expected, actualSpan[i], Comparer); } } } diff --git a/tests/ImageSharp.Tests/ColorProfiles/RgbAndYCbCrConversionTest.cs b/tests/ImageSharp.Tests/ColorProfiles/RgbAndYCbCrConversionTest.cs new file mode 100644 index 0000000000..91f7fc08ee --- /dev/null +++ b/tests/ImageSharp.Tests/ColorProfiles/RgbAndYCbCrConversionTest.cs @@ -0,0 +1,76 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.ColorProfiles; + +namespace SixLabors.ImageSharp.Tests.ColorProfiles; + +/// +/// Tests - conversions. +/// +/// +/// Test data generated mathematically +/// +public class RgbAndYCbCrConversionTest +{ + private static readonly ApproximateColorProfileComparer Comparer = new(.001F); + + [Theory] + [InlineData(255, 128, 128, 1, 1, 1)] + [InlineData(0, 128, 128, 0, 0, 0)] + [InlineData(128, 128, 128, 0.502, 0.502, 0.502)] + public void Convert_YCbCr_To_Rgb(float y, float cb, float cr, float r, float g, float b) + { + // Arrange + YCbCr input = new(y, cb, cr); + Rgb expected = new(r, g, b); + ColorProfileConverter converter = new(); + + Span inputSpan = new YCbCr[5]; + inputSpan.Fill(input); + + Span actualSpan = new Rgb[5]; + + // Act + Rgb actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } + + [Theory] + [InlineData(0, 0, 0, 0, 128, 128)] + [InlineData(1, 1, 1, 255, 128, 128)] + [InlineData(0.5, 0.5, 0.5, 127.5, 128, 128)] + [InlineData(1, 0, 0, 76.245, 84.972, 255)] + public void Convert_Rgb_To_YCbCr(float r, float g, float b, float y, float cb, float cr) + { + // Arrange + Rgb input = new(r, g, b); + YCbCr expected = new(y, cb, cr); + ColorProfileConverter converter = new(); + + Span inputSpan = new Rgb[5]; + inputSpan.Fill(input); + + Span actualSpan = new YCbCr[5]; + + // Act + YCbCr actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } +} diff --git a/tests/ImageSharp.Tests/Colorspaces/RgbTests.cs b/tests/ImageSharp.Tests/ColorProfiles/RgbTests.cs similarity index 66% rename from tests/ImageSharp.Tests/Colorspaces/RgbTests.cs rename to tests/ImageSharp.Tests/ColorProfiles/RgbTests.cs index be96b79f46..7e4d4ee0e7 100644 --- a/tests/ImageSharp.Tests/Colorspaces/RgbTests.cs +++ b/tests/ImageSharp.Tests/ColorProfiles/RgbTests.cs @@ -2,10 +2,10 @@ // Licensed under the Six Labors Split License. using System.Numerics; -using SixLabors.ImageSharp.ColorSpaces; +using SixLabors.ImageSharp.ColorProfiles; using SixLabors.ImageSharp.PixelFormats; -namespace SixLabors.ImageSharp.Tests.Colorspaces; +namespace SixLabors.ImageSharp.Tests.ColorProfiles; /// /// Tests the struct. @@ -18,7 +18,7 @@ public void RgbConstructorAssignsFields() const float r = .75F; const float g = .64F; const float b = .87F; - var rgb = new Rgb(r, g, b); + Rgb rgb = new(r, g, b); Assert.Equal(r, rgb.R); Assert.Equal(g, rgb.G); @@ -28,12 +28,12 @@ public void RgbConstructorAssignsFields() [Fact] public void RgbEquality() { - var x = default(Rgb); - var y = new Rgb(Vector3.One); + Rgb x = default; + Rgb y = new(Vector3.One); - Assert.True(default(Rgb) == default(Rgb)); - Assert.False(default(Rgb) != default(Rgb)); - Assert.Equal(default(Rgb), default(Rgb)); + Assert.True(default == default(Rgb)); + Assert.False(default != default(Rgb)); + Assert.Equal(default, default(Rgb)); Assert.Equal(new Rgb(1, 0, 1), new Rgb(1, 0, 1)); Assert.Equal(new Rgb(Vector3.One), new Rgb(Vector3.One)); Assert.False(x.Equals(y)); @@ -42,14 +42,14 @@ public void RgbEquality() } [Fact] - public void RgbAndRgb24Operators() + public void RgbAndRgb24Interop() { const byte r = 64; const byte g = 128; const byte b = 255; - Rgb24 rgb24 = new Rgb(r / 255F, g / 255F, b / 255F); - Rgb rgb2 = rgb24; + Rgb24 rgb24 = Rgb24.FromScaledVector4(new Rgb(r / 255F, g / 255F, b / 255F).ToScaledVector4()); + Rgb rgb2 = Rgb.FromScaledVector4(rgb24.ToScaledVector4()); Assert.Equal(r, rgb24.R); Assert.Equal(g, rgb24.G); @@ -61,14 +61,14 @@ public void RgbAndRgb24Operators() } [Fact] - public void RgbAndRgba32Operators() + public void RgbAndRgba32Interop() { const byte r = 64; const byte g = 128; const byte b = 255; - Rgba32 rgba32 = new Rgb(r / 255F, g / 255F, b / 255F); - Rgb rgb2 = rgba32; + Rgba32 rgba32 = Rgba32.FromScaledVector4(new Rgb(r / 255F, g / 255F, b / 255F).ToScaledVector4()); + Rgb rgb2 = Rgb.FromScaledVector4(rgba32.ToScaledVector4()); Assert.Equal(r, rgba32.R); Assert.Equal(g, rgba32.G); diff --git a/tests/ImageSharp.Tests/Colorspaces/StringRepresentationTests.cs b/tests/ImageSharp.Tests/ColorProfiles/StringRepresentationTests.cs similarity index 78% rename from tests/ImageSharp.Tests/Colorspaces/StringRepresentationTests.cs rename to tests/ImageSharp.Tests/ColorProfiles/StringRepresentationTests.cs index 2ae0824f28..770c987dba 100644 --- a/tests/ImageSharp.Tests/Colorspaces/StringRepresentationTests.cs +++ b/tests/ImageSharp.Tests/ColorProfiles/StringRepresentationTests.cs @@ -2,18 +2,17 @@ // Licensed under the Six Labors Split License. using System.Numerics; -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; +using SixLabors.ImageSharp.ColorProfiles; -namespace SixLabors.ImageSharp.Tests.Colorspaces; +namespace SixLabors.ImageSharp.Tests.ColorProfiles; public class StringRepresentationTests { - private static readonly Vector3 One = new Vector3(1); - private static readonly Vector3 Zero = new Vector3(0); - private static readonly Vector3 Random = new Vector3(42.4F, 94.5F, 83.4F); + private static readonly Vector3 One = new(1); + private static readonly Vector3 Zero = new(0); + private static readonly Vector3 Random = new(42.4F, 94.5F, 83.4F); - public static readonly TheoryData TestData = new TheoryData + public static readonly TheoryData TestData = new() { { new CieLab(Zero), "CieLab(0, 0, 0)" }, { new CieLch(Zero), "CieLch(0, 0, 0)" }, @@ -23,7 +22,6 @@ public class StringRepresentationTests { new CieXyy(Zero), "CieXyy(0, 0, 0)" }, { new HunterLab(Zero), "HunterLab(0, 0, 0)" }, { new Lms(Zero), "Lms(0, 0, 0)" }, - { new LinearRgb(Zero), "LinearRgb(0, 0, 0)" }, { new Rgb(Zero), "Rgb(0, 0, 0)" }, { new Hsl(Zero), "Hsl(0, 0, 0)" }, { new Hsv(Zero), "Hsv(0, 0, 0)" }, @@ -36,7 +34,6 @@ public class StringRepresentationTests { new CieXyy(One), "CieXyy(1, 1, 1)" }, { new HunterLab(One), "HunterLab(1, 1, 1)" }, { new Lms(One), "Lms(1, 1, 1)" }, - { new LinearRgb(One), "LinearRgb(1, 1, 1)" }, { new Rgb(One), "Rgb(1, 1, 1)" }, { new Hsl(One), "Hsl(1, 1, 1)" }, { new Hsv(One), "Hsv(1, 1, 1)" }, @@ -50,8 +47,8 @@ public class StringRepresentationTests { new CieXyy(Random), "CieXyy(42.4, 94.5, 83.4)" }, { new HunterLab(Random), "HunterLab(42.4, 94.5, 83.4)" }, { new Lms(Random), "Lms(42.4, 94.5, 83.4)" }, - { new LinearRgb(Random), "LinearRgb(1, 1, 1)" }, // clamping to 1 is expected - { new Rgb(Random), "Rgb(1, 1, 1)" }, // clamping to 1 is expected + { new Rgb(Random), "Rgb(42.4, 94.5, 83.4)" }, + { Rgb.Clamp(new Rgb(Random)), "Rgb(1, 1, 1)" }, { new Hsl(Random), "Hsl(42.4, 1, 1)" }, // clamping to 1 is expected { new Hsv(Random), "Hsv(42.4, 1, 1)" }, // clamping to 1 is expected { new YCbCr(Random), "YCbCr(42.4, 94.5, 83.4)" }, diff --git a/tests/ImageSharp.Tests/ColorProfiles/VonKriesChromaticAdaptationTests.cs b/tests/ImageSharp.Tests/ColorProfiles/VonKriesChromaticAdaptationTests.cs new file mode 100644 index 0000000000..7f5687dee2 --- /dev/null +++ b/tests/ImageSharp.Tests/ColorProfiles/VonKriesChromaticAdaptationTests.cs @@ -0,0 +1,42 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.ColorProfiles; + +namespace SixLabors.ImageSharp.Tests.ColorProfiles; + +public class VonKriesChromaticAdaptationTests +{ + private static readonly ApproximateColorProfileComparer Comparer = new(.0001F); + public static readonly TheoryData WhitePoints = new() + { + { KnownIlluminants.D65, KnownIlluminants.D50 }, + { KnownIlluminants.D65, KnownIlluminants.D65 } + }; + + [Theory] + [MemberData(nameof(WhitePoints))] + public void SingleAndBulkTransformYieldIdenticalResults(CieXyz from, CieXyz to) + { + ColorConversionOptions options = new() + { + WhitePoint = from, + TargetWhitePoint = to + }; + + CieXyz input = new(1, 0, 1); + CieXyz expected = VonKriesChromaticAdaptation.Transform(in input, (from, to), KnownChromaticAdaptationMatrices.Bradford); + + Span inputSpan = new CieXyz[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieXyz[5]; + + VonKriesChromaticAdaptation.Transform(inputSpan, actualSpan, (from, to), KnownChromaticAdaptationMatrices.Bradford); + + for (int i = 0; i < inputSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } +} diff --git a/tests/ImageSharp.Tests/Colorspaces/YCbCrTests.cs b/tests/ImageSharp.Tests/ColorProfiles/YCbCrTests.cs similarity index 65% rename from tests/ImageSharp.Tests/Colorspaces/YCbCrTests.cs rename to tests/ImageSharp.Tests/ColorProfiles/YCbCrTests.cs index efab45c3cb..f8404ad948 100644 --- a/tests/ImageSharp.Tests/Colorspaces/YCbCrTests.cs +++ b/tests/ImageSharp.Tests/ColorProfiles/YCbCrTests.cs @@ -1,10 +1,10 @@ -// Copyright (c) Six Labors. +// Copyright (c) Six Labors. // Licensed under the Six Labors Split License. using System.Numerics; -using SixLabors.ImageSharp.ColorSpaces; +using SixLabors.ImageSharp.ColorProfiles; -namespace SixLabors.ImageSharp.Tests.Colorspaces; +namespace SixLabors.ImageSharp.Tests.ColorProfiles; /// /// Tests the struct. @@ -17,7 +17,7 @@ public void YCbCrConstructorAssignsFields() const float y = 75F; const float cb = 64F; const float cr = 87F; - var yCbCr = new YCbCr(y, cb, cr); + YCbCr yCbCr = new(y, cb, cr); Assert.Equal(y, yCbCr.Y); Assert.Equal(cb, yCbCr.Cb); @@ -27,12 +27,12 @@ public void YCbCrConstructorAssignsFields() [Fact] public void YCbCrEquality() { - var x = default(YCbCr); - var y = new YCbCr(Vector3.One); + YCbCr x = default; + YCbCr y = new(Vector3.One); - Assert.True(default(YCbCr) == default(YCbCr)); - Assert.False(default(YCbCr) != default(YCbCr)); - Assert.Equal(default(YCbCr), default(YCbCr)); + Assert.True(default == default(YCbCr)); + Assert.False(default != default(YCbCr)); + Assert.Equal(default, default(YCbCr)); Assert.Equal(new YCbCr(1, 0, 1), new YCbCr(1, 0, 1)); Assert.Equal(new YCbCr(Vector3.One), new YCbCr(Vector3.One)); Assert.False(x.Equals(y)); diff --git a/tests/ImageSharp.Tests/Colorspaces/Companding/CompandingTests.cs b/tests/ImageSharp.Tests/Colorspaces/Companding/CompandingTests.cs deleted file mode 100644 index 3fb3598909..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Companding/CompandingTests.cs +++ /dev/null @@ -1,113 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Numerics; -using SixLabors.ImageSharp.ColorSpaces.Companding; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Companding; - -/// -/// Tests various companding algorithms. Expanded numbers are hand calculated from formulas online. -/// -public class CompandingTests -{ - private static readonly ApproximateFloatComparer FloatComparer = new ApproximateFloatComparer(.00001F); - - [Fact] - public void Rec2020Companding_IsCorrect() - { - const float input = .667F; - float e = Rec2020Companding.Expand(input); - float c = Rec2020Companding.Compress(e); - CompandingIsCorrectImpl(e, c, .4484759F, input); - } - - [Fact] - public void Rec709Companding_IsCorrect() - { - const float input = .667F; - float e = Rec709Companding.Expand(input); - float c = Rec709Companding.Compress(e); - CompandingIsCorrectImpl(e, c, .4483577F, input); - } - - [Fact] - public void SRgbCompanding_IsCorrect() - { - const float input = .667F; - float e = SRgbCompanding.Expand(input); - float c = SRgbCompanding.Compress(e); - CompandingIsCorrectImpl(e, c, .40242353F, input); - } - - [Theory] - [InlineData(0)] - [InlineData(1)] - [InlineData(30)] - public void SRgbCompanding_Expand_VectorSpan(int length) - { - var rnd = new Random(42); - Vector4[] source = rnd.GenerateRandomVectorArray(length, 0, 1); - var expected = new Vector4[source.Length]; - - for (int i = 0; i < source.Length; i++) - { - Vector4 s = source[i]; - ref Vector4 e = ref expected[i]; - SRgbCompanding.Expand(ref s); - e = s; - } - - SRgbCompanding.Expand(source); - - Assert.Equal(expected, source, new ApproximateFloatComparer(1e-6f)); - } - - [Theory] - [InlineData(0)] - [InlineData(1)] - [InlineData(30)] - public void SRgbCompanding_Compress_VectorSpan(int length) - { - var rnd = new Random(42); - Vector4[] source = rnd.GenerateRandomVectorArray(length, 0, 1); - var expected = new Vector4[source.Length]; - - for (int i = 0; i < source.Length; i++) - { - Vector4 s = source[i]; - ref Vector4 e = ref expected[i]; - SRgbCompanding.Compress(ref s); - e = s; - } - - SRgbCompanding.Compress(source); - - Assert.Equal(expected, source, new ApproximateFloatComparer(1e-6f)); - } - - [Fact] - public void GammaCompanding_IsCorrect() - { - const float gamma = 2.2F; - const float input = .667F; - float e = GammaCompanding.Expand(input, gamma); - float c = GammaCompanding.Compress(e, gamma); - CompandingIsCorrectImpl(e, c, .41027668F, input); - } - - [Fact] - public void LCompanding_IsCorrect() - { - const float input = .667F; - float e = LCompanding.Expand(input); - float c = LCompanding.Compress(e); - CompandingIsCorrectImpl(e, c, .36236193F, input); - } - - private static void CompandingIsCorrectImpl(float e, float c, float expanded, float compressed) - { - Assert.Equal(expanded, e, FloatComparer); - Assert.Equal(compressed, c, FloatComparer); - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/ApproximateColorspaceComparer.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/ApproximateColorspaceComparer.cs deleted file mode 100644 index d66a73b5a1..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/ApproximateColorspaceComparer.cs +++ /dev/null @@ -1,238 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Allows the approximate comparison of colorspace component values. -/// -internal readonly struct ApproximateColorSpaceComparer : - IEqualityComparer, - IEqualityComparer, - IEqualityComparer, - IEqualityComparer, - IEqualityComparer, - IEqualityComparer, - IEqualityComparer, - IEqualityComparer, - IEqualityComparer, - IEqualityComparer, - IEqualityComparer, - IEqualityComparer, - IEqualityComparer, - IEqualityComparer, - IEqualityComparer, - IEqualityComparer, - IEqualityComparer, - IEqualityComparer -{ - private readonly float epsilon; - - /// - /// Initializes a new instance of the class. - /// - /// The comparison error difference epsilon to use. - public ApproximateColorSpaceComparer(float epsilon = 1F) => this.epsilon = epsilon; - - /// - public bool Equals(Rgb x, Rgb y) - { - return this.Equals(x.R, y.R) - && this.Equals(x.G, y.G) - && this.Equals(x.B, y.B); - } - - /// - public int GetHashCode(Rgb obj) => obj.GetHashCode(); - - /// - public bool Equals(LinearRgb x, LinearRgb y) - { - return this.Equals(x.R, y.R) - && this.Equals(x.G, y.G) - && this.Equals(x.B, y.B); - } - - /// - public int GetHashCode(LinearRgb obj) => obj.GetHashCode(); - - /// - public bool Equals(CieLab x, CieLab y) - { - return this.Equals(x.L, y.L) - && this.Equals(x.A, y.A) - && this.Equals(x.B, y.B); - } - - /// - public int GetHashCode(CieLab obj) => obj.GetHashCode(); - - /// - public bool Equals(CieLch x, CieLch y) - { - return this.Equals(x.L, y.L) - && this.Equals(x.C, y.C) - && this.Equals(x.H, y.H); - } - - /// - public int GetHashCode(CieLch obj) => obj.GetHashCode(); - - /// - public bool Equals(CieLchuv x, CieLchuv y) - { - return this.Equals(x.L, y.L) - && this.Equals(x.C, y.C) - && this.Equals(x.H, y.H); - } - - /// - public int GetHashCode(CieLchuv obj) => obj.GetHashCode(); - - /// - public bool Equals(CieLuv x, CieLuv y) - { - return this.Equals(x.L, y.L) - && this.Equals(x.U, y.U) - && this.Equals(x.V, y.V); - } - - /// - public int GetHashCode(CieLuv obj) => obj.GetHashCode(); - - /// - public bool Equals(CieXyz x, CieXyz y) - { - return this.Equals(x.X, y.X) - && this.Equals(x.Y, y.Y) - && this.Equals(x.Z, y.Z); - } - - /// - public int GetHashCode(CieXyz obj) => obj.GetHashCode(); - - /// - public bool Equals(CieXyy x, CieXyy y) - { - return this.Equals(x.X, y.X) - && this.Equals(x.Y, y.Y) - && this.Equals(x.Yl, y.Yl); - } - - /// - public int GetHashCode(CieXyy obj) => obj.GetHashCode(); - - /// - public bool Equals(Cmyk x, Cmyk y) - { - return this.Equals(x.C, y.C) - && this.Equals(x.M, y.M) - && this.Equals(x.Y, y.Y) - && this.Equals(x.K, y.K); - } - - /// - public int GetHashCode(Cmyk obj) => obj.GetHashCode(); - - /// - public bool Equals(HunterLab x, HunterLab y) - { - return this.Equals(x.L, y.L) - && this.Equals(x.A, y.A) - && this.Equals(x.B, y.B); - } - - /// - public int GetHashCode(HunterLab obj) => obj.GetHashCode(); - - /// - public bool Equals(Hsl x, Hsl y) - { - return this.Equals(x.H, y.H) - && this.Equals(x.S, y.S) - && this.Equals(x.L, y.L); - } - - /// - public int GetHashCode(Hsl obj) => obj.GetHashCode(); - - /// - public bool Equals(Hsv x, Hsv y) - { - return this.Equals(x.H, y.H) - && this.Equals(x.S, y.S) - && this.Equals(x.V, y.V); - } - - /// - public int GetHashCode(Hsv obj) => obj.GetHashCode(); - - /// - public bool Equals(Lms x, Lms y) - { - return this.Equals(x.L, y.L) - && this.Equals(x.M, y.M) - && this.Equals(x.S, y.S); - } - - /// - public int GetHashCode(Lms obj) => obj.GetHashCode(); - - /// - public bool Equals(YCbCr x, YCbCr y) - { - return this.Equals(x.Y, y.Y) - && this.Equals(x.Cb, y.Cb) - && this.Equals(x.Cr, y.Cr); - } - - /// - public int GetHashCode(YCbCr obj) => obj.GetHashCode(); - - /// - public bool Equals(CieXyChromaticityCoordinates x, CieXyChromaticityCoordinates y) => this.Equals(x.X, y.X) && this.Equals(x.Y, y.Y); - - /// - public int GetHashCode(CieXyChromaticityCoordinates obj) => obj.GetHashCode(); - - /// - public bool Equals(RgbPrimariesChromaticityCoordinates x, RgbPrimariesChromaticityCoordinates y) => this.Equals(x.R, y.R) && this.Equals(x.G, y.G) && this.Equals(x.B, y.B); - - /// - public int GetHashCode(RgbPrimariesChromaticityCoordinates obj) => obj.GetHashCode(); - - /// - public bool Equals(GammaWorkingSpace x, GammaWorkingSpace y) - { - if (x is GammaWorkingSpace g1 && y is GammaWorkingSpace g2) - { - return this.Equals(g1.Gamma, g2.Gamma) - && this.Equals(g1.WhitePoint, g2.WhitePoint) - && this.Equals(g1.ChromaticityCoordinates, g2.ChromaticityCoordinates); - } - - return false; - } - - /// - public int GetHashCode(GammaWorkingSpace obj) => obj.GetHashCode(); - - /// - public bool Equals(RgbWorkingSpace x, RgbWorkingSpace y) - { - return this.Equals(x.WhitePoint, y.WhitePoint) - && this.Equals(x.ChromaticityCoordinates, y.ChromaticityCoordinates); - } - - /// - public int GetHashCode(RgbWorkingSpace obj) => obj.GetHashCode(); - - private bool Equals(float x, float y) - { - float d = x - y; - return d >= -this.epsilon && d <= this.epsilon; - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieLchuvConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieLchuvConversionTests.cs deleted file mode 100644 index d8378217e4..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieLchuvConversionTests.cs +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -/// -/// Test data generated using: -/// -/// -public class CieLabAndCieLchuvConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(30.66194, 200, 352.7564, 31.95653, 116.8745, 2.388602)] - public void Convert_Lchuv_to_Lab(float l, float c, float h, float l2, float a, float b) - { - // Arrange - var input = new CieLchuv(l, c, h); - var expected = new CieLab(l2, a, b); - - Span inputSpan = new CieLchuv[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieLab[5]; - - // Act - var actual = Converter.ToCieLab(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(36.0555, 303.6901, 10.01514, 30.66194, 200, 352.7564)] - public void Convert_Lab_to_Lchuv(float l, float a, float b, float l2, float c, float h) - { - // Arrange - var input = new CieLab(l, a, b); - var expected = new CieLchuv(l2, c, h); - - Span inputSpan = new CieLab[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieLchuv[5]; - - // Act - var actual = Converter.ToCieLchuv(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieLuvConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieLuvConversionTests.cs deleted file mode 100644 index 220ef4f220..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieLuvConversionTests.cs +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -/// -/// Test data generated using: -/// -/// -public class CieLabAndCieLuvConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(10, 36.0555, 303.6901, 10.0151367, -23.9644356, 17.0226)] - public void Convert_CieLuv_to_CieLab(float l, float u, float v, float l2, float a, float b) - { - // Arrange - var input = new CieLuv(l, u, v); - var expected = new CieLab(l2, a, b); - - Span inputSpan = new CieLuv[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieLab[5]; - - // Act - var actual = Converter.ToCieLab(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(10.0151367, -23.9644356, 17.0226, 10.0000038, -12.830183, 15.1829338)] - public void Convert_CieLab_to_CieLuv(float l, float a, float b, float l2, float u, float v) - { - // Arrange - var input = new CieLab(l, a, b); - var expected = new CieLuv(l2, u, v); - - Span inputSpan = new CieLab[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieLuv[5]; - - // Act - var actual = Converter.ToCieLuv(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieXyyConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieXyyConversionTests.cs deleted file mode 100644 index 49ea4502fc..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieXyyConversionTests.cs +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -public class CieLabAndCieXyyConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(0.8644734, 0.06098868, 0.06509002, 36.05552, 275.6228, 10.01517)] - public void Convert_CieXyy_to_CieLab(float x, float y, float yl, float l, float a, float b) - { - // Arrange - var input = new CieXyy(x, y, yl); - var expected = new CieLab(l, a, b); - - Span inputSpan = new CieXyy[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieLab[5]; - - // Act - var actual = Converter.ToCieLab(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(36.0555, 303.6901, 10.01514, 0.8644734, 0.06098868, 0.06509002)] - public void Convert_CieLab_to_CieXyy(float l, float a, float b, float x, float y, float yl) - { - // Arrange - var input = new CieLab(l, a, b); - var expected = new CieXyy(x, y, yl); - - Span inputSpan = new CieLab[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieXyy[5]; - - // Act - var actual = Converter.ToCieXyy(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCmykConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCmykConversionTests.cs deleted file mode 100644 index 7f9470e202..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCmykConversionTests.cs +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -public class CieLabAndCmykConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 1, 0, 0, 0)] - [InlineData(0, 1, 0.6156551, 5.960464E-08, 55.063, 82.54871, 23.16506)] - public void Convert_Cmyk_to_CieLab(float c, float m, float y, float k, float l, float a, float b) - { - // Arrange - var input = new Cmyk(c, m, y, k); - var expected = new CieLab(l, a, b); - - Span inputSpan = new Cmyk[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieLab[5]; - - // Act - var actual = Converter.ToCieLab(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0, 1)] - [InlineData(36.0555, 303.6901, 10.01514, 0, 1, 0.6156551, 5.960464E-08)] - public void Convert_CieLab_to_Cmyk(float l, float a, float b, float c, float m, float y, float k) - { - // Arrange - var input = new CieLab(l, a, b); - var expected = new Cmyk(c, m, y, k); - - Span inputSpan = new CieLab[5]; - inputSpan.Fill(input); - - Span actualSpan = new Cmyk[5]; - - // Act - var actual = Converter.ToCmyk(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndHslConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndHslConversionTests.cs deleted file mode 100644 index 1af6a9315f..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndHslConversionTests.cs +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -public class CieLabAndHslConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(336.9393, 1, 0.5, 55.063, 82.54868, 23.16508)] - public void Convert_Hsl_to_CieLab(float h, float s, float ll, float l, float a, float b) - { - // Arrange - var input = new Hsl(h, s, ll); - var expected = new CieLab(l, a, b); - - Span inputSpan = new Hsl[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieLab[5]; - - // Act - var actual = Converter.ToCieLab(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(36.0555, 303.6901, 10.01514, 336.9393, 1, 0.5)] - public void Convert_CieLab_to_Hsl(float l, float a, float b, float h, float s, float ll) - { - // Arrange - var input = new CieLab(l, a, b); - var expected = new Hsl(h, s, ll); - - Span inputSpan = new CieLab[5]; - inputSpan.Fill(input); - - Span actualSpan = new Hsl[5]; - - // Act - var actual = Converter.ToHsl(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndHsvConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndHsvConversionTests.cs deleted file mode 100644 index c7c3ad19b5..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndHsvConversionTests.cs +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -public class CieLabAndHsvConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(336.9393, 1, 0.9999999, 55.063, 82.54871, 23.16504)] - public void Convert_Hsv_to_CieLab(float h, float s, float v, float l, float a, float b) - { - // Arrange - var input = new Hsv(h, s, v); - var expected = new CieLab(l, a, b); - - Span inputSpan = new Hsv[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieLab[5]; - - // Act - var actual = Converter.ToCieLab(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(36.0555, 303.6901, 10.01514, 336.9393, 1, 0.9999999)] - public void Convert_CieLab_to_Hsv(float l, float a, float b, float h, float s, float v) - { - // Arrange - var input = new CieLab(l, a, b); - var expected = new Hsv(h, s, v); - - Span inputSpan = new CieLab[5]; - inputSpan.Fill(input); - - Span actualSpan = new Hsv[5]; - - // Act - var actual = Converter.ToHsv(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndHunterLabConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndHunterLabConversionTests.cs deleted file mode 100644 index 81fff6e144..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndHunterLabConversionTests.cs +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -public class CieLabAndHunterLabConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(27.51646, 556.9392, -0.03974226, 36.05554, 275.6227, 10.01519)] - public void Convert_HunterLab_to_CieLab(float l2, float a2, float b2, float l, float a, float b) - { - // Arrange - var input = new HunterLab(l2, a2, b2); - var expected = new CieLab(l, a, b); - - Span inputSpan = new HunterLab[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieLab[5]; - - // Act - var actual = Converter.ToCieLab(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(36.0555, 303.6901, 10.01514, 27.51646, 556.9392, -0.03974226)] - public void Convert_CieLab_to_HunterLab(float l, float a, float b, float l2, float a2, float b2) - { - // Arrange - var input = new CieLab(l, a, b); - var expected = new HunterLab(l2, a2, b2); - - Span inputSpan = new CieLab[5]; - inputSpan.Fill(input); - - Span actualSpan = new HunterLab[5]; - - // Act - var actual = Converter.ToHunterLab(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndLinearRgbConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndLinearRgbConversionTests.cs deleted file mode 100644 index 68547d8a22..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndLinearRgbConversionTests.cs +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -public class CieLabAndLinearRgbConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(1, 0, 0.1221596, 55.063, 82.54871, 23.16505)] - public void Convert_LinearRgb_to_CieLab(float r, float g, float b2, float l, float a, float b) - { - // Arrange - var input = new LinearRgb(r, g, b2); - var expected = new CieLab(l, a, b); - - Span inputSpan = new LinearRgb[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieLab[5]; - - // Act - var actual = Converter.ToCieLab(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(36.0555, 303.6901, 10.01514, 1, 0, 0.1221596)] - public void Convert_CieLab_to_LinearRgb(float l, float a, float b, float r, float g, float b2) - { - // Arrange - var input = new CieLab(l, a, b); - var expected = new LinearRgb(r, g, b2); - - Span inputSpan = new CieLab[5]; - inputSpan.Fill(input); - - Span actualSpan = new LinearRgb[5]; - - // Act - var actual = Converter.ToLinearRgb(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndLmsConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndLmsConversionTests.cs deleted file mode 100644 index 2918b6f62b..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndLmsConversionTests.cs +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -public class CieLabAndLmsConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(0.8303261, -0.5776886, 0.1133359, 36.05553, 275.6228, 10.01518)] - public void Convert_Lms_to_CieLab(float l2, float m, float s, float l, float a, float b) - { - // Arrange - var input = new Lms(l2, m, s); - var expected = new CieLab(l, a, b); - - Span inputSpan = new Lms[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieLab[5]; - - // Act - var actual = Converter.ToCieLab(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(36.0555, 303.6901, 10.01514, 0.8303261, -0.5776886, 0.1133359)] - public void Convert_CieLab_to_Lms(float l, float a, float b, float l2, float m, float s) - { - // Arrange - var input = new CieLab(l, a, b); - var expected = new Lms(l2, m, s); - - Span inputSpan = new CieLab[5]; - inputSpan.Fill(input); - - Span actualSpan = new Lms[5]; - - // Act - var actual = Converter.ToLms(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndRgbConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndRgbConversionTests.cs deleted file mode 100644 index 3acf695d12..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndRgbConversionTests.cs +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -public class CieLabAndRgbConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(0.9999999, 0, 0.384345, 55.063, 82.54871, 23.16505)] - public void Convert_Rgb_to_CieLab(float r, float g, float b2, float l, float a, float b) - { - // Arrange - var input = new Rgb(r, g, b2); - var expected = new CieLab(l, a, b); - - Span inputSpan = new Rgb[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieLab[5]; - - // Act - var actual = Converter.ToCieLab(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(36.0555, 303.6901, 10.01514, 0.9999999, 0, 0.384345)] - public void Convert_CieLab_to_Rgb(float l, float a, float b, float r, float g, float b2) - { - // Arrange - var input = new CieLab(l, a, b); - var expected = new Rgb(r, g, b2); - - Span inputSpan = new CieLab[5]; - inputSpan.Fill(input); - - Span actualSpan = new Rgb[5]; - - // Act - var actual = Converter.ToRgb(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndYCbCrConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndYCbCrConversionTests.cs deleted file mode 100644 index f13e989a85..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndYCbCrConversionTests.cs +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -public class CieLabAndYCbCrConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 128, 128, 0, 0, 0)] - [InlineData(87.4179, 133.9763, 247.5308, 55.06287, 82.54838, 23.1697)] - public void Convert_YCbCr_to_CieLab(float y, float cb, float cr, float l, float a, float b) - { - // Arrange - var input = new YCbCr(y, cb, cr); - var expected = new CieLab(l, a, b); - - Span inputSpan = new YCbCr[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieLab[5]; - - // Act - var actual = Converter.ToCieLab(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 128, 128)] - [InlineData(36.0555, 303.6901, 10.01514, 87.4179, 133.9763, 247.5308)] - public void Convert_CieLab_to_YCbCr(float l, float a, float b, float y, float cb, float cr) - { - // Arrange - var input = new CieLab(l, a, b); - var expected = new YCbCr(y, cb, cr); - - Span inputSpan = new CieLab[5]; - inputSpan.Fill(input); - - Span actualSpan = new YCbCr[5]; - - // Act - var actual = Converter.ToYCbCr(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndCieLuvConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndCieLuvConversionTests.cs deleted file mode 100644 index b50d47aeba..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndCieLuvConversionTests.cs +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -public class CieLchAndCieLuvConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(36.0555, 103.6901, 10.01514, 34.89777, 187.6642, -7.181467)] - public void Convert_CieLch_to_CieLuv(float l, float c, float h, float l2, float u, float v) - { - // Arrange - var input = new CieLch(l, c, h); - var expected = new CieLuv(l2, u, v); - - Span inputSpan = new CieLch[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieLuv[5]; - - // Act - var actual = Converter.ToCieLuv(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(34.89777, 187.6642, -7.181467, 36.05552, 103.6901, 10.01514)] - public void Convert_CieLuv_to_CieLch(float l2, float u, float v, float l, float c, float h) - { - // Arrange - var input = new CieLuv(l2, u, v); - var expected = new CieLch(l, c, h); - - Span inputSpan = new CieLuv[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieLch[5]; - - // Act - var actual = Converter.ToCieLch(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndCieXyyConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndCieXyyConversionTests.cs deleted file mode 100644 index 93f0828861..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndCieXyyConversionTests.cs +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -public class CieLchAndCieXyyConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(36.0555, 103.6901, 10.01514, 0.6529307, 0.2147411, 0.08447381)] - public void Convert_CieLch_to_CieXyy(float l, float c, float h, float x, float y, float yl) - { - // Arrange - var input = new CieLch(l, c, h); - var expected = new CieXyy(x, y, yl); - - Span inputSpan = new CieLch[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieXyy[5]; - - // Act - var actual = Converter.ToCieXyy(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0.6529307, 0.2147411, 0.08447381, 36.05552, 103.6901, 10.01515)] - public void Convert_CieXyy_to_CieLch(float x, float y, float yl, float l, float c, float h) - { - // Arrange - var input = new CieXyy(x, y, yl); - var expected = new CieLch(l, c, h); - - Span inputSpan = new CieXyy[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieLch[5]; - - // Act - var actual = Converter.ToCieLch(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndHslConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndHslConversionTests.cs deleted file mode 100644 index 0bc76562b1..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndHslConversionTests.cs +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -public class CieLchAndHslConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(36.0555, 103.6901, 10.01514, 341.959, 1, 0.4207301)] - public void Convert_CieLch_to_Hsl(float l, float c, float h, float h2, float s, float l2) - { - // Arrange - var input = new CieLch(l, c, h); - var expected = new Hsl(h2, s, l2); - - Span inputSpan = new CieLch[5]; - inputSpan.Fill(input); - - Span actualSpan = new Hsl[5]; - - // Act - var actual = Converter.ToHsl(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(341.959, 1, 0.4207301, 46.13444, 78.0637, 22.90503)] - public void Convert_Hsl_to_CieLch(float h2, float s, float l2, float l, float c, float h) - { - // Arrange - var input = new Hsl(h2, s, l2); - var expected = new CieLch(l, c, h); - - Span inputSpan = new Hsl[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieLch[5]; - - // Act - var actual = Converter.ToCieLch(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndHsvConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndHsvConversionTests.cs deleted file mode 100644 index bb28c03946..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndHsvConversionTests.cs +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -public class CieLchAndHsvConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(36.0555, 103.6901, 10.01514, 341.959, 1, 0.8414602)] - public void Convert_CieLch_to_Hsv(float l, float c, float h, float h2, float s, float v) - { - // Arrange - var input = new CieLch(l, c, h); - var expected = new Hsv(h2, s, v); - - Span inputSpan = new CieLch[5]; - inputSpan.Fill(input); - - Span actualSpan = new Hsv[5]; - - // Act - var actual = Converter.ToHsv(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(341.959, 1, 0.8414602, 46.13444, 78.0637, 22.90501)] - public void Convert_Hsv_to_CieLch(float h2, float s, float v, float l, float c, float h) - { - // Arrange - var input = new Hsv(h2, s, v); - var expected = new CieLch(l, c, h); - - Span inputSpan = new Hsv[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieLch[5]; - - // Act - var actual = Converter.ToCieLch(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndHunterLabConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndHunterLabConversionTests.cs deleted file mode 100644 index 9892ac8f57..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndHunterLabConversionTests.cs +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -public class CieLchAndHunterLabConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(36.0555, 103.6901, 10.01514, 29.41358, 106.6302, 9.102425)] - public void Convert_CieLch_to_HunterLab(float l, float c, float h, float l2, float a, float b) - { - // Arrange - var input = new CieLch(l, c, h); - var expected = new HunterLab(l2, a, b); - - Span inputSpan = new CieLch[5]; - inputSpan.Fill(input); - - Span actualSpan = new HunterLab[5]; - - // Act - var actual = Converter.ToHunterLab(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(29.41358, 106.6302, 9.102425, 36.05551, 103.6901, 10.01515)] - public void Convert_HunterLab_to_CieLch(float l2, float a, float b, float l, float c, float h) - { - // Arrange - var input = new HunterLab(l2, a, b); - var expected = new CieLch(l, c, h); - - Span inputSpan = new HunterLab[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieLch[5]; - - // Act - var actual = Converter.ToCieLch(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndLinearRgbConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndLinearRgbConversionTests.cs deleted file mode 100644 index 3ecfadf113..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndLinearRgbConversionTests.cs +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -public class CieLchAndLinearRgbConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(36.0555, 103.6901, 10.01514, 0.6765013, 0, 0.05209038)] - public void Convert_CieLch_to_LinearRgb(float l, float c, float h, float r, float g, float b) - { - // Arrange - var input = new CieLch(l, c, h); - var expected = new LinearRgb(r, g, b); - - Span inputSpan = new CieLch[5]; - inputSpan.Fill(input); - - Span actualSpan = new LinearRgb[5]; - - // Act - var actual = Converter.ToLinearRgb(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0.6765013, 0, 0.05209038, 46.13445, 78.06367, 22.90504)] - public void Convert_LinearRgb_to_CieLch(float r, float g, float b, float l, float c, float h) - { - // Arrange - var input = new LinearRgb(r, g, b); - var expected = new CieLch(l, c, h); - - Span inputSpan = new LinearRgb[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieLch[5]; - - // Act - var actual = Converter.ToCieLch(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndLmsConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndLmsConversionTests.cs deleted file mode 100644 index 7a19391211..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndLmsConversionTests.cs +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -public class CieLchAndLmsConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(36.0555, 103.6901, 10.01514, 0.2440057, -0.04603009, 0.05780027)] - public void Convert_CieLch_to_Lms(float l, float c, float h, float l2, float m, float s) - { - // Arrange - var input = new CieLch(l, c, h); - var expected = new Lms(l2, m, s); - - Span inputSpan = new CieLch[5]; - inputSpan.Fill(input); - - Span actualSpan = new Lms[5]; - - // Act - var actual = Converter.ToLms(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0.2440057, -0.04603009, 0.05780027, 36.05552, 103.6901, 10.01515)] - public void Convert_Lms_to_CieLch(float l2, float m, float s, float l, float c, float h) - { - // Arrange - var input = new Lms(l2, m, s); - var expected = new CieLch(l, c, h); - - Span inputSpan = new Lms[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieLch[5]; - - // Act - var actual = Converter.ToCieLch(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndRgbConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndRgbConversionTests.cs deleted file mode 100644 index 013e79534d..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndRgbConversionTests.cs +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -public class CieLchAndRgbConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(36.0555, 103.6901, 10.01514, 0.8414602, 0, 0.2530123)] - public void Convert_CieLch_to_Rgb(float l, float c, float h, float r, float g, float b) - { - // Arrange - var input = new CieLch(l, c, h); - var expected = new Rgb(r, g, b); - - Span inputSpan = new CieLch[5]; - inputSpan.Fill(input); - - Span actualSpan = new Rgb[5]; - - // Act - var actual = Converter.ToRgb(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0.8414602, 0, 0.2530123, 46.13444, 78.0637, 22.90503)] - public void Convert_Rgb_to_CieLch(float r, float g, float b, float l, float c, float h) - { - // Arrange - var input = new Rgb(r, g, b); - var expected = new CieLch(l, c, h); - - Span inputSpan = new Rgb[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieLch[5]; - - // Act - var actual = Converter.ToCieLch(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndYCbCrConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndYCbCrConversionTests.cs deleted file mode 100644 index bcde97102f..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndYCbCrConversionTests.cs +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -public class CieLchAndYCbCrConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 128, 128)] - [InlineData(36.0555, 103.6901, 10.01514, 71.5122, 124.053, 230.0401)] - public void Convert_CieLch_to_YCbCr(float l, float c, float h, float y, float cb, float cr) - { - // Arrange - var input = new CieLch(l, c, h); - var expected = new YCbCr(y, cb, cr); - - Span inputSpan = new CieLch[5]; - inputSpan.Fill(input); - - Span actualSpan = new YCbCr[5]; - - // Act - var actual = Converter.ToYCbCr(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(71.5122, 124.053, 230.0401, 46.23178, 78.1114, 22.7662)] - public void Convert_YCbCr_to_CieLch(float y, float cb, float cr, float l, float c, float h) - { - // Arrange - var input = new YCbCr(y, cb, cr); - var expected = new CieLch(l, c, h); - - Span inputSpan = new YCbCr[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieLch[5]; - - // Act - var actual = Converter.ToCieLch(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchuvAndCieLchConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchuvAndCieLchConversionTests.cs deleted file mode 100644 index 1098de91e0..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchuvAndCieLchConversionTests.cs +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -public class CieLchuvAndCieLchConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(36.73742, 64.79149, 30.1786, 36.0555, 103.6901, 10.01513)] - public void Convert_CieLch_to_CieLchuv(float l2, float c2, float h2, float l, float c, float h) - { - // Arrange - var input = new CieLch(l2, c2, h2); - var expected = new CieLchuv(l, c, h); - - Span inputSpan = new CieLch[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieLchuv[5]; - - // Act - var actual = Converter.ToCieLchuv(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(36.0555, 103.6901, 10.01514, 36.73742, 64.79149, 30.1786)] - public void Convert_CieLchuv_to_CieLch(float l, float c, float h, float l2, float c2, float h2) - { - // Arrange - var input = new CieLchuv(l, c, h); - var expected = new CieLch(l2, c2, h2); - - Span inputSpan = new CieLchuv[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieLch[5]; - - // Act - var actual = Converter.ToCieLch(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchuvAndCmykConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchuvAndCmykConversionTests.cs deleted file mode 100644 index 176a0e2175..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchuvAndCmykConversionTests.cs +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -public class CieLchuvAndCmykConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 1, 0, 0, 0)] - [InlineData(0, 0.8576171, 0.7693201, 0.3440427, 36.0555, 103.6901, 10.01514)] - public void Convert_Cmyk_to_CieLchuv(float c2, float m, float y, float k, float l, float c, float h) - { - // Arrange - var input = new Cmyk(c2, m, y, k); - var expected = new CieLchuv(l, c, h); - - Span inputSpan = new Cmyk[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieLchuv[5]; - - // Act - var actual = Converter.ToCieLchuv(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0, 1)] - [InlineData(36.0555, 103.6901, 10.01514, 0, 0.8576171, 0.7693201, 0.3440427)] - public void Convert_CieLchuv_to_Cmyk(float l, float c, float h, float c2, float m, float y, float k) - { - // Arrange - var input = new CieLchuv(l, c, h); - var expected = new Cmyk(c2, m, y, k); - - Span inputSpan = new CieLchuv[5]; - inputSpan.Fill(input); - - Span actualSpan = new Cmyk[5]; - - // Act - var actual = Converter.ToCmyk(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndCieXyyConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndCieXyyConversionTests.cs deleted file mode 100644 index e32cc6ebfc..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndCieXyyConversionTests.cs +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -public class CieLuvAndCieXyyConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(36.0555, 103.6901, 10.01514, 0.5646762, 0.2932749, 0.09037033)] - public void Convert_CieLuv_to_CieXyy(float l, float u, float v, float x, float y, float yl) - { - // Arrange - var input = new CieLuv(l, u, v); - var expected = new CieXyy(x, y, yl); - - Span inputSpan = new CieLuv[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieXyy[5]; - - // Act - var actual = Converter.ToCieXyy(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(0.5646762, 0.2932749, 0.09037033, 36.0555, 103.6901, 10.01514)] - public void Convert_CieXyy_to_CieLuv(float x, float y, float yl, float l, float u, float v) - { - // Arrange - var input = new CieXyy(x, y, yl); - var expected = new CieLuv(l, u, v); - - Span inputSpan = new CieXyy[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieLuv[5]; - - // Act - var actual = Converter.ToCieLuv(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndHslConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndHslConversionTests.cs deleted file mode 100644 index 95f07465ab..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndHslConversionTests.cs +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -public class CieLuvAndHslConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(36.0555, 93.6901, 10.01514, 347.3767, 0.7115612, 0.3765343)] - public void Convert_CieLuv_to_Hsl(float l, float u, float v, float h, float s, float l2) - { - // Arrange - var input = new CieLuv(l, u, v); - var expected = new Hsl(h, s, l2); - - Span inputSpan = new CieLuv[5]; - inputSpan.Fill(input); - - Span actualSpan = new Hsl[5]; - - // Act - var actual = Converter.ToHsl(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(347.3767, 0.7115612, 0.3765343, 36.0555, 93.69012, 10.01514)] - public void Convert_Hsl_to_CieLuv(float h, float s, float l2, float l, float u, float v) - { - // Arrange - var input = new Hsl(h, s, l2); - var expected = new CieLuv(l, u, v); - - Span inputSpan = new Hsl[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieLuv[5]; - - // Act - var actual = Converter.ToCieLuv(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndHsvConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndHsvConversionTests.cs deleted file mode 100644 index ddb90f0ef9..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndHsvConversionTests.cs +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -public class CieLuvAndHsvConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(36.0555, 93.6901, 10.01514, 347.3767, 0.8314762, 0.6444615)] - public void Convert_CieLuv_to_Hsv(float l, float u, float v, float h, float s, float v2) - { - // Arrange - var input = new CieLuv(l, u, v); - var expected = new Hsv(h, s, v2); - - Span inputSpan = new CieLuv[5]; - inputSpan.Fill(input); - - Span actualSpan = new Hsv[5]; - - // Act - var actual = Converter.ToHsv(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(347.3767, 0.8314762, 0.6444615, 36.0555, 93.69012, 10.01514)] - public void Convert_Hsv_to_CieLuv(float h, float s, float v2, float l, float u, float v) - { - // Arrange - var input = new Hsv(h, s, v2); - var expected = new CieLuv(l, u, v); - - Span inputSpan = new Hsv[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieLuv[5]; - - // Act - var actual = Converter.ToCieLuv(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndHunterLabConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndHunterLabConversionTests.cs deleted file mode 100644 index 38449e4b77..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndHunterLabConversionTests.cs +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -public class CieLuvAndHunterLabConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(36.0555, 93.6901, 10.01514, 30.19531, 46.4312, 11.16259)] - public void Convert_CieLuv_to_HunterLab(float l, float u, float v, float l2, float a, float b) - { - // Arrange - var input = new CieLuv(l, u, v); - var expected = new HunterLab(l2, a, b); - - Span inputSpan = new CieLuv[5]; - inputSpan.Fill(input); - - Span actualSpan = new HunterLab[5]; - - // Act - var actual = Converter.ToHunterLab(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(30.19531, 46.4312, 11.16259, 36.0555, 93.6901, 10.01514)] - public void Convert_HunterLab_to_CieLuv(float l2, float a, float b, float l, float u, float v) - { - // Arrange - var input = new HunterLab(l2, a, b); - var expected = new CieLuv(l, u, v); - - Span inputSpan = new HunterLab[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieLuv[5]; - - // Act - var actual = Converter.ToCieLuv(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndLinearRgbConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndLinearRgbConversionTests.cs deleted file mode 100644 index f3bd936043..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndLinearRgbConversionTests.cs +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -public class CieLuvAndLinearRgbConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(36.0555, 93.6901, 10.01514, 0.3729299, 0.01141088, 0.04014909)] - public void Convert_CieLuv_to_LinearRgb(float l, float u, float v, float r, float g, float b) - { - // Arrange - var input = new CieLuv(l, u, v); - var expected = new LinearRgb(r, g, b); - - Span inputSpan = new CieLuv[5]; - inputSpan.Fill(input); - - Span actualSpan = new LinearRgb[5]; - - // Act - var actual = Converter.ToLinearRgb(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(0.3729299, 0.01141088, 0.04014909, 36.0555, 93.6901, 10.01511)] - public void Convert_LinearRgb_to_CieLuv(float r, float g, float b, float l, float u, float v) - { - // Arrange - var input = new LinearRgb(r, g, b); - var expected = new CieLuv(l, u, v); - - Span inputSpan = new LinearRgb[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieLuv[5]; - - // Act - var actual = Converter.ToCieLuv(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndLmsConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndLmsConversionTests.cs deleted file mode 100644 index ac90a7ba41..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndLmsConversionTests.cs +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -public class CieLuvAndLmsConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(36.0555, 93.6901, 10.01514, 0.164352, 0.03267485, 0.0483408)] - public void Convert_CieLuv_to_Lms(float l, float u, float v, float l2, float m, float s) - { - // Arrange - var input = new CieLuv(l, u, v); - var expected = new Lms(l2, m, s); - - Span inputSpan = new CieLuv[5]; - inputSpan.Fill(input); - - Span actualSpan = new Lms[5]; - - // Act - var actual = Converter.ToLms(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(0.164352, 0.03267485, 0.0483408, 36.0555, 93.69009, 10.01514)] - public void Convert_Lms_to_CieLuv(float l2, float m, float s, float l, float u, float v) - { - // Arrange - var input = new Lms(l2, m, s); - var expected = new CieLuv(l, u, v); - - Span inputSpan = new Lms[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieLuv[5]; - - // Act - var actual = Converter.ToCieLuv(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndRgbConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndRgbConversionTests.cs deleted file mode 100644 index b2e308fce0..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndRgbConversionTests.cs +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -public class CieLuvAndRgbConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(36.0555, 93.6901, 10.01514, 0.6444615, 0.1086071, 0.2213444)] - public void Convert_CieLuv_to_Rgb(float l, float u, float v, float r, float g, float b) - { - // Arrange - var input = new CieLuv(l, u, v); - var expected = new Rgb(r, g, b); - - Span inputSpan = new CieLuv[5]; - inputSpan.Fill(input); - - Span actualSpan = new Rgb[5]; - - // Act - var actual = Converter.ToRgb(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(0.6444615, 0.1086071, 0.2213444, 36.0555, 93.69012, 10.01514)] - public void Convert_Rgb_to_CieLuv(float r, float g, float b, float l, float u, float v) - { - // Arrange - var input = new Rgb(r, g, b); - var expected = new CieLuv(l, u, v); - - Span inputSpan = new Rgb[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieLuv[5]; - - // Act - var actual = Converter.ToCieLuv(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndYCbCrConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndYCbCrConversionTests.cs deleted file mode 100644 index f7c6372b1a..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndYCbCrConversionTests.cs +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -public class CieLuvAndYCbCrConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 128, 128)] - [InlineData(36.0555, 93.6901, 10.01514, 71.8283, 119.3174, 193.9839)] - public void Convert_CieLuv_to_YCbCr(float l, float u, float v, float y, float cb, float cr) - { - // Arrange - var input = new CieLuv(l, u, v); - var expected = new YCbCr(y, cb, cr); - - Span inputSpan = new CieLuv[5]; - inputSpan.Fill(input); - - Span actualSpan = new YCbCr[5]; - - // Act - var actual = Converter.ToYCbCr(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 128, 128, 0, 0, 0)] - [InlineData(71.8283, 119.3174, 193.9839, 36.00565, 93.44593, 10.2234)] - public void Convert_YCbCr_to_CieLuv(float y, float cb, float cr, float l, float u, float v) - { - // Arrange - var input = new YCbCr(y, cb, cr); - var expected = new CieLuv(l, u, v); - - Span inputSpan = new YCbCr[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieLuv[5]; - - // Act - var actual = Converter.ToCieLuv(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndHslConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndHslConversionTests.cs deleted file mode 100644 index bae9140029..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndHslConversionTests.cs +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -public class CieXyyAndHslConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(0.360555, 0.936901, 0.1001514, 120, 1, 0.211263)] - public void Convert_CieXyy_to_Hsl(float x, float y, float yl, float h, float s, float l) - { - // Arrange - var input = new CieXyy(x, y, yl); - var expected = new Hsl(h, s, l); - - Span inputSpan = new CieXyy[5]; - inputSpan.Fill(input); - - Span actualSpan = new Hsl[5]; - - // Act - var actual = Converter.ToHsl(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(120, 1, 0.211263, 0.3, 0.6, 0.1067051)] - public void Convert_Hsl_to_CieXyy(float h, float s, float l, float x, float y, float yl) - { - // Arrange - var input = new Hsl(h, s, l); - var expected = new CieXyy(x, y, yl); - - Span inputSpan = new Hsl[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieXyy[5]; - - // Act - CieXyy actual = Converter.ToCieXyy(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndHsvConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndHsvConversionTests.cs deleted file mode 100644 index 7de91cc322..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndHsvConversionTests.cs +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -public class CieXyyAndHsvConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(0.360555, 0.936901, 0.1001514, 120, 1, 0.4225259)] - public void Convert_CieXyy_to_Hsv(float x, float y, float yl, float h, float s, float v) - { - // Arrange - var input = new CieXyy(x, y, yl); - var expected = new Hsv(h, s, v); - - Span inputSpan = new CieXyy[5]; - inputSpan.Fill(input); - - Span actualSpan = new Hsv[5]; - - // Act - var actual = Converter.ToHsv(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(120, 1, 0.4225259, 0.3, 0.6, 0.1067051)] - public void Convert_Hsv_to_CieXyy(float h, float s, float v, float x, float y, float yl) - { - // Arrange - var input = new Hsv(h, s, v); - var expected = new CieXyy(x, y, yl); - - Span inputSpan = new Hsv[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieXyy[5]; - - // Act - var actual = Converter.ToCieXyy(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndHunterLabConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndHunterLabConversionTests.cs deleted file mode 100644 index 40b58b7048..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndHunterLabConversionTests.cs +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -public class CieXyyAndHunterLabConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(0.360555, 0.936901, 0.1001514, 31.46263, -32.81796, 28.64938)] - public void Convert_CieXyy_to_HunterLab(float x, float y, float yl, float l, float a, float b) - { - // Arrange - var input = new CieXyy(x, y, yl); - var expected = new HunterLab(l, a, b); - - Span inputSpan = new CieXyy[5]; - inputSpan.Fill(input); - - Span actualSpan = new HunterLab[5]; - - // Act - var actual = Converter.ToHunterLab(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(31.46263, -32.81796, 28.64938, 0.3605552, 0.9369011, 0.1001514)] - public void Convert_HunterLab_to_CieXyy(float l, float a, float b, float x, float y, float yl) - { - // Arrange - var input = new HunterLab(l, a, b); - var expected = new CieXyy(x, y, yl); - - Span inputSpan = new HunterLab[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieXyy[5]; - - // Act - CieXyy actual = Converter.ToCieXyy(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndLinearRgbConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndLinearRgbConversionTests.cs deleted file mode 100644 index 062f54abc3..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndLinearRgbConversionTests.cs +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -public class CieXyyAndLinearRgbConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(0.360555, 0.936901, 0.1001514, 0, 0.1492062, 0)] - public void Convert_CieXyy_to_LinearRgb(float x, float y, float yl, float r, float g, float b) - { - // Arrange - var input = new CieXyy(x, y, yl); - var expected = new LinearRgb(r, g, b); - - Span inputSpan = new CieXyy[5]; - inputSpan.Fill(input); - - Span actualSpan = new LinearRgb[5]; - - // Act - var actual = Converter.ToLinearRgb(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(0, 0.1492062, 0, 0.3, 0.6, 0.1067051)] - public void Convert_LinearRgb_to_CieXyy(float r, float g, float b, float x, float y, float yl) - { - // Arrange - var input = new LinearRgb(r, g, b); - var expected = new CieXyy(x, y, yl); - - Span inputSpan = new LinearRgb[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieXyy[5]; - - // Act - var actual = Converter.ToCieXyy(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndLmsConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndLmsConversionTests.cs deleted file mode 100644 index 8e9cbc5ffc..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndLmsConversionTests.cs +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -public class CieXyyAndLmsConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(0.360555, 0.936901, 0.1001514, 0.06631134, 0.1415282, -0.03809926)] - public void Convert_CieXyy_to_Lms(float x, float y, float yl, float l, float m, float s) - { - // Arrange - var input = new CieXyy(x, y, yl); - var expected = new Lms(l, m, s); - - Span inputSpan = new CieXyy[5]; - inputSpan.Fill(input); - - Span actualSpan = new Lms[5]; - - // Act - var actual = Converter.ToLms(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(0.06631134, 0.1415282, -0.03809926, 0.360555, 0.9369009, 0.1001514)] - public void Convert_Lms_to_CieXyy(float l, float m, float s, float x, float y, float yl) - { - // Arrange - var input = new Lms(l, m, s); - var expected = new CieXyy(x, y, yl); - - Span inputSpan = new Lms[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieXyy[5]; - - // Act - CieXyy actual = Converter.ToCieXyy(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndRgbConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndRgbConversionTests.cs deleted file mode 100644 index 0a7cd68429..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndRgbConversionTests.cs +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -public class CieXyyAndRgbConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(0.360555, 0.936901, 0.1001514, 0, 0.4225259, 0)] - public void Convert_CieXyy_to_Rgb(float x, float y, float yl, float r, float g, float b) - { - // Arrange - var input = new CieXyy(x, y, yl); - var expected = new Rgb(r, g, b); - - Span inputSpan = new CieXyy[5]; - inputSpan.Fill(input); - - Span actualSpan = new Rgb[5]; - - // Act - var actual = Converter.ToRgb(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(0, 0.4225259, 0, 0.3, 0.6, 0.1067051)] - public void Convert_Rgb_to_CieXyy(float r, float g, float b, float x, float y, float yl) - { - // Arrange - var input = new Rgb(r, g, b); - var expected = new CieXyy(x, y, yl); - - Span inputSpan = new Rgb[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieXyy[5]; - - // Act - CieXyy actual = Converter.ToCieXyy(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndYCbCrConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndYCbCrConversionTests.cs deleted file mode 100644 index efacebcf19..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndYCbCrConversionTests.cs +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -public class CieXyyAndYCbCrConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 128, 128)] - [InlineData(0.360555, 0.936901, 0.1001514, 63.24579, 92.30826, 82.88884)] - public void Convert_CieXyy_to_YCbCr(float x, float y, float yl, float y2, float cb, float cr) - { - // Arrange - var input = new CieXyy(x, y, yl); - var expected = new YCbCr(y2, cb, cr); - - Span inputSpan = new CieXyy[5]; - inputSpan.Fill(input); - - Span actualSpan = new YCbCr[5]; - - // Act - var actual = Converter.ToYCbCr(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 128, 128, 0, 0, 0)] - [InlineData(63.24579, 92.30826, 82.88884, 0.3, 0.6, 0.1072441)] - public void Convert_YCbCr_to_CieXyy(float y2, float cb, float cr, float x, float y, float yl) - { - // Arrange - var input = new YCbCr(y2, cb, cr); - var expected = new CieXyy(x, y, yl); - - Span inputSpan = new YCbCr[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieXyy[5]; - - // Act - CieXyy actual = Converter.ToCieXyy(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLchConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLchConversionTests.cs deleted file mode 100644 index 698c9add60..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLchConversionTests.cs +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -public class CieXyzAndCieLchConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0.360555, 0.936901, 0.1001514, 97.50815, 155.8035, 139.323)] - public void Convert_CieXyz_to_CieLch(float x, float y, float yl, float l, float c, float h) - { - // Arrange - var input = new CieXyz(x, y, yl); - var expected = new CieLch(l, c, h); - - Span inputSpan = new CieXyz[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieLch[5]; - - // Act - var actual = Converter.ToCieLch(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(97.50815, 155.8035, 139.323, 0.3605551, 0.936901, 0.1001514)] - public void Convert_CieLch_to_CieXyz(float l, float c, float h, float x, float y, float yl) - { - // Arrange - var input = new CieLch(l, c, h); - var expected = new CieXyz(x, y, yl); - - Span inputSpan = new CieLch[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieXyz[5]; - - // Act - CieXyz actual = Converter.ToCieXyz(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLchuvConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLchuvConversionTests.cs deleted file mode 100644 index a4caf4c857..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLchuvConversionTests.cs +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -public class CieXyzAndCieLchuvConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0.360555, 0.936901, 0.1001514, 97.50697, 183.3831, 133.6321)] - public void Convert_CieXyz_to_CieLchuv(float x, float y, float yl, float l, float c, float h) - { - // Arrange - var input = new CieXyz(x, y, yl); - var expected = new CieLchuv(l, c, h); - - Span inputSpan = new CieXyz[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieLchuv[5]; - - // Act - var actual = Converter.ToCieLchuv(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(97.50697, 183.3831, 133.6321, 0.360555, 0.936901, 0.1001515)] - public void Convert_CieLchuv_to_CieXyz(float l, float c, float h, float x, float y, float yl) - { - // Arrange - var input = new CieLchuv(l, c, h); - var expected = new CieXyz(x, y, yl); - - Span inputSpan = new CieLchuv[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieXyz[5]; - - // Act - CieXyz actual = Converter.ToCieXyz(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLuvConversionTest.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLuvConversionTest.cs deleted file mode 100644 index 9e3381b40d..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLuvConversionTest.cs +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -/// -/// Test data generated using: -/// -/// -public class CieXyzAndCieLuvConversionTest -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0001F); - - /// - /// Tests conversion from to (). - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(0, 100, 50, 0, 0, 0)] - [InlineData(0.1, 100, 50, 0.000493, 0.000111, 0)] - [InlineData(70.0000, 86.3525, 2.8240, 0.569310, 0.407494, 0.365843)] - [InlineData(10.0000, -1.2345, -10.0000, 0.012191, 0.011260, 0.025939)] - [InlineData(100, 0, 0, 0.950470, 1.000000, 1.088830)] - [InlineData(1, 1, 1, 0.001255, 0.001107, 0.000137)] - public void Convert_Luv_to_Xyz(float l, float u, float v, float x, float y, float z) - { - // Arrange - var input = new CieLuv(l, u, v, Illuminants.D65); - var options = new ColorSpaceConverterOptions { WhitePoint = Illuminants.D65, TargetLabWhitePoint = Illuminants.D65 }; - var converter = new ColorSpaceConverter(options); - var expected = new CieXyz(x, y, z); - - Span inputSpan = new CieLuv[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieXyz[5]; - - // Act - var actual = converter.ToCieXyz(input); - converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from () to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(0.000493, 0.000111, 0, 0.1003, 0.9332, -0.0070)] - [InlineData(0.569310, 0.407494, 0.365843, 70.0000, 86.3524, 2.8240)] - [InlineData(0.012191, 0.011260, 0.025939, 9.9998, -1.2343, -9.9999)] - [InlineData(0.950470, 1.000000, 1.088830, 100, 0, 0)] - [InlineData(0.001255, 0.001107, 0.000137, 0.9999, 0.9998, 1.0004)] - public void Convert_Xyz_to_Luv(float x, float y, float z, float l, float u, float v) - { - // Arrange - var input = new CieXyz(x, y, z); - var options = new ColorSpaceConverterOptions { WhitePoint = Illuminants.D65, TargetLabWhitePoint = Illuminants.D65 }; - var converter = new ColorSpaceConverter(options); - var expected = new CieLuv(l, u, v); - - Span inputSpan = new CieXyz[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieLuv[5]; - - // Act - var actual = converter.ToCieLuv(input); - converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndHslConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndHslConversionTests.cs deleted file mode 100644 index 634d03a502..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndHslConversionTests.cs +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -public class CieXyzAndHslConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(0.360555, 0.936901, 0.1001514, 120, 1, 0.5)] - public void Convert_CieXyz_to_Hsl(float x, float y, float yl, float h, float s, float l) - { - // Arrange - var input = new CieXyz(x, y, yl); - var expected = new Hsl(h, s, l); - - Span inputSpan = new CieXyz[5]; - inputSpan.Fill(input); - - Span actualSpan = new Hsl[5]; - - // Act - var actual = Converter.ToHsl(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(120, 1, 0.5, 0.3575761, 0.7151522, 0.119192)] - public void Convert_Hsl_to_CieXyz(float h, float s, float l, float x, float y, float yl) - { - // Arrange - var input = new Hsl(h, s, l); - var expected = new CieXyz(x, y, yl); - - Span inputSpan = new Hsl[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieXyz[5]; - - // Act - var actual = Converter.ToCieXyz(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndHsvConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndHsvConversionTests.cs deleted file mode 100644 index ccedd7b755..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndHsvConversionTests.cs +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -public class CieXyzAndHsvConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(0.360555, 0.936901, 0.1001514, 120, 1, 0.9999999)] - public void Convert_CieXyz_to_Hsv(float x, float y, float yl, float h, float s, float v) - { - // Arrange - var input = new CieXyz(x, y, yl); - var expected = new Hsv(h, s, v); - - Span inputSpan = new CieXyz[5]; - inputSpan.Fill(input); - - Span actualSpan = new Hsv[5]; - - // Act - var actual = Converter.ToHsv(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(120, 1, 0.9999999, 0.3575761, 0.7151522, 0.119192)] - public void Convert_Hsv_to_CieXyz(float h, float s, float v, float x, float y, float yl) - { - // Arrange - var input = new Hsv(h, s, v); - var expected = new CieXyz(x, y, yl); - - Span inputSpan = new Hsv[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieXyz[5]; - - // Act - CieXyz actual = Converter.ToCieXyz(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndHunterLabConversionTest.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndHunterLabConversionTest.cs deleted file mode 100644 index af7087ba23..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndHunterLabConversionTest.cs +++ /dev/null @@ -1,115 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -/// -/// Test data generated using: -/// -/// -public class CieXyzAndHunterLabConversionTest -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0001F); - - /// - /// Tests conversion from to (). - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(100, 0, 0, 0.98074, 1, 1.18232)] // C white point is HunterLab 100, 0, 0 - public void Convert_HunterLab_to_Xyz(float l, float a, float b, float x, float y, float z) - { - // Arrange - var input = new HunterLab(l, a, b); - var options = new ColorSpaceConverterOptions { WhitePoint = Illuminants.C }; - var converter = new ColorSpaceConverter(options); - var expected = new CieXyz(x, y, z); - - Span inputSpan = new HunterLab[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieXyz[5]; - - // Act - var actual = converter.ToCieXyz(input); - converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to (). - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(100, 0, 0, 0.95047, 1, 1.08883)] // D65 white point is HunerLab 100, 0, 0 (adaptation to C performed) - public void Convert_HunterLab_to_Xyz_D65(float l, float a, float b, float x, float y, float z) - { - // Arrange - var input = new HunterLab(l, a, b); - var options = new ColorSpaceConverterOptions { WhitePoint = Illuminants.D65 }; - var converter = new ColorSpaceConverter(options); - var expected = new CieXyz(x, y, z); - - Span inputSpan = new HunterLab[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieXyz[5]; - - // Act - var actual = converter.ToCieXyz(input); - converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from () to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(0.95047, 1, 1.08883, 100, 0, 0)] // D65 white point is HunterLab 100, 0, 0 (adaptation to C performed) - public void Convert_Xyz_D65_to_HunterLab(float x, float y, float z, float l, float a, float b) - { - // Arrange - var input = new CieXyz(x, y, z); - var options = new ColorSpaceConverterOptions { WhitePoint = Illuminants.D65 }; - var converter = new ColorSpaceConverter(options); - var expected = new HunterLab(l, a, b); - - Span inputSpan = new CieXyz[5]; - inputSpan.Fill(input); - - Span actualSpan = new HunterLab[5]; - - // Act - var actual = converter.ToHunterLab(input); - converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndYCbCrConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndYCbCrConversionTests.cs deleted file mode 100644 index ba67e605a6..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndYCbCrConversionTests.cs +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -public class CieXyzAndYCbCrConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 128, 128)] - [InlineData(0.360555, 0.936901, 0.1001514, 149.685, 43.52769, 21.23457)] - public void Convert_CieXyz_to_YCbCr(float x, float y, float z, float y2, float cb, float cr) - { - // Arrange - var input = new CieXyz(x, y, z); - var expected = new YCbCr(y2, cb, cr); - - Span inputSpan = new CieXyz[5]; - inputSpan.Fill(input); - - Span actualSpan = new YCbCr[5]; - - // Act - var actual = Converter.ToYCbCr(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 128, 128, 0, 0, 0)] - [InlineData(149.685, 43.52769, 21.23457, 0.3575761, 0.7151522, 0.119192)] - public void Convert_YCbCr_to_CieXyz(float y2, float cb, float cr, float x, float y, float z) - { - // Arrange - var input = new YCbCr(y2, cb, cr); - var expected = new CieXyz(x, y, z); - - Span inputSpan = new YCbCr[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieXyz[5]; - - // Act - CieXyz actual = Converter.ToCieXyz(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieLchConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieLchConversionTests.cs deleted file mode 100644 index 9def3e1b20..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieLchConversionTests.cs +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -public class CmykAndCieLchConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0.360555, 0.1036901, 0.818514, 0.274615, 62.85025, 64.77041, 118.2425)] - public void Convert_Cmyk_to_CieLch(float c, float m, float y, float k, float l, float c2, float h) - { - // Arrange - var input = new Cmyk(c, m, y, k); - var expected = new CieLch(l, c2, h); - - Span inputSpan = new Cmyk[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieLch[5]; - - // Act - var actual = Converter.ToCieLch(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(100, 3.81656E-05, 218.6598, 0, 1.192093E-07, 0, 5.960464E-08)] - [InlineData(62.85025, 64.77041, 118.2425, 0.286581, 0, 0.7975187, 0.34983)] - public void Convert_CieLch_to_Cmyk(float l, float c2, float h, float c, float m, float y, float k) - { - // Arrange - var input = new CieLch(l, c2, h); - var expected = new Cmyk(c, m, y, k); - - Span inputSpan = new CieLch[5]; - inputSpan.Fill(input); - - Span actualSpan = new Cmyk[5]; - - // Act - var actual = Converter.ToCmyk(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieLuvConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieLuvConversionTests.cs deleted file mode 100644 index 9ae0fb7119..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieLuvConversionTests.cs +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -public class CmykAndCieLuvConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 100, -1.937151E-05, 0)] - [InlineData(0.360555, 0.1036901, 0.818514, 0.274615, 62.66017, -24.01712, 68.29556)] - public void Convert_Cmyk_to_CieLuv(float c, float m, float y, float k, float l, float u, float v) - { - // Arrange - var input = new Cmyk(c, m, y, k); - var expected = new CieLuv(l, u, v); - - Span inputSpan = new Cmyk[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieLuv[5]; - - // Act - var actual = Converter.ToCieLuv(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(100, -1.937151E-05, 0, 3.576279E-07, 0, 0, 5.960464E-08)] - [InlineData(62.66017, -24.01712, 68.29556, 0.2865804, 0, 0.7975189, 0.3498302)] - public void Convert_CieLuv_to_Cmyk(float l, float u, float v, float c, float m, float y, float k) - { - // Arrange - var input = new CieLuv(l, u, v); - var expected = new Cmyk(c, m, y, k); - - Span inputSpan = new CieLuv[5]; - inputSpan.Fill(input); - - Span actualSpan = new Cmyk[5]; - - // Act - var actual = Converter.ToCmyk(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieXyyConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieXyyConversionTests.cs deleted file mode 100644 index 270db9d205..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieXyyConversionTests.cs +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -public class CmykAndCieXyyConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0.3127266, 0.3290231, 1)] - [InlineData(0.360555, 0.1036901, 0.818514, 0.274615, 0.3628971, 0.5289949, 0.3118104)] - public void Convert_Cmyk_to_CieXyy(float c, float m, float y, float k, float x, float y2, float yl) - { - // Arrange - var input = new Cmyk(c, m, y, k); - var expected = new CieXyy(x, y2, yl); - - Span inputSpan = new Cmyk[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieXyy[5]; - - // Act - var actual = Converter.ToCieXyy(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0.3127266, 0.3290231, 1, 0, 0, 0, 5.960464E-08)] - [InlineData(0.3628971, 0.5289949, 0.3118104, 0.2865805, 0, 0.7975187, 0.3498302)] - public void Convert_CieXyy_to_Cmyk(float x, float y2, float yl, float c, float m, float y, float k) - { - // Arrange - var input = new CieXyy(x, y2, yl); - var expected = new Cmyk(c, m, y, k); - - Span inputSpan = new CieXyy[5]; - inputSpan.Fill(input); - - Span actualSpan = new Cmyk[5]; - - // Act - var actual = Converter.ToCmyk(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieXyzConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieXyzConversionTests.cs deleted file mode 100644 index 972948c71d..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieXyzConversionTests.cs +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -public class CmykAndCieXyzConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0.9504699, 1, 1.08883)] - [InlineData(0.360555, 0.1036901, 0.818514, 0.274615, 0.2139058, 0.3118104, 0.0637231)] - public void Convert_Cmyk_to_CieXyz(float c, float m, float y, float k, float x, float y2, float z) - { - // Arrange - var input = new Cmyk(c, m, y, k); - var expected = new CieXyz(x, y2, z); - - Span inputSpan = new Cmyk[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieXyz[5]; - - // Act - var actual = Converter.ToCieXyz(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0.9504699, 1, 1.08883, 1.192093E-07, 0, 0, 5.960464E-08)] - [InlineData(0.2139058, 0.3118104, 0.0637231, 0.2865805, 0, 0.7975187, 0.3498302)] - public void Convert_CieXyz_to_Cmyk(float x, float y2, float z, float c, float m, float y, float k) - { - // Arrange - var input = new CieXyz(x, y2, z); - var expected = new Cmyk(c, m, y, k); - - Span inputSpan = new CieXyz[5]; - inputSpan.Fill(input); - - Span actualSpan = new Cmyk[5]; - - // Act - var actual = Converter.ToCmyk(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndHslConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndHslConversionTests.cs deleted file mode 100644 index 2b00942aca..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndHslConversionTests.cs +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -public class CmykAndHslConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0, 1)] - [InlineData(0.360555, 0.1036901, 0.818514, 0.274615, 81.56041, 0.6632275, 0.3909085)] - public void Convert_Cmyk_to_Hsl(float c, float m, float y, float k, float h, float s, float l) - { - // Arrange - var input = new Cmyk(c, m, y, k); - var expected = new Hsl(h, s, l); - - Span inputSpan = new Cmyk[5]; - inputSpan.Fill(input); - - Span actualSpan = new Hsl[5]; - - // Act - var actual = ColorSpaceConverter.ToHsl(input); - ColorSpaceConverter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 1, 0, 0, 0, 0)] - [InlineData(81.56041, 0.6632275, 0.3909085, 0.2865805, 0, 0.7975187, 0.3498302)] - public void Convert_Hsl_to_Cmyk(float h, float s, float l, float c, float m, float y, float k) - { - // Arrange - var input = new Hsl(h, s, l); - var expected = new Cmyk(c, m, y, k); - - Span inputSpan = new Hsl[5]; - inputSpan.Fill(input); - - Span actualSpan = new Cmyk[5]; - - // Act - var actual = ColorSpaceConverter.ToCmyk(input); - ColorSpaceConverter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndHsvConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndHsvConversionTests.cs deleted file mode 100644 index f158fb5f9e..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndHsvConversionTests.cs +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -public class CmykAndHsvConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0, 1)] - [InlineData(0.360555, 0.1036901, 0.818514, 0.274615, 81.56041, 0.7975187, 0.6501698)] - public void Convert_Cmyk_to_Hsv(float c, float m, float y, float k, float h, float s, float v) - { - // Arrange - var input = new Cmyk(c, m, y, k); - var expected = new Hsv(h, s, v); - - Span inputSpan = new Cmyk[5]; - inputSpan.Fill(input); - - Span actualSpan = new Hsv[5]; - - // Act - var actual = ColorSpaceConverter.ToHsv(input); - ColorSpaceConverter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 1, 0, 0, 0, 0)] - [InlineData(81.56041, 0.7975187, 0.6501698, 0.2865805, 0, 0.7975187, 0.3498302)] - public void Convert_Hsv_to_Cmyk(float h, float s, float v, float c, float m, float y, float k) - { - // Arrange - var input = new Hsv(h, s, v); - var expected = new Cmyk(c, m, y, k); - - Span inputSpan = new Hsv[5]; - inputSpan.Fill(input); - - Span actualSpan = new Cmyk[5]; - - // Act - var actual = ColorSpaceConverter.ToCmyk(input); - ColorSpaceConverter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndHunterLabConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndHunterLabConversionTests.cs deleted file mode 100644 index 9832a0d715..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndHunterLabConversionTests.cs +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -public class CmykAndHunterLabConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 99.99999, 0, -1.66893E-05)] - [InlineData(0.360555, 0.1036901, 0.818514, 0.274615, 55.66742, -27.21679, 31.73834)] - public void Convert_Cmyk_to_HunterLab(float c, float m, float y, float k, float l, float a, float b) - { - // Arrange - var input = new Cmyk(c, m, y, k); - var expected = new HunterLab(l, a, b); - - Span inputSpan = new Cmyk[5]; - inputSpan.Fill(input); - - Span actualSpan = new HunterLab[5]; - - // Act - var actual = Converter.ToHunterLab(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(99.99999, 0, -1.66893E-05, 1.192093E-07, 1.192093E-07, 0, 5.960464E-08)] - [InlineData(55.66742, -27.21679, 31.73834, 0.2865806, 0, 0.7975186, 0.3498301)] - public void Convert_HunterLab_to_Cmyk(float l, float a, float b, float c, float m, float y, float k) - { - // Arrange - var input = new HunterLab(l, a, b); - var expected = new Cmyk(c, m, y, k); - - Span inputSpan = new HunterLab[5]; - inputSpan.Fill(input); - - Span actualSpan = new Cmyk[5]; - - // Act - var actual = Converter.ToCmyk(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndYCbCrConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndYCbCrConversionTests.cs deleted file mode 100644 index 1e8bc52e2f..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndYCbCrConversionTests.cs +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -public class CmykAndYCbCrConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 255, 128, 128)] - [InlineData(0.360555, 0.1036901, 0.818514, 0.274615, 136.5134, 69.90555, 114.9948)] - public void Convert_Cmyk_to_YCbCr(float c, float m, float y, float k, float y2, float cb, float cr) - { - // Arrange - var input = new Cmyk(c, m, y, k); - var expected = new YCbCr(y2, cb, cr); - - Span inputSpan = new Cmyk[5]; - inputSpan.Fill(input); - - Span actualSpan = new YCbCr[5]; - - // Act - var actual = ColorSpaceConverter.ToYCbCr(input); - ColorSpaceConverter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(255, 128, 128, 0, 0, 0, 5.960464E-08)] - [InlineData(136.5134, 69.90555, 114.9948, 0.2891567, 0, 0.7951807, 0.3490196)] - public void Convert_YCbCr_to_Cmyk(float y2, float cb, float cr, float c, float m, float y, float k) - { - // Arrange - var input = new YCbCr(y2, cb, cr); - var expected = new Cmyk(c, m, y, k); - - Span inputSpan = new YCbCr[5]; - inputSpan.Fill(input); - - Span actualSpan = new Cmyk[5]; - - // Act - var actual = Converter.ToCmyk(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/ColorConverterAdaptTest.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/ColorConverterAdaptTest.cs deleted file mode 100644 index bbebf96b32..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/ColorConverterAdaptTest.cs +++ /dev/null @@ -1,178 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests methods. -/// Test data generated using: -/// -/// -/// -public class ColorConverterAdaptTest -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0001F); - - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(1, 1, 1, 1, 1, 1)] - [InlineData(0.206162, 0.260277, 0.746717, 0.220000, 0.130000, 0.780000)] - public void Adapt_RGB_WideGamutRGB_To_sRGB(float r1, float g1, float b1, float r2, float g2, float b2) - { - // Arrange - var input = new Rgb(r1, g1, b1, RgbWorkingSpaces.WideGamutRgb); - var expected = new Rgb(r2, g2, b2, RgbWorkingSpaces.SRgb); - var options = new ColorSpaceConverterOptions { TargetRgbWorkingSpace = RgbWorkingSpaces.SRgb }; - var converter = new ColorSpaceConverter(options); - - // Action - Rgb actual = converter.Adapt(input); - - // Assert - Assert.Equal(expected.WorkingSpace, actual.WorkingSpace, ColorSpaceComparer); - Assert.Equal(expected, actual, ColorSpaceComparer); - } - - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(1, 1, 1, 1, 1, 1)] - [InlineData(0.220000, 0.130000, 0.780000, 0.206162, 0.260277, 0.746717)] - public void Adapt_RGB_SRGB_To_WideGamutRGB(float r1, float g1, float b1, float r2, float g2, float b2) - { - // Arrange - var input = new Rgb(r1, g1, b1, RgbWorkingSpaces.SRgb); - var expected = new Rgb(r2, g2, b2, RgbWorkingSpaces.WideGamutRgb); - var options = new ColorSpaceConverterOptions { TargetRgbWorkingSpace = RgbWorkingSpaces.WideGamutRgb }; - var converter = new ColorSpaceConverter(options); - - // Action - Rgb actual = converter.Adapt(input); - - // Assert - Assert.Equal(expected.WorkingSpace, actual.WorkingSpace, ColorSpaceComparer); - Assert.Equal(expected, actual, ColorSpaceComparer); - } - - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(22, 33, 1, 22.269869, 32.841164, 1.633926)] - public void Adapt_Lab_D65_To_D50(float l1, float a1, float b1, float l2, float a2, float b2) - { - // Arrange - var input = new CieLab(l1, a1, b1, Illuminants.D65); - var expected = new CieLab(l2, a2, b2); - var options = new ColorSpaceConverterOptions { TargetLabWhitePoint = Illuminants.D50 }; - var converter = new ColorSpaceConverter(options); - - // Action - CieLab actual = converter.Adapt(input); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - } - - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(0.5, 0.5, 0.5, 0.510286, 0.501489, 0.378970)] - public void Adapt_Xyz_D65_To_D50_Bradford(float x1, float y1, float z1, float x2, float y2, float z2) - { - // Arrange - var input = new CieXyz(x1, y1, z1); - var expected = new CieXyz(x2, y2, z2); - var options = new ColorSpaceConverterOptions { WhitePoint = Illuminants.D50 }; - var converter = new ColorSpaceConverter(options); - - // Action - CieXyz actual = converter.Adapt(input, Illuminants.D65); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - } - - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(0.5, 0.5, 0.5, 0.507233, 0.500000, 0.378943)] - public void Adapt_Xyz_D65_To_D50_XyzScaling(float x1, float y1, float z1, float x2, float y2, float z2) - { - // Arrange - var input = new CieXyz(x1, y1, z1); - var expected = new CieXyz(x2, y2, z2); - var options = new ColorSpaceConverterOptions - { - ChromaticAdaptation = new VonKriesChromaticAdaptation(LmsAdaptationMatrix.XyzScaling), - WhitePoint = Illuminants.D50 - }; - - var converter = new ColorSpaceConverter(options); - - // Action - CieXyz actual = converter.Adapt(input, Illuminants.D65); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - } - - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(22, 33, 1, 22.1090755, 32.2102661, 1.153463)] - public void Adapt_HunterLab_D65_To_D50(float l1, float a1, float b1, float l2, float a2, float b2) - { - // Arrange - var input = new HunterLab(l1, a1, b1, Illuminants.D65); - var expected = new HunterLab(l2, a2, b2); - var options = new ColorSpaceConverterOptions { TargetLabWhitePoint = Illuminants.D50 }; - var converter = new ColorSpaceConverter(options); - - // Action - HunterLab actual = converter.Adapt(input); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - } - - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(22, 33, 1, 22, 33, 0.9999999)] - public void Adapt_CieLchuv_D65_To_D50_XyzScaling(float l1, float c1, float h1, float l2, float c2, float h2) - { - // Arrange - var input = new CieLchuv(l1, c1, h1, Illuminants.D65); - var expected = new CieLchuv(l2, c2, h2); - var options = new ColorSpaceConverterOptions - { - ChromaticAdaptation = new VonKriesChromaticAdaptation(LmsAdaptationMatrix.XyzScaling), - TargetLabWhitePoint = Illuminants.D50 - }; - var converter = new ColorSpaceConverter(options); - - // Action - CieLchuv actual = converter.Adapt(input); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - } - - [Theory] - [InlineData(22, 33, 1, 22, 33, 0.9999999)] - public void Adapt_CieLch_D65_To_D50_XyzScaling(float l1, float c1, float h1, float l2, float c2, float h2) - { - // Arrange - var input = new CieLch(l1, c1, h1, Illuminants.D65); - var expected = new CieLch(l2, c2, h2); - var options = new ColorSpaceConverterOptions - { - ChromaticAdaptation = new VonKriesChromaticAdaptation(LmsAdaptationMatrix.XyzScaling), - TargetLabWhitePoint = Illuminants.D50 - }; - var converter = new ColorSpaceConverter(options); - - // Action - CieLch actual = converter.Adapt(input); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndCieXyzConversionTest.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndCieXyzConversionTest.cs deleted file mode 100644 index 0119f4f3a4..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndCieXyzConversionTest.cs +++ /dev/null @@ -1,170 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -/// -/// Test data generated using: -/// -/// -public class RgbAndCieXyzConversionTest -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0001F); - - /// - /// Tests conversion from () - /// to (default sRGB working space). - /// - [Theory] - [InlineData(0.96422, 1.00000, 0.82521, 1, 1, 1)] - [InlineData(0.00000, 1.00000, 0.00000, 0, 1, 0)] - [InlineData(0.96422, 0.00000, 0.00000, 1, 0, 0.292064)] - [InlineData(0.00000, 0.00000, 0.82521, 0, 0.181415, 1)] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(0.297676, 0.267854, 0.045504, 0.720315, 0.509999, 0.168112)] - public void Convert_XYZ_D50_to_SRGB(float x, float y, float z, float r, float g, float b) - { - // Arrange - var input = new CieXyz(x, y, z); - var options = new ColorSpaceConverterOptions { WhitePoint = Illuminants.D50, TargetRgbWorkingSpace = RgbWorkingSpaces.SRgb }; - var converter = new ColorSpaceConverter(options); - var expected = new Rgb(r, g, b); - - Span inputSpan = new CieXyz[5]; - inputSpan.Fill(input); - - Span actualSpan = new Rgb[5]; - - // Act - var actual = converter.ToRgb(input); - converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(Rgb.DefaultWorkingSpace, actual.WorkingSpace, ColorSpaceComparer); - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion - /// from () - /// to (default sRGB working space). - /// - [Theory] - [InlineData(0.950470, 1.000000, 1.088830, 1, 1, 1)] - [InlineData(0, 1.000000, 0, 0, 1, 0)] - [InlineData(0.950470, 0, 0, 1, 0, 0.254967)] - [InlineData(0, 0, 1.088830, 0, 0.235458, 1)] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(0.297676, 0.267854, 0.045504, 0.754903, 0.501961, 0.099998)] - public void Convert_XYZ_D65_to_SRGB(float x, float y, float z, float r, float g, float b) - { - // Arrange - var input = new CieXyz(x, y, z); - var options = new ColorSpaceConverterOptions { WhitePoint = Illuminants.D65, TargetRgbWorkingSpace = RgbWorkingSpaces.SRgb }; - var converter = new ColorSpaceConverter(options); - var expected = new Rgb(r, g, b); - - Span inputSpan = new CieXyz[5]; - inputSpan.Fill(input); - - Span actualSpan = new Rgb[5]; - - // Act - var actual = converter.ToRgb(input); - converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(Rgb.DefaultWorkingSpace, actual.WorkingSpace, ColorSpaceComparer); - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from (default sRGB working space) - /// to (). - /// - [Theory] - [InlineData(1, 1, 1, 0.964220, 1.000000, 0.825210)] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(1, 0, 0, 0.436075, 0.222504, 0.013932)] - [InlineData(0, 1, 0, 0.385065, 0.716879, 0.0971045)] - [InlineData(0, 0, 1, 0.143080, 0.060617, 0.714173)] - [InlineData(0.754902, 0.501961, 0.100000, 0.315757, 0.273323, 0.035506)] - public void Convert_SRGB_to_XYZ_D50(float r, float g, float b, float x, float y, float z) - { - // Arrange - var input = new Rgb(r, g, b); - var options = new ColorSpaceConverterOptions { WhitePoint = Illuminants.D50 }; - var converter = new ColorSpaceConverter(options); - var expected = new CieXyz(x, y, z); - - Span inputSpan = new Rgb[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieXyz[5]; - - // Act - var actual = converter.ToCieXyz(input); - converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from (default sRGB working space) - /// to (). - /// - [Theory] - [InlineData(1, 1, 1, 0.950470, 1.000000, 1.088830)] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(1, 0, 0, 0.412456, 0.212673, 0.019334)] - [InlineData(0, 1, 0, 0.357576, 0.715152, 0.119192)] - [InlineData(0, 0, 1, 0.1804375, 0.072175, 0.950304)] - [InlineData(0.754902, 0.501961, 0.100000, 0.297676, 0.267854, 0.045504)] - public void Convert_SRGB_to_XYZ_D65(float r, float g, float b, float x, float y, float z) - { - // Arrange - var input = new Rgb(r, g, b); - var options = new ColorSpaceConverterOptions { WhitePoint = Illuminants.D65 }; - var converter = new ColorSpaceConverter(options); - var expected = new CieXyz(x, y, z); - - Span inputSpan = new Rgb[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieXyz[5]; - - // Act - var actual = converter.ToCieXyz(input); - converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndYCbCrConversionTest.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndYCbCrConversionTest.cs deleted file mode 100644 index eb4eb0bbff..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndYCbCrConversionTest.cs +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -/// -/// Test data generated mathematically -/// -public class RgbAndYCbCrConversionTest -{ - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.001F); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(255, 128, 128, 1, 1, 1)] - [InlineData(0, 128, 128, 0, 0, 0)] - [InlineData(128, 128, 128, 0.502, 0.502, 0.502)] - public void Convert_YCbCr_To_Rgb(float y, float cb, float cr, float r, float g, float b) - { - // Arrange - var input = new YCbCr(y, cb, cr); - var expected = new Rgb(r, g, b); - - Span inputSpan = new YCbCr[5]; - inputSpan.Fill(input); - - Span actualSpan = new Rgb[5]; - - // Act - var actual = Converter.ToRgb(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(Rgb.DefaultWorkingSpace, actual.WorkingSpace, ColorSpaceComparer); - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 128, 128)] - [InlineData(1, 1, 1, 255, 128, 128)] - [InlineData(0.5, 0.5, 0.5, 127.5, 128, 128)] - [InlineData(1, 0, 0, 76.245, 84.972, 255)] - public void Convert_Rgb_To_YCbCr(float r, float g, float b, float y, float cb, float cr) - { - // Arrange - var input = new Rgb(r, g, b); - var expected = new YCbCr(y, cb, cr); - - Span inputSpan = new Rgb[5]; - inputSpan.Fill(input); - - Span actualSpan = new YCbCr[5]; - - // Act - var actual = ColorSpaceConverter.ToYCbCr(input); - ColorSpaceConverter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/VonKriesChromaticAdaptationTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/VonKriesChromaticAdaptationTests.cs deleted file mode 100644 index 9e33ad1689..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/VonKriesChromaticAdaptationTests.cs +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -public class VonKriesChromaticAdaptationTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0001F); - public static readonly TheoryData WhitePoints = new TheoryData - { - { CieLuv.DefaultWhitePoint, CieLab.DefaultWhitePoint }, - { CieLuv.DefaultWhitePoint, CieLuv.DefaultWhitePoint } - }; - - [Theory] - [MemberData(nameof(WhitePoints))] - public void SingleAndBulkTransformYieldIdenticalResults(CieXyz sourceWhitePoint, CieXyz destinationWhitePoint) - { - var adaptation = new VonKriesChromaticAdaptation(); - var input = new CieXyz(1, 0, 1); - CieXyz expected = adaptation.Transform(input, sourceWhitePoint, destinationWhitePoint); - - Span inputSpan = new CieXyz[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieXyz[5]; - - adaptation.Transform(inputSpan, actualSpan, sourceWhitePoint, destinationWhitePoint); - - for (int i = 0; i < inputSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/LinearRgbTests.cs b/tests/ImageSharp.Tests/Colorspaces/LinearRgbTests.cs deleted file mode 100644 index ff2d151344..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/LinearRgbTests.cs +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Numerics; -using SixLabors.ImageSharp.ColorSpaces; - -namespace SixLabors.ImageSharp.Tests.Colorspaces; - -/// -/// Tests the struct. -/// -public class LinearRgbTests -{ - [Fact] - public void LinearRgbConstructorAssignsFields() - { - const float r = .75F; - const float g = .64F; - const float b = .87F; - var rgb = new LinearRgb(r, g, b); - - Assert.Equal(r, rgb.R); - Assert.Equal(g, rgb.G); - Assert.Equal(b, rgb.B); - } - - [Fact] - public void LinearRgbEquality() - { - var x = default(LinearRgb); - var y = new LinearRgb(Vector3.One); - - Assert.True(default(LinearRgb) == default(LinearRgb)); - Assert.False(default(LinearRgb) != default(LinearRgb)); - Assert.Equal(default(LinearRgb), default(LinearRgb)); - Assert.Equal(new LinearRgb(1, 0, 1), new LinearRgb(1, 0, 1)); - Assert.Equal(new LinearRgb(Vector3.One), new LinearRgb(Vector3.One)); - Assert.False(x.Equals(y)); - Assert.False(x.Equals((object)y)); - Assert.False(x.GetHashCode().Equals(y.GetHashCode())); - } -} diff --git a/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs b/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs index 3e8e171645..36b3012640 100644 --- a/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs +++ b/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs @@ -3,6 +3,7 @@ using System.Numerics; using System.Runtime.CompilerServices; +using System.Runtime.Intrinsics.Arm; using System.Runtime.Intrinsics.X86; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Tests.TestUtilities; @@ -26,7 +27,7 @@ public partial class SimdUtilsTests [InlineData(5.3, 536.4, 4.5, 8.1)] public void PseudoRound(float x, float y, float z, float w) { - var v = new Vector4(x, y, z, w); + Vector4 v = new(x, y, z, w); Vector4 actual = v.PseudoRound(); @@ -57,7 +58,7 @@ private static Vector CreateRandomTestVector(int seed, float min, float m { float[] data = new float[Vector.Count]; - var rnd = new Random(seed); + Random rnd = new(seed); for (int i = 0; i < Vector.Count; i++) { @@ -112,26 +113,15 @@ private bool SkipOnNonAvx2([CallerMemberName] string testCaseName = null) 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 ArraySizesDivisibleBy64 = new() { 0, 64, 512 }; 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( - count, - (s, d) => SimdUtils.FallbackIntrinsics128.ByteToNormalizedFloat(s.Span, d.Span)); - - [Theory] - [MemberData(nameof(ArraySizesDivisibleBy32))] - public void ExtendedIntrinsics_BulkConvertByteToNormalizedFloat(int count) => TestImpl_BulkConvertByteToNormalizedFloat( - count, - (s, d) => SimdUtils.ExtendedIntrinsics.ByteToNormalizedFloat(s.Span, d.Span)); - - [Theory] - [MemberData(nameof(ArraySizesDivisibleBy32))] + [MemberData(nameof(ArraySizesDivisibleBy64))] public void HwIntrinsics_BulkConvertByteToNormalizedFloat(int count) { - if (!Sse2.IsSupported) + if (!Sse2.IsSupported && !AdvSimd.IsSupported) { return; } @@ -143,7 +133,7 @@ static void RunTest(string serialized) => TestImpl_BulkConvertByteToNormalizedFl FeatureTestRunner.RunWithHwIntrinsicsFeature( RunTest, count, - HwIntrinsics.AllowAll | HwIntrinsics.DisableAVX2 | HwIntrinsics.DisableSSE41); + HwIntrinsics.AllowAll | HwIntrinsics.DisableAVX512F | HwIntrinsics.DisableAVX2 | HwIntrinsics.DisableSSE41); } [Theory] @@ -166,43 +156,10 @@ private static void TestImpl_BulkConvertByteToNormalizedFloat( } [Theory] - [MemberData(nameof(ArraySizesDivisibleBy4))] - public void FallbackIntrinsics128_BulkConvertNormalizedFloatToByteClampOverflows(int count) => TestImpl_BulkConvertNormalizedFloatToByteClampOverflows( - count, - (s, d) => SimdUtils.FallbackIntrinsics128.NormalizedFloatToByteSaturate(s.Span, d.Span)); - - [Theory] - [MemberData(nameof(ArraySizesDivisibleBy32))] - public void ExtendedIntrinsics_BulkConvertNormalizedFloatToByteClampOverflows(int count) => TestImpl_BulkConvertNormalizedFloatToByteClampOverflows( - count, - (s, d) => SimdUtils.ExtendedIntrinsics.NormalizedFloatToByteSaturate(s.Span, d.Span)); - - [Theory] - [InlineData(1234)] - public void ExtendedIntrinsics_ConvertToSingle(short scale) - { - int n = Vector.Count; - short[] sData = new Random(scale).GenerateRandomInt16Array(2 * n, (short)-scale, scale); - float[] fData = sData.Select(u => (float)u).ToArray(); - - var source = new Vector(sData); - - var expected1 = new Vector(fData, 0); - var expected2 = new Vector(fData, n); - - // Act: - SimdUtils.ExtendedIntrinsics.ConvertToSingle(source, out Vector actual1, out Vector actual2); - - // Assert: - Assert.Equal(expected1, actual1); - Assert.Equal(expected2, actual2); - } - - [Theory] - [MemberData(nameof(ArraySizesDivisibleBy32))] + [MemberData(nameof(ArraySizesDivisibleBy64))] public void HwIntrinsics_BulkConvertNormalizedFloatToByteClampOverflows(int count) { - if (!Sse2.IsSupported) + if (!Sse2.IsSupported && !AdvSimd.IsSupported) { return; } @@ -214,7 +171,7 @@ static void RunTest(string serialized) => TestImpl_BulkConvertNormalizedFloatToB FeatureTestRunner.RunWithHwIntrinsicsFeature( RunTest, count, - HwIntrinsics.AllowAll | HwIntrinsics.DisableAVX2); + HwIntrinsics.AllowAll | HwIntrinsics.DisableAVX512BW | HwIntrinsics.DisableAVX2); } [Theory] @@ -262,7 +219,7 @@ public void PackFromRgbPlanesAvx2Reduce_Rgb24() 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; - var d = new Rgb24[32 + padding]; + Rgb24[] d = new Rgb24[32 + padding]; ReadOnlySpan rr = r.AsSpan(); ReadOnlySpan gg = g.AsSpan(); @@ -296,7 +253,7 @@ public void PackFromRgbPlanesAvx2Reduce_Rgba32() byte[] g = Enumerable.Range(100, 32).Select(x => (byte)x).ToArray(); byte[] b = Enumerable.Range(200, 32).Select(x => (byte)x).ToArray(); - var d = new Rgba32[32]; + Rgba32[] d = new Rgba32[32]; ReadOnlySpan rr = r.AsSpan(); ReadOnlySpan gg = g.AsSpan(); @@ -322,18 +279,18 @@ public void PackFromRgbPlanesAvx2Reduce_Rgba32() internal static void TestPackFromRgbPlanes(int count, Action packMethod) where TPixel : unmanaged, IPixel { - var rnd = new Random(42); + Random rnd = new(42); byte[] r = rnd.GenerateRandomByteArray(count); byte[] g = rnd.GenerateRandomByteArray(count); byte[] b = rnd.GenerateRandomByteArray(count); - var expected = new TPixel[count]; + TPixel[] expected = new TPixel[count]; for (int i = 0; i < count; i++) { - expected[i].FromRgb24(new Rgb24(r[i], g[i], b[i])); + expected[i] = TPixel.FromRgb24(new Rgb24(r[i], g[i], b[i])); } - var actual = new TPixel[count + 3]; // padding for Rgb24 AVX2 + TPixel[] actual = new TPixel[count + 3]; // padding for Rgb24 AVX2 packMethod(r, g, b, actual); Assert.True(expected.AsSpan().SequenceEqual(actual.AsSpan()[..count])); diff --git a/tests/ImageSharp.Tests/ConfigurationTests.cs b/tests/ImageSharp.Tests/ConfigurationTests.cs index c5d61726c8..c8e6cd2657 100644 --- a/tests/ImageSharp.Tests/ConfigurationTests.cs +++ b/tests/ImageSharp.Tests/ConfigurationTests.cs @@ -20,7 +20,7 @@ public class ConfigurationTests public Configuration DefaultConfiguration { get; } - private readonly int expectedDefaultConfigurationCount = 9; + private readonly int expectedDefaultConfigurationCount = 11; public ConfigurationTests() { diff --git a/tests/ImageSharp.Tests/Drawing/DrawImageTests.cs b/tests/ImageSharp.Tests/Drawing/DrawImageTests.cs index 533f0c6dee..88f4cde7ac 100644 --- a/tests/ImageSharp.Tests/Drawing/DrawImageTests.cs +++ b/tests/ImageSharp.Tests/Drawing/DrawImageTests.cs @@ -119,7 +119,7 @@ public void DrawImageOfDifferentPixelType(TestImageProvider prov public void WorksWithDifferentLocations(TestImageProvider provider, int x, int y) { using Image background = provider.GetImage(); - using Image overlay = new(50, 50, Color.Black.ToRgba32()); + using Image overlay = new(50, 50, Color.Black.ToPixel()); background.Mutate(c => c.DrawImage(overlay, new Point(x, y), PixelColorBlendingMode.Normal, 1F)); @@ -144,7 +144,7 @@ public void WorksWithDifferentLocations(TestImageProvider provider, int public void WorksWithDifferentBounds(TestImageProvider provider, int width, int height) { using Image background = provider.GetImage(); - using Image overlay = new(50, 50, Color.Black.ToRgba32()); + using Image overlay = new(50, 50, Color.Black.ToPixel()); background.Mutate(c => c.DrawImage(overlay, new Rectangle(0, 0, width, height), PixelColorBlendingMode.Normal, 1F)); diff --git a/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs index 1ce794e44b..94cfe85ee5 100644 --- a/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs @@ -4,6 +4,7 @@ using Microsoft.DotNet.RemoteExecutor; using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.Formats.Bmp; +using SixLabors.ImageSharp.Formats.Png; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Metadata; using SixLabors.ImageSharp.PixelFormats; @@ -112,7 +113,7 @@ public void BmpDecoder_CanDecode_1Bit(TestImageProvider provider { using Image image = provider.GetImage(BmpDecoder.Instance); image.DebugSave(provider); - image.CompareToOriginal(provider, new SystemDrawingReferenceDecoder()); + image.CompareToOriginal(provider, new SystemDrawingReferenceDecoder(BmpFormat.Instance)); } [Theory] @@ -219,7 +220,7 @@ public void BmpDecoder_CanDecode_RunLengthEncoded_8Bit_WithDelta_SystemDrawingRe image.DebugSave(provider); if (TestEnvironment.IsWindows) { - image.CompareToOriginal(provider, new SystemDrawingReferenceDecoder()); + image.CompareToOriginal(provider, new SystemDrawingReferenceDecoder(BmpFormat.Instance)); } } @@ -232,7 +233,7 @@ public void BmpDecoder_CanDecode_RunLengthEncoded_8Bit_WithDelta_MagickRefDecode BmpDecoderOptions options = new() { RleSkippedPixelHandling = RleSkippedPixelHandling.FirstColorOfPalette }; using Image image = provider.GetImage(BmpDecoder.Instance, options); image.DebugSave(provider); - image.CompareToOriginal(provider, new MagickReferenceDecoder()); + image.CompareToOriginal(provider, MagickReferenceDecoder.Png); } [Theory] @@ -251,7 +252,7 @@ public void BmpDecoder_CanDecode_RunLengthEncoded_8Bit(TestImageProvider BmpDecoderOptions options = new() { RleSkippedPixelHandling = RleSkippedPixelHandling.FirstColorOfPalette }; using Image image = provider.GetImage(BmpDecoder.Instance, options); image.DebugSave(provider); - image.CompareToOriginal(provider, new MagickReferenceDecoder()); + image.CompareToOriginal(provider, MagickReferenceDecoder.Png); } [Theory] @@ -298,7 +299,7 @@ public void BmpDecoder_CanDecodeBitmap_WithAlphaChannel(TestImageProvide { using Image image = provider.GetImage(BmpDecoder.Instance); image.DebugSave(provider); - image.CompareToOriginal(provider, new MagickReferenceDecoder()); + image.CompareToOriginal(provider, MagickReferenceDecoder.Png); } [Theory] @@ -314,7 +315,7 @@ public void BmpDecoder_CanDecodeBitfields_WithUnusualBitmasks(TestImageP // which should be remapped to 255 for RGBA32, but the magick decoder has a value of 191 set. // The total difference without the alpha channel is still: 0.0204% // Exporting the image as PNG with GIMP yields to the same result as the ImageSharp implementation. - image.CompareToOriginal(provider, ImageComparer.TolerantPercentage(6.1f), new MagickReferenceDecoder()); + image.CompareToOriginal(provider, ImageComparer.TolerantPercentage(6.1f), MagickReferenceDecoder.Png); } [Theory] @@ -327,7 +328,7 @@ public void BmpDecoder_CanDecodeBmpv2(TestImageProvider provider image.DebugSave(provider); // Do not validate. Reference files will fail validation. - image.CompareToOriginal(provider, new MagickReferenceDecoder(false)); + image.CompareToOriginal(provider, new MagickReferenceDecoder(PngFormat.Instance, false)); } [Theory] @@ -347,7 +348,7 @@ public void BmpDecoder_CanDecodeLessThanFullPalette(TestImageProvider image = provider.GetImage(BmpDecoder.Instance); image.DebugSave(provider); - image.CompareToOriginal(provider, new MagickReferenceDecoder()); + image.CompareToOriginal(provider, MagickReferenceDecoder.Png); } [Theory] @@ -394,7 +395,7 @@ public void BmpDecoder_CanDecodeAdobeBmpv3(TestImageProvider pro { using Image image = provider.GetImage(BmpDecoder.Instance); image.DebugSave(provider); - image.CompareToOriginal(provider, new MagickReferenceDecoder()); + image.CompareToOriginal(provider, MagickReferenceDecoder.Png); } [Theory] @@ -404,7 +405,7 @@ public void BmpDecoder_CanDecodeAdobeBmpv3_WithAlpha(TestImageProvider image = provider.GetImage(BmpDecoder.Instance); image.DebugSave(provider); - image.CompareToOriginal(provider, new MagickReferenceDecoder()); + image.CompareToOriginal(provider, MagickReferenceDecoder.Png); } [Theory] @@ -477,7 +478,7 @@ public void Identify_DetectsCorrectPixelType(string imagePath, int expectedPixel using MemoryStream stream = new(testFile.Bytes, false); ImageInfo imageInfo = Image.Identify(stream); Assert.NotNull(imageInfo); - Assert.Equal(expectedPixelSize, imageInfo.PixelType?.BitsPerPixel); + Assert.Equal(expectedPixelSize, imageInfo.PixelType.BitsPerPixel); } [Theory] diff --git a/tests/ImageSharp.Tests/Formats/Bmp/BmpEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Bmp/BmpEncoderTests.cs index 42cbd90f3b..d68ec47557 100644 --- a/tests/ImageSharp.Tests/Formats/Bmp/BmpEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Bmp/BmpEncoderTests.cs @@ -20,11 +20,11 @@ public class BmpEncoderTests private static BmpEncoder BmpEncoder => new(); public static readonly TheoryData BitsPerPixel = - new() - { - BmpBitsPerPixel.Pixel24, - BmpBitsPerPixel.Pixel32 - }; + new() + { + BmpBitsPerPixel.Bit24, + BmpBitsPerPixel.Bit32 + }; public static readonly TheoryData RatioFiles = new() @@ -37,13 +37,13 @@ public class BmpEncoderTests public static readonly TheoryData BmpBitsPerPixelFiles = new() { - { Bit1, BmpBitsPerPixel.Pixel1 }, - { Bit2, BmpBitsPerPixel.Pixel2 }, - { Bit4, BmpBitsPerPixel.Pixel4 }, - { Bit8, BmpBitsPerPixel.Pixel8 }, - { Rgb16, BmpBitsPerPixel.Pixel16 }, - { Car, BmpBitsPerPixel.Pixel24 }, - { Bit32Rgb, BmpBitsPerPixel.Pixel32 } + { Bit1, BmpBitsPerPixel.Bit1 }, + { Bit2, BmpBitsPerPixel.Bit2 }, + { Bit4, BmpBitsPerPixel.Bit4 }, + { Bit8, BmpBitsPerPixel.Bit8 }, + { Rgb16, BmpBitsPerPixel.Bit16 }, + { Car, BmpBitsPerPixel.Bit24 }, + { Bit32Rgb, BmpBitsPerPixel.Bit32 } }; [Fact] @@ -97,61 +97,61 @@ public void Encode_WorksWithDifferentSizes(TestImageProvider pro where TPixel : unmanaged, IPixel => TestBmpEncoderCore(provider, bitsPerPixel); [Theory] - [WithFile(Bit32Rgb, PixelTypes.Rgba32 | PixelTypes.Rgb24, BmpBitsPerPixel.Pixel32)] - [WithFile(Bit32Rgba, PixelTypes.Rgba32 | PixelTypes.Rgb24, BmpBitsPerPixel.Pixel32)] - [WithFile(WinBmpv4, PixelTypes.Rgba32 | PixelTypes.Rgb24, BmpBitsPerPixel.Pixel32)] - [WithFile(WinBmpv5, PixelTypes.Rgba32 | PixelTypes.Rgb24, BmpBitsPerPixel.Pixel32)] + [WithFile(Bit32Rgb, PixelTypes.Rgba32 | PixelTypes.Rgb24, BmpBitsPerPixel.Bit32)] + [WithFile(Bit32Rgba, PixelTypes.Rgba32 | PixelTypes.Rgb24, BmpBitsPerPixel.Bit32)] + [WithFile(WinBmpv4, PixelTypes.Rgba32 | PixelTypes.Rgb24, BmpBitsPerPixel.Bit32)] + [WithFile(WinBmpv5, PixelTypes.Rgba32 | PixelTypes.Rgb24, BmpBitsPerPixel.Bit32)] public void Encode_32Bit_WithV3Header_Works(TestImageProvider provider, BmpBitsPerPixel bitsPerPixel) // If supportTransparency is false, a v3 bitmap header will be written. where TPixel : unmanaged, IPixel => TestBmpEncoderCore(provider, bitsPerPixel, supportTransparency: false); [Theory] - [WithFile(Bit32Rgb, PixelTypes.Rgba32 | PixelTypes.Rgb24, BmpBitsPerPixel.Pixel32)] - [WithFile(Bit32Rgba, PixelTypes.Rgba32 | PixelTypes.Rgb24, BmpBitsPerPixel.Pixel32)] - [WithFile(WinBmpv4, PixelTypes.Rgba32 | PixelTypes.Rgb24, BmpBitsPerPixel.Pixel32)] - [WithFile(WinBmpv5, PixelTypes.Rgba32 | PixelTypes.Rgb24, BmpBitsPerPixel.Pixel32)] + [WithFile(Bit32Rgb, PixelTypes.Rgba32 | PixelTypes.Rgb24, BmpBitsPerPixel.Bit32)] + [WithFile(Bit32Rgba, PixelTypes.Rgba32 | PixelTypes.Rgb24, BmpBitsPerPixel.Bit32)] + [WithFile(WinBmpv4, PixelTypes.Rgba32 | PixelTypes.Rgb24, BmpBitsPerPixel.Bit32)] + [WithFile(WinBmpv5, PixelTypes.Rgba32 | PixelTypes.Rgb24, BmpBitsPerPixel.Bit32)] public void Encode_32Bit_WithV4Header_Works(TestImageProvider provider, BmpBitsPerPixel bitsPerPixel) where TPixel : unmanaged, IPixel => TestBmpEncoderCore(provider, bitsPerPixel, supportTransparency: true); [Theory] - [WithFile(WinBmpv3, PixelTypes.Rgb24, BmpBitsPerPixel.Pixel24)] // WinBmpv3 is a 24 bits per pixel image. - [WithFile(F, PixelTypes.Rgb24, BmpBitsPerPixel.Pixel24)] + [WithFile(WinBmpv3, PixelTypes.Rgb24, BmpBitsPerPixel.Bit24)] // WinBmpv3 is a 24 bits per pixel image. + [WithFile(F, PixelTypes.Rgb24, BmpBitsPerPixel.Bit24)] public void Encode_24Bit_WithV3Header_Works(TestImageProvider provider, BmpBitsPerPixel bitsPerPixel) where TPixel : unmanaged, IPixel => TestBmpEncoderCore(provider, bitsPerPixel, supportTransparency: false); [Theory] - [WithFile(WinBmpv3, PixelTypes.Rgb24, BmpBitsPerPixel.Pixel24)] - [WithFile(F, PixelTypes.Rgb24, BmpBitsPerPixel.Pixel24)] + [WithFile(WinBmpv3, PixelTypes.Rgb24, BmpBitsPerPixel.Bit24)] + [WithFile(F, PixelTypes.Rgb24, BmpBitsPerPixel.Bit24)] public void Encode_24Bit_WithV4Header_Works(TestImageProvider provider, BmpBitsPerPixel bitsPerPixel) where TPixel : unmanaged, IPixel => TestBmpEncoderCore(provider, bitsPerPixel, supportTransparency: true); [Theory] - [WithFile(Rgb16, PixelTypes.Bgra5551, BmpBitsPerPixel.Pixel16)] - [WithFile(Bit16, PixelTypes.Bgra5551, BmpBitsPerPixel.Pixel16)] + [WithFile(Rgb16, PixelTypes.Bgra5551, BmpBitsPerPixel.Bit16)] + [WithFile(Bit16, PixelTypes.Bgra5551, BmpBitsPerPixel.Bit16)] public void Encode_16Bit_WithV3Header_Works(TestImageProvider provider, BmpBitsPerPixel bitsPerPixel) where TPixel : unmanaged, IPixel => TestBmpEncoderCore(provider, bitsPerPixel, supportTransparency: false); [Theory] - [WithFile(Rgb16, PixelTypes.Bgra5551, BmpBitsPerPixel.Pixel16)] - [WithFile(Bit16, PixelTypes.Bgra5551, BmpBitsPerPixel.Pixel16)] + [WithFile(Rgb16, PixelTypes.Bgra5551, BmpBitsPerPixel.Bit16)] + [WithFile(Bit16, PixelTypes.Bgra5551, BmpBitsPerPixel.Bit16)] public void Encode_16Bit_WithV4Header_Works(TestImageProvider provider, BmpBitsPerPixel bitsPerPixel) where TPixel : unmanaged, IPixel => TestBmpEncoderCore(provider, bitsPerPixel, supportTransparency: true); [Theory] - [WithFile(WinBmpv5, PixelTypes.Rgba32, BmpBitsPerPixel.Pixel8)] - [WithFile(Bit8Palette4, PixelTypes.Rgba32, BmpBitsPerPixel.Pixel8)] + [WithFile(WinBmpv5, PixelTypes.Rgba32, BmpBitsPerPixel.Bit8)] + [WithFile(Bit8Palette4, PixelTypes.Rgba32, BmpBitsPerPixel.Bit8)] public void Encode_8Bit_WithV3Header_Works(TestImageProvider provider, BmpBitsPerPixel bitsPerPixel) where TPixel : unmanaged, IPixel => TestBmpEncoderCore(provider, bitsPerPixel, supportTransparency: false); [Theory] - [WithFile(WinBmpv5, PixelTypes.Rgba32, BmpBitsPerPixel.Pixel8)] - [WithFile(Bit8Palette4, PixelTypes.Rgba32, BmpBitsPerPixel.Pixel8)] + [WithFile(WinBmpv5, PixelTypes.Rgba32, BmpBitsPerPixel.Bit8)] + [WithFile(Bit8Palette4, PixelTypes.Rgba32, BmpBitsPerPixel.Bit8)] public void Encode_8Bit_WithV4Header_Works(TestImageProvider provider, BmpBitsPerPixel bitsPerPixel) where TPixel : unmanaged, IPixel => TestBmpEncoderCore(provider, bitsPerPixel, supportTransparency: true); [Theory] - [WithFile(Bit8Gs, PixelTypes.L8, BmpBitsPerPixel.Pixel8)] + [WithFile(Bit8Gs, PixelTypes.L8, BmpBitsPerPixel.Bit8)] public void Encode_8BitGray_WithV3Header_Works(TestImageProvider provider, BmpBitsPerPixel bitsPerPixel) where TPixel : unmanaged, IPixel => TestBmpEncoderCore( @@ -160,7 +160,7 @@ public void Encode_8BitGray_WithV3Header_Works(TestImageProvider supportTransparency: false); [Theory] - [WithFile(Bit4, PixelTypes.Rgba32, BmpBitsPerPixel.Pixel4)] + [WithFile(Bit4, PixelTypes.Rgba32, BmpBitsPerPixel.Bit4)] public void Encode_4Bit_WithV3Header_Works( TestImageProvider provider, BmpBitsPerPixel bitsPerPixel) @@ -176,7 +176,7 @@ public void Encode_4Bit_WithV3Header_Works( } [Theory] - [WithFile(Bit4, PixelTypes.Rgba32, BmpBitsPerPixel.Pixel4)] + [WithFile(Bit4, PixelTypes.Rgba32, BmpBitsPerPixel.Bit4)] public void Encode_4Bit_WithV4Header_Works( TestImageProvider provider, BmpBitsPerPixel bitsPerPixel) @@ -192,7 +192,7 @@ public void Encode_4Bit_WithV4Header_Works( } [Theory] - [WithFile(Bit2, PixelTypes.Rgba32, BmpBitsPerPixel.Pixel2)] + [WithFile(Bit2, PixelTypes.Rgba32, BmpBitsPerPixel.Bit2)] public void Encode_2Bit_WithV3Header_Works( TestImageProvider provider, BmpBitsPerPixel bitsPerPixel) @@ -214,7 +214,7 @@ public void Encode_2Bit_WithV3Header_Works( } [Theory] - [WithFile(Bit2, PixelTypes.Rgba32, BmpBitsPerPixel.Pixel2)] + [WithFile(Bit2, PixelTypes.Rgba32, BmpBitsPerPixel.Bit2)] public void Encode_2Bit_WithV4Header_Works( TestImageProvider provider, BmpBitsPerPixel bitsPerPixel) @@ -236,21 +236,21 @@ public void Encode_2Bit_WithV4Header_Works( } [Theory] - [WithFile(Bit1, PixelTypes.Rgba32, BmpBitsPerPixel.Pixel1)] + [WithFile(Bit1, PixelTypes.Rgba32, BmpBitsPerPixel.Bit1)] public void Encode_1Bit_WithV3Header_Works( TestImageProvider provider, BmpBitsPerPixel bitsPerPixel) where TPixel : unmanaged, IPixel => TestBmpEncoderCore(provider, bitsPerPixel, supportTransparency: false); [Theory] - [WithFile(Bit1, PixelTypes.Rgba32, BmpBitsPerPixel.Pixel1)] + [WithFile(Bit1, PixelTypes.Rgba32, BmpBitsPerPixel.Bit1)] public void Encode_1Bit_WithV4Header_Works( TestImageProvider provider, BmpBitsPerPixel bitsPerPixel) where TPixel : unmanaged, IPixel => TestBmpEncoderCore(provider, bitsPerPixel, supportTransparency: true); [Theory] - [WithFile(Bit8Gs, PixelTypes.L8, BmpBitsPerPixel.Pixel8)] + [WithFile(Bit8Gs, PixelTypes.L8, BmpBitsPerPixel.Bit8)] public void Encode_8BitGray_WithV4Header_Works(TestImageProvider provider, BmpBitsPerPixel bitsPerPixel) where TPixel : unmanaged, IPixel => TestBmpEncoderCore( @@ -271,7 +271,7 @@ public void Encode_8BitColor_WithWuQuantizer(TestImageProvider p using Image image = provider.GetImage(); BmpEncoder encoder = new() { - BitsPerPixel = BmpBitsPerPixel.Pixel8, + BitsPerPixel = BmpBitsPerPixel.Bit8, Quantizer = new WuQuantizer() }; @@ -287,7 +287,7 @@ public void Encode_8BitColor_WithWuQuantizer(TestImageProvider p provider, extension: "bmp", appendPixelTypeToFileName: false, - decoder: new MagickReferenceDecoder(false)); + decoder: new MagickReferenceDecoder(BmpFormat.Instance, false)); } [Theory] @@ -303,7 +303,7 @@ public void Encode_8BitColor_WithOctreeQuantizer(TestImageProvider image = provider.GetImage(); BmpEncoder encoder = new() { - BitsPerPixel = BmpBitsPerPixel.Pixel8, + BitsPerPixel = BmpBitsPerPixel.Bit8, Quantizer = new OctreeQuantizer() }; string actualOutputFile = provider.Utility.SaveTestOutputFile(image, "bmp", encoder, appendPixelTypeToFileName: false); @@ -318,12 +318,12 @@ public void Encode_8BitColor_WithOctreeQuantizer(TestImageProvider(TestImageProvider provider, BmpBitsPerPixel bitsPerPixel) where TPixel : unmanaged, IPixel => TestBmpEncoderCore(provider, bitsPerPixel, supportTransparency: true); @@ -364,8 +364,8 @@ public void Encode_WorksWithSizeGreaterThen65k(int width, int height) } [Theory] - [WithFile(Car, PixelTypes.Rgba32, BmpBitsPerPixel.Pixel32)] - [WithFile(V5Header, PixelTypes.Rgba32, BmpBitsPerPixel.Pixel32)] + [WithFile(Car, PixelTypes.Rgba32, BmpBitsPerPixel.Bit32)] + [WithFile(V5Header, PixelTypes.Rgba32, BmpBitsPerPixel.Bit32)] public void Encode_WorksWithDiscontiguousBuffers(TestImageProvider provider, BmpBitsPerPixel bitsPerPixel) where TPixel : unmanaged, IPixel { @@ -374,14 +374,14 @@ public void Encode_WorksWithDiscontiguousBuffers(TestImageProvider(TestImageProvider provider, BmpBitsPerPixel bitsPerPixel) where TPixel : unmanaged, IPixel { using Image image = provider.GetImage(); - using var reencodedStream = new MemoryStream(); - var encoder = new BmpEncoder + using MemoryStream reencodedStream = new(); + BmpEncoder encoder = new() { BitsPerPixel = bitsPerPixel, SupportTransparency = false, @@ -409,7 +409,7 @@ private static void TestBmpEncoderCore( using Image image = provider.GetImage(); // There is no alpha in bmp with less then 32 bits per pixels, so the reference image will be made opaque. - if (bitsPerPixel != BmpBitsPerPixel.Pixel32) + if (bitsPerPixel != BmpBitsPerPixel.Bit32) { image.Mutate(c => c.MakeOpaque()); } diff --git a/tests/ImageSharp.Tests/Formats/Bmp/BmpMetadataTests.cs b/tests/ImageSharp.Tests/Formats/Bmp/BmpMetadataTests.cs index 1d84356713..64564ae1d8 100644 --- a/tests/ImageSharp.Tests/Formats/Bmp/BmpMetadataTests.cs +++ b/tests/ImageSharp.Tests/Formats/Bmp/BmpMetadataTests.cs @@ -15,10 +15,10 @@ public class BmpMetadataTests public void CloneIsDeep() { BmpMetadata meta = new() - { BitsPerPixel = BmpBitsPerPixel.Pixel24, InfoHeaderType = BmpInfoHeaderType.Os2Version2 }; - BmpMetadata clone = (BmpMetadata)meta.DeepClone(); + { BitsPerPixel = BmpBitsPerPixel.Bit24, InfoHeaderType = BmpInfoHeaderType.Os2Version2 }; + BmpMetadata clone = meta.DeepClone(); - clone.BitsPerPixel = BmpBitsPerPixel.Pixel32; + clone.BitsPerPixel = BmpBitsPerPixel.Bit32; clone.InfoHeaderType = BmpInfoHeaderType.WinVersion2; Assert.False(meta.BitsPerPixel.Equals(clone.BitsPerPixel)); diff --git a/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs index a7e16f7737..77ac51e8a1 100644 --- a/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs @@ -1,6 +1,7 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. +using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.Formats.Gif; using SixLabors.ImageSharp.Formats.Png; using SixLabors.ImageSharp.Formats.Webp; @@ -113,7 +114,7 @@ public void EncodeGlobalPaletteReturnsSmallerFile(TestImageProvider image = provider.GetImage(); GifEncoder encoder = new() { - ColorTableMode = GifColorTableMode.Global, + ColorTableMode = FrameColorTableMode.Global, Quantizer = new OctreeQuantizer(new QuantizerOptions { Dither = null }) }; @@ -122,7 +123,7 @@ public void EncodeGlobalPaletteReturnsSmallerFile(TestImageProvider(TestImageP GifEncoder encoder = new() { - ColorTableMode = GifColorTableMode.Global, + ColorTableMode = FrameColorTableMode.Global, PixelSamplingStrategy = new DefaultPixelSamplingStrategy(maxPixels, scanRatio) }; @@ -175,10 +176,10 @@ public void NonMutatingEncodePreservesPaletteCount() Image image = Image.Load(inStream); GifMetadata metaData = image.Metadata.GetGifMetadata(); GifFrameMetadata frameMetadata = image.Frames.RootFrame.Metadata.GetGifMetadata(); - GifColorTableMode colorMode = metaData.ColorTableMode; + FrameColorTableMode colorMode = metaData.ColorTableMode; int maxColors; - if (colorMode == GifColorTableMode.Global) + if (colorMode == FrameColorTableMode.Global) { maxColors = metaData.GlobalColorTable.Value.Length; } @@ -204,7 +205,7 @@ public void NonMutatingEncodePreservesPaletteCount() // Gifiddle and Cyotek GifInfo say this image has 64 colors. colorMode = cloneMetadata.ColorTableMode; - if (colorMode == GifColorTableMode.Global) + if (colorMode == FrameColorTableMode.Global) { maxColors = metaData.GlobalColorTable.Value.Length; } @@ -220,7 +221,7 @@ public void NonMutatingEncodePreservesPaletteCount() GifFrameMetadata iMeta = image.Frames[i].Metadata.GetGifMetadata(); GifFrameMetadata cMeta = clone.Frames[i].Metadata.GetGifMetadata(); - if (iMeta.ColorTableMode == GifColorTableMode.Local) + if (iMeta.ColorTableMode == FrameColorTableMode.Local) { Assert.Equal(iMeta.LocalColorTable.Value.Length, cMeta.LocalColorTable.Value.Length); } @@ -241,33 +242,11 @@ public void OptionalExtensionsShouldBeHandledProperly(TestImageProvider< where TPixel : unmanaged, IPixel { using Image image = provider.GetImage(); - - int count = 0; - foreach (ImageFrame frame in image.Frames) - { - if (frame.Metadata.TryGetGifMetadata(out GifFrameMetadata _)) - { - count++; - } - } - provider.Utility.SaveTestOutputFile(image, extension: "gif"); using FileStream fs = File.OpenRead(provider.Utility.GetTestOutputFileName("gif")); using Image image2 = Image.Load(fs); - Assert.Equal(image.Frames.Count, image2.Frames.Count); - - count = 0; - foreach (ImageFrame frame in image2.Frames) - { - if (frame.Metadata.TryGetGifMetadata(out GifFrameMetadata _)) - { - count++; - } - } - - Assert.Equal(image2.Frames.Count, count); } [Theory] @@ -305,14 +284,14 @@ public void Encode_AnimatedFormatTransform_FromPng(TestImageProvider(TestImageProvider { "Foo" } + Comments = ["Foo"] }; GifMetadata clone = (GifMetadata)meta.DeepClone(); clone.RepeatCount = 2; - clone.ColorTableMode = GifColorTableMode.Local; + clone.ColorTableMode = FrameColorTableMode.Local; clone.GlobalColorTable = new[] { Color.Black }; Assert.False(meta.RepeatCount.Equals(clone.RepeatCount)); @@ -126,7 +126,7 @@ public void Identify_VerifyRatio(string imagePath, int xResolution, int yResolut public async Task Identify_VerifyRatioAsync(string imagePath, int xResolution, int yResolution, PixelResolutionUnit resolutionUnit) { TestFile testFile = TestFile.Create(imagePath); - using MemoryStream stream = new(testFile.Bytes, false); + await using MemoryStream stream = new(testFile.Bytes, false); ImageInfo image = await GifDecoder.Instance.IdentifyAsync(DecoderOptions.Default, stream); ImageMetadata meta = image.Metadata; Assert.Equal(xResolution, meta.HorizontalResolution); @@ -152,7 +152,7 @@ public void Decode_VerifyRatio(string imagePath, int xResolution, int yResolutio public async Task Decode_VerifyRatioAsync(string imagePath, int xResolution, int yResolution, PixelResolutionUnit resolutionUnit) { TestFile testFile = TestFile.Create(imagePath); - using MemoryStream stream = new(testFile.Bytes, false); + await using MemoryStream stream = new(testFile.Bytes, false); using Image image = await GifDecoder.Instance.DecodeAsync(DecoderOptions.Default, stream); ImageMetadata meta = image.Metadata; Assert.Equal(xResolution, meta.HorizontalResolution); @@ -183,14 +183,14 @@ public void Decode_VerifyRepeatCount(string imagePath, uint repeatCount) } [Theory] - [InlineData(TestImages.Gif.Cheers, 93, GifColorTableMode.Global, 256, 4, GifDisposalMethod.NotDispose)] + [InlineData(TestImages.Gif.Cheers, 93, FrameColorTableMode.Global, 256, 4, FrameDisposalMode.DoNotDispose)] public void Identify_Frames( string imagePath, int framesCount, - GifColorTableMode colorTableMode, + FrameColorTableMode colorTableMode, int globalColorTableLength, int frameDelay, - GifDisposalMethod disposalMethod) + FrameDisposalMode disposalMethod) { TestFile testFile = TestFile.Create(imagePath); using MemoryStream stream = new(testFile.Bytes, false); @@ -206,13 +206,13 @@ public void Identify_Frames( Assert.Equal(colorTableMode, gifFrameMetadata.ColorTableMode); - if (colorTableMode == GifColorTableMode.Global) + if (colorTableMode == FrameColorTableMode.Global) { Assert.Equal(globalColorTableLength, gifMetadata.GlobalColorTable.Value.Length); } Assert.Equal(frameDelay, gifFrameMetadata.FrameDelay); - Assert.Equal(disposalMethod, gifFrameMetadata.DisposalMethod); + Assert.Equal(disposalMethod, gifFrameMetadata.DisposalMode); } [Theory] diff --git a/tests/ImageSharp.Tests/Formats/Gif/Sections/GifGraphicControlExtensionTests.cs b/tests/ImageSharp.Tests/Formats/Gif/Sections/GifGraphicControlExtensionTests.cs index c602bc91bb..05dc5bc52a 100644 --- a/tests/ImageSharp.Tests/Formats/Gif/Sections/GifGraphicControlExtensionTests.cs +++ b/tests/ImageSharp.Tests/Formats/Gif/Sections/GifGraphicControlExtensionTests.cs @@ -1,6 +1,7 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. +using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.Formats.Gif; namespace SixLabors.ImageSharp.Tests.Formats.Gif.Sections; @@ -10,9 +11,9 @@ public class GifGraphicControlExtensionTests [Fact] public void TestPackedValue() { - Assert.Equal(0, GifGraphicControlExtension.GetPackedValue(GifDisposalMethod.Unspecified, false, false)); - Assert.Equal(11, GifGraphicControlExtension.GetPackedValue(GifDisposalMethod.RestoreToBackground, true, true)); - Assert.Equal(4, GifGraphicControlExtension.GetPackedValue(GifDisposalMethod.NotDispose, false, false)); - Assert.Equal(14, GifGraphicControlExtension.GetPackedValue(GifDisposalMethod.RestoreToPrevious, true, false)); + Assert.Equal(0, GifGraphicControlExtension.GetPackedValue(FrameDisposalMode.Unspecified, false, false)); + Assert.Equal(11, GifGraphicControlExtension.GetPackedValue(FrameDisposalMode.RestoreToBackground, true, true)); + Assert.Equal(4, GifGraphicControlExtension.GetPackedValue(FrameDisposalMode.DoNotDispose, false, false)); + Assert.Equal(14, GifGraphicControlExtension.GetPackedValue(FrameDisposalMode.RestoreToPrevious, true, false)); } } diff --git a/tests/ImageSharp.Tests/Formats/Icon/Cur/CurDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Icon/Cur/CurDecoderTests.cs new file mode 100644 index 0000000000..f7ee7614af --- /dev/null +++ b/tests/ImageSharp.Tests/Formats/Icon/Cur/CurDecoderTests.cs @@ -0,0 +1,41 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.Formats.Bmp; +using SixLabors.ImageSharp.Formats.Cur; +using SixLabors.ImageSharp.Formats.Icon; +using SixLabors.ImageSharp.PixelFormats; +using static SixLabors.ImageSharp.Tests.TestImages.Cur; + +namespace SixLabors.ImageSharp.Tests.Formats.Icon.Cur; + +[Trait("Format", "Cur")] +[ValidateDisposedMemoryAllocations] +public class CurDecoderTests +{ + [Theory] + [WithFile(WindowsMouse, PixelTypes.Rgba32)] + public void CurDecoder_Decode(TestImageProvider provider) + { + using Image image = provider.GetImage(CurDecoder.Instance); + + CurFrameMetadata meta = image.Frames[0].Metadata.GetCurMetadata(); + Assert.Equal(image.Width, meta.EncodingWidth); + Assert.Equal(image.Height, meta.EncodingHeight); + Assert.Equal(IconFrameCompression.Bmp, meta.Compression); + Assert.Equal(BmpBitsPerPixel.Bit32, meta.BmpBitsPerPixel); + } + + [Theory] + [WithFile(CurFake, PixelTypes.Rgba32)] + [WithFile(CurReal, PixelTypes.Rgba32)] + public void CurDecoder_Decode2(TestImageProvider provider) + { + using Image image = provider.GetImage(CurDecoder.Instance); + CurFrameMetadata meta = image.Frames[0].Metadata.GetCurMetadata(); + Assert.Equal(image.Width, meta.EncodingWidth); + Assert.Equal(image.Height, meta.EncodingHeight); + Assert.Equal(IconFrameCompression.Bmp, meta.Compression); + Assert.Equal(BmpBitsPerPixel.Bit32, meta.BmpBitsPerPixel); + } +} diff --git a/tests/ImageSharp.Tests/Formats/Icon/Cur/CurEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Icon/Cur/CurEncoderTests.cs new file mode 100644 index 0000000000..59c40c9245 --- /dev/null +++ b/tests/ImageSharp.Tests/Formats/Icon/Cur/CurEncoderTests.cs @@ -0,0 +1,66 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.Formats.Cur; +using SixLabors.ImageSharp.Formats.Ico; +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison; +using static SixLabors.ImageSharp.Tests.TestImages.Cur; +using static SixLabors.ImageSharp.Tests.TestImages.Ico; + +namespace SixLabors.ImageSharp.Tests.Formats.Icon.Cur; + +[Trait("Format", "Cur")] +public class CurEncoderTests +{ + private static CurEncoder Encoder => new(); + + [Theory] + [WithFile(CurReal, PixelTypes.Rgba32)] + [WithFile(WindowsMouse, PixelTypes.Rgba32)] + public void CanRoundTripEncoder(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + using Image image = provider.GetImage(CurDecoder.Instance); + using MemoryStream memStream = new(); + image.DebugSaveMultiFrame(provider); + + image.Save(memStream, Encoder); + memStream.Seek(0, SeekOrigin.Begin); + + using Image encoded = Image.Load(memStream); + encoded.DebugSaveMultiFrame(provider, appendPixelTypeToFileName: false); + + encoded.CompareToOriginalMultiFrame(provider, ImageComparer.Exact, CurDecoder.Instance); + } + + [Theory] + [WithFile(Flutter, PixelTypes.Rgba32)] + public void CanConvertFromIco(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + using Image image = provider.GetImage(IcoDecoder.Instance); + using MemoryStream memStream = new(); + + image.Save(memStream, Encoder); + memStream.Seek(0, SeekOrigin.Begin); + + using Image encoded = Image.Load(memStream); + encoded.DebugSaveMultiFrame(provider); + + // Despite preservation of the palette. The process can still be lossy + encoded.CompareToOriginalMultiFrame(provider, ImageComparer.TolerantPercentage(.23f), IcoDecoder.Instance); + + for (int i = 0; i < image.Frames.Count; i++) + { + IcoFrameMetadata icoFrame = image.Frames[i].Metadata.GetIcoMetadata(); + CurFrameMetadata curFrame = encoded.Frames[i].Metadata.GetCurMetadata(); + + // Compression may differ as we cannot convert that. + // Color table may differ. + Assert.Equal(icoFrame.BmpBitsPerPixel, curFrame.BmpBitsPerPixel); + Assert.Equal(icoFrame.EncodingWidth, curFrame.EncodingWidth); + Assert.Equal(icoFrame.EncodingHeight, curFrame.EncodingHeight); + } + } +} diff --git a/tests/ImageSharp.Tests/Formats/Icon/Ico/IcoDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Icon/Ico/IcoDecoderTests.cs new file mode 100644 index 0000000000..bc46df0955 --- /dev/null +++ b/tests/ImageSharp.Tests/Formats/Icon/Ico/IcoDecoderTests.cs @@ -0,0 +1,332 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.Formats.Bmp; +using SixLabors.ImageSharp.Formats.Ico; +using SixLabors.ImageSharp.Formats.Icon; +using SixLabors.ImageSharp.PixelFormats; +using static SixLabors.ImageSharp.Tests.TestImages.Ico; + +namespace SixLabors.ImageSharp.Tests.Formats.Icon.Ico; + +[Trait("Format", "Icon")] +[ValidateDisposedMemoryAllocations] +public class IcoDecoderTests +{ + [Theory] + [WithFile(Flutter, PixelTypes.Rgba32)] + public void IcoDecoder_Decode(TestImageProvider provider) + { + using Image image = provider.GetImage(IcoDecoder.Instance); + + image.DebugSaveMultiFrame(provider); + + Assert.Equal(10, image.Frames.Count); + } + + [Theory] + [WithFile(Bpp1Size15x15, PixelTypes.Rgba32)] + [WithFile(Bpp1Size16x16, PixelTypes.Rgba32)] + [WithFile(Bpp1Size17x17, PixelTypes.Rgba32)] + [WithFile(Bpp1Size1x1, PixelTypes.Rgba32)] + [WithFile(Bpp1Size256x256, PixelTypes.Rgba32)] + [WithFile(Bpp1Size2x2, PixelTypes.Rgba32)] + [WithFile(Bpp1Size31x31, PixelTypes.Rgba32)] + [WithFile(Bpp1Size32x32, PixelTypes.Rgba32)] + [WithFile(Bpp1Size33x33, PixelTypes.Rgba32)] + [WithFile(Bpp1Size3x3, PixelTypes.Rgba32)] + [WithFile(Bpp1Size4x4, PixelTypes.Rgba32)] + [WithFile(Bpp1Size5x5, PixelTypes.Rgba32)] + [WithFile(Bpp1Size6x6, PixelTypes.Rgba32)] + [WithFile(Bpp1Size7x7, PixelTypes.Rgba32)] + [WithFile(Bpp1Size8x8, PixelTypes.Rgba32)] + [WithFile(Bpp1Size9x9, PixelTypes.Rgba32)] + [WithFile(Bpp1TranspNotSquare, PixelTypes.Rgba32)] + [WithFile(Bpp1TranspPartial, PixelTypes.Rgba32)] + public void Bpp1Test(TestImageProvider provider) + { + using Image image = provider.GetImage(IcoDecoder.Instance); + + image.DebugSave(provider); + + IcoFrameMetadata meta = image.Frames.RootFrame.Metadata.GetIcoMetadata(); + int expectedWidth = image.Width >= 256 ? 0 : image.Width; + int expectedHeight = image.Height >= 256 ? 0 : image.Height; + + Assert.Equal(expectedWidth, meta.EncodingWidth); + Assert.Equal(expectedHeight, meta.EncodingHeight); + Assert.Equal(IconFrameCompression.Bmp, meta.Compression); + Assert.Equal(BmpBitsPerPixel.Bit1, meta.BmpBitsPerPixel); + } + + [Theory] + [WithFile(Bpp24Size15x15, PixelTypes.Rgba32)] + [WithFile(Bpp24Size16x16, PixelTypes.Rgba32)] + [WithFile(Bpp24Size17x17, PixelTypes.Rgba32)] + [WithFile(Bpp24Size1x1, PixelTypes.Rgba32)] + [WithFile(Bpp24Size256x256, PixelTypes.Rgba32)] + [WithFile(Bpp24Size2x2, PixelTypes.Rgba32)] + [WithFile(Bpp24Size31x31, PixelTypes.Rgba32)] + [WithFile(Bpp24Size32x32, PixelTypes.Rgba32)] + [WithFile(Bpp24Size33x33, PixelTypes.Rgba32)] + [WithFile(Bpp24Size3x3, PixelTypes.Rgba32)] + [WithFile(Bpp24Size4x4, PixelTypes.Rgba32)] + [WithFile(Bpp24Size5x5, PixelTypes.Rgba32)] + [WithFile(Bpp24Size6x6, PixelTypes.Rgba32)] + [WithFile(Bpp24Size7x7, PixelTypes.Rgba32)] + [WithFile(Bpp24Size8x8, PixelTypes.Rgba32)] + [WithFile(Bpp24Size9x9, PixelTypes.Rgba32)] + [WithFile(Bpp24TranspNotSquare, PixelTypes.Rgba32)] + [WithFile(Bpp24TranspPartial, PixelTypes.Rgba32)] + [WithFile(Bpp24Transp, PixelTypes.Rgba32)] + public void Bpp24Test(TestImageProvider provider) + { + using Image image = provider.GetImage(IcoDecoder.Instance); + + image.DebugSave(provider); + + IcoFrameMetadata meta = image.Frames.RootFrame.Metadata.GetIcoMetadata(); + int expectedWidth = image.Width >= 256 ? 0 : image.Width; + int expectedHeight = image.Height >= 256 ? 0 : image.Height; + + Assert.Equal(expectedWidth, meta.EncodingWidth); + Assert.Equal(expectedHeight, meta.EncodingHeight); + Assert.Equal(IconFrameCompression.Bmp, meta.Compression); + Assert.Equal(BmpBitsPerPixel.Bit24, meta.BmpBitsPerPixel); + } + + [Theory] + [WithFile(Bpp32Size15x15, PixelTypes.Rgba32)] + [WithFile(Bpp32Size16x16, PixelTypes.Rgba32)] + [WithFile(Bpp32Size17x17, PixelTypes.Rgba32)] + [WithFile(Bpp32Size1x1, PixelTypes.Rgba32)] + [WithFile(Bpp32Size256x256, PixelTypes.Rgba32)] + [WithFile(Bpp32Size2x2, PixelTypes.Rgba32)] + [WithFile(Bpp32Size31x31, PixelTypes.Rgba32)] + [WithFile(Bpp32Size32x32, PixelTypes.Rgba32)] + [WithFile(Bpp32Size33x33, PixelTypes.Rgba32)] + [WithFile(Bpp32Size3x3, PixelTypes.Rgba32)] + [WithFile(Bpp32Size4x4, PixelTypes.Rgba32)] + [WithFile(Bpp32Size5x5, PixelTypes.Rgba32)] + [WithFile(Bpp32Size6x6, PixelTypes.Rgba32)] + [WithFile(Bpp32Size7x7, PixelTypes.Rgba32)] + [WithFile(Bpp32Size8x8, PixelTypes.Rgba32)] + [WithFile(Bpp32Size9x9, PixelTypes.Rgba32)] + [WithFile(Bpp32TranspNotSquare, PixelTypes.Rgba32)] + [WithFile(Bpp32TranspPartial, PixelTypes.Rgba32)] + [WithFile(Bpp32Transp, PixelTypes.Rgba32)] + public void Bpp32Test(TestImageProvider provider) + { + using Image image = provider.GetImage(IcoDecoder.Instance); + + image.DebugSave(provider); + + IcoFrameMetadata meta = image.Frames.RootFrame.Metadata.GetIcoMetadata(); + int expectedWidth = image.Width >= 256 ? 0 : image.Width; + int expectedHeight = image.Height >= 256 ? 0 : image.Height; + + Assert.Equal(expectedWidth, meta.EncodingWidth); + Assert.Equal(expectedHeight, meta.EncodingHeight); + Assert.Equal(IconFrameCompression.Bmp, meta.Compression); + Assert.Equal(BmpBitsPerPixel.Bit32, meta.BmpBitsPerPixel); + } + + [Theory] + [WithFile(Bpp4Size15x15, PixelTypes.Rgba32)] + [WithFile(Bpp4Size16x16, PixelTypes.Rgba32)] + [WithFile(Bpp4Size17x17, PixelTypes.Rgba32)] + [WithFile(Bpp4Size1x1, PixelTypes.Rgba32)] + [WithFile(Bpp4Size256x256, PixelTypes.Rgba32)] + [WithFile(Bpp4Size2x2, PixelTypes.Rgba32)] + [WithFile(Bpp4Size31x31, PixelTypes.Rgba32)] + [WithFile(Bpp4Size32x32, PixelTypes.Rgba32)] + [WithFile(Bpp4Size33x33, PixelTypes.Rgba32)] + [WithFile(Bpp4Size3x3, PixelTypes.Rgba32)] + [WithFile(Bpp4Size4x4, PixelTypes.Rgba32)] + [WithFile(Bpp4Size5x5, PixelTypes.Rgba32)] + [WithFile(Bpp4Size6x6, PixelTypes.Rgba32)] + [WithFile(Bpp4Size7x7, PixelTypes.Rgba32)] + [WithFile(Bpp4Size8x8, PixelTypes.Rgba32)] + [WithFile(Bpp4Size9x9, PixelTypes.Rgba32)] + [WithFile(Bpp4TranspNotSquare, PixelTypes.Rgba32)] + [WithFile(Bpp4TranspPartial, PixelTypes.Rgba32)] + public void Bpp4Test(TestImageProvider provider) + { + using Image image = provider.GetImage(IcoDecoder.Instance); + + image.DebugSave(provider); + + IcoFrameMetadata meta = image.Frames.RootFrame.Metadata.GetIcoMetadata(); + int expectedWidth = image.Width >= 256 ? 0 : image.Width; + int expectedHeight = image.Height >= 256 ? 0 : image.Height; + + Assert.Equal(expectedWidth, meta.EncodingWidth); + Assert.Equal(expectedHeight, meta.EncodingHeight); + Assert.Equal(IconFrameCompression.Bmp, meta.Compression); + Assert.Equal(BmpBitsPerPixel.Bit4, meta.BmpBitsPerPixel); + } + + [Theory] + [WithFile(Bpp8Size15x15, PixelTypes.Rgba32)] + [WithFile(Bpp8Size16x16, PixelTypes.Rgba32)] + [WithFile(Bpp8Size17x17, PixelTypes.Rgba32)] + [WithFile(Bpp8Size1x1, PixelTypes.Rgba32)] + [WithFile(Bpp8Size256x256, PixelTypes.Rgba32)] + [WithFile(Bpp8Size2x2, PixelTypes.Rgba32)] + [WithFile(Bpp8Size31x31, PixelTypes.Rgba32)] + [WithFile(Bpp8Size32x32, PixelTypes.Rgba32)] + [WithFile(Bpp8Size33x33, PixelTypes.Rgba32)] + [WithFile(Bpp8Size3x3, PixelTypes.Rgba32)] + [WithFile(Bpp8Size4x4, PixelTypes.Rgba32)] + [WithFile(Bpp8Size5x5, PixelTypes.Rgba32)] + [WithFile(Bpp8Size6x6, PixelTypes.Rgba32)] + [WithFile(Bpp8Size7x7, PixelTypes.Rgba32)] + + // [WithFile(Bpp8Size8x8, PixelTypes.Rgba32)] This is actually 24 bit. + [WithFile(Bpp8Size9x9, PixelTypes.Rgba32)] + [WithFile(Bpp8TranspNotSquare, PixelTypes.Rgba32)] + [WithFile(Bpp8TranspPartial, PixelTypes.Rgba32)] + public void Bpp8Test(TestImageProvider provider) + { + using Image image = provider.GetImage(IcoDecoder.Instance); + + image.DebugSave(provider); + + IcoFrameMetadata meta = image.Frames.RootFrame.Metadata.GetIcoMetadata(); + int expectedWidth = image.Width >= 256 ? 0 : image.Width; + int expectedHeight = image.Height >= 256 ? 0 : image.Height; + + Assert.Equal(expectedWidth, meta.EncodingWidth); + Assert.Equal(expectedHeight, meta.EncodingHeight); + Assert.Equal(IconFrameCompression.Bmp, meta.Compression); + Assert.Equal(BmpBitsPerPixel.Bit8, meta.BmpBitsPerPixel); + } + + [Theory] + [WithFile(InvalidAll, PixelTypes.Rgba32)] + [WithFile(InvalidBpp, PixelTypes.Rgba32)] + [WithFile(InvalidCompression, PixelTypes.Rgba32)] + [WithFile(InvalidRLE4, PixelTypes.Rgba32)] + [WithFile(InvalidRLE8, PixelTypes.Rgba32)] + public void InvalidTest(TestImageProvider provider) + => Assert.Throws(() => + { + using Image image = provider.GetImage(IcoDecoder.Instance); + }); + + [Theory] + [WithFile(InvalidPng, PixelTypes.Rgba32)] + public void InvalidPngTest(TestImageProvider provider) + { + using Image image = provider.GetImage(IcoDecoder.Instance); + + image.DebugSave(provider); + + IcoFrameMetadata meta = image.Frames.RootFrame.Metadata.GetIcoMetadata(); + int expectedWidth = image.Width >= 256 ? 0 : image.Width; + int expectedHeight = image.Height >= 256 ? 0 : image.Height; + + Assert.Equal(expectedWidth, meta.EncodingWidth); + Assert.Equal(expectedHeight, meta.EncodingHeight); + Assert.Equal(IconFrameCompression.Png, meta.Compression); + Assert.Equal(BmpBitsPerPixel.Bit32, meta.BmpBitsPerPixel); + } + + [Theory] + [WithFile(MixedBmpPngA, PixelTypes.Rgba32)] + [WithFile(MixedBmpPngB, PixelTypes.Rgba32)] + [WithFile(MixedBmpPngC, PixelTypes.Rgba32)] + public void MixedBmpPngTest(TestImageProvider provider) + { + using Image image = provider.GetImage(IcoDecoder.Instance); + + Assert.True(image.Frames.Count > 1); + + image.DebugSaveMultiFrame(provider); + } + + [Theory] + [WithFile(MultiSizeA, PixelTypes.Rgba32)] + [WithFile(MultiSizeB, PixelTypes.Rgba32)] + [WithFile(MultiSizeC, PixelTypes.Rgba32)] + [WithFile(MultiSizeD, PixelTypes.Rgba32)] + [WithFile(MultiSizeE, PixelTypes.Rgba32)] + [WithFile(MultiSizeF, PixelTypes.Rgba32)] + public void MultiSizeTest(TestImageProvider provider) + { + using Image image = provider.GetImage(IcoDecoder.Instance); + + Assert.True(image.Frames.Count > 1); + + for (int i = 0; i < image.Frames.Count; i++) + { + ImageFrame frame = image.Frames[i]; + IcoFrameMetadata meta = frame.Metadata.GetIcoMetadata(); + Assert.Equal(BmpBitsPerPixel.Bit32, meta.BmpBitsPerPixel); + } + + image.DebugSaveMultiFrame(provider); + } + + [Theory] + [WithFile(MultiSizeA, PixelTypes.Rgba32)] + [WithFile(MultiSizeB, PixelTypes.Rgba32)] + [WithFile(MultiSizeC, PixelTypes.Rgba32)] + [WithFile(MultiSizeD, PixelTypes.Rgba32)] + [WithFile(MultiSizeE, PixelTypes.Rgba32)] + [WithFile(MultiSizeF, PixelTypes.Rgba32)] + public void MultiSize_CanDecodeSingleFrame(TestImageProvider provider) + { + using Image image = provider.GetImage(IcoDecoder.Instance, new() { MaxFrames = 1 }); + Assert.Single(image.Frames); + } + + [Theory] + [InlineData(MultiSizeA)] + [InlineData(MultiSizeB)] + [InlineData(MultiSizeC)] + [InlineData(MultiSizeD)] + [InlineData(MultiSizeE)] + [InlineData(MultiSizeF)] + public void MultiSize_CanIdentifySingleFrame(string imagePath) + { + TestFile testFile = TestFile.Create(imagePath); + using MemoryStream stream = new(testFile.Bytes, false); + + ImageInfo imageInfo = Image.Identify(new() { MaxFrames = 1 }, stream); + + Assert.Single(imageInfo.FrameMetadataCollection); + } + + [Theory] + [WithFile(MultiSizeMultiBitsA, PixelTypes.Rgba32)] + [WithFile(MultiSizeMultiBitsB, PixelTypes.Rgba32)] + [WithFile(MultiSizeMultiBitsC, PixelTypes.Rgba32)] + [WithFile(MultiSizeMultiBitsD, PixelTypes.Rgba32)] + public void MultiSizeMultiBitsTest(TestImageProvider provider) + { + using Image image = provider.GetImage(IcoDecoder.Instance); + + Assert.True(image.Frames.Count > 1); + + image.DebugSaveMultiFrame(provider); + } + + [Theory] + [WithFile(IcoFake, PixelTypes.Rgba32)] + public void IcoFakeTest(TestImageProvider provider) + { + using Image image = provider.GetImage(IcoDecoder.Instance); + + image.DebugSave(provider); + + IcoFrameMetadata meta = image.Frames.RootFrame.Metadata.GetIcoMetadata(); + int expectedWidth = image.Width >= 256 ? 0 : image.Width; + int expectedHeight = image.Height >= 256 ? 0 : image.Height; + + Assert.Equal(expectedWidth, meta.EncodingWidth); + Assert.Equal(expectedHeight, meta.EncodingHeight); + Assert.Equal(IconFrameCompression.Bmp, meta.Compression); + Assert.Equal(BmpBitsPerPixel.Bit32, meta.BmpBitsPerPixel); + } +} diff --git a/tests/ImageSharp.Tests/Formats/Icon/Ico/IcoEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Icon/Ico/IcoEncoderTests.cs new file mode 100644 index 0000000000..751db384d7 --- /dev/null +++ b/tests/ImageSharp.Tests/Formats/Icon/Ico/IcoEncoderTests.cs @@ -0,0 +1,65 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.Formats.Cur; +using SixLabors.ImageSharp.Formats.Ico; +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison; +using static SixLabors.ImageSharp.Tests.TestImages.Cur; +using static SixLabors.ImageSharp.Tests.TestImages.Ico; + +namespace SixLabors.ImageSharp.Tests.Formats.Icon.Ico; + +[Trait("Format", "Icon")] +public class IcoEncoderTests +{ + private static IcoEncoder Encoder => new(); + + [Theory] + [WithFile(Flutter, PixelTypes.Rgba32)] + public void CanRoundTripEncoder(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + using Image image = provider.GetImage(IcoDecoder.Instance); + using MemoryStream memStream = new(); + image.DebugSaveMultiFrame(provider); + + image.Save(memStream, Encoder); + memStream.Seek(0, SeekOrigin.Begin); + + using Image encoded = Image.Load(memStream); + encoded.DebugSaveMultiFrame(provider); + + // Despite preservation of the palette. The process can still be lossy + encoded.CompareToOriginalMultiFrame(provider, ImageComparer.TolerantPercentage(.23f), IcoDecoder.Instance); + } + + [Theory] + [WithFile(WindowsMouse, PixelTypes.Rgba32)] + public void CanConvertFromCur(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + using Image image = provider.GetImage(CurDecoder.Instance); + using MemoryStream memStream = new(); + + image.Save(memStream, Encoder); + memStream.Seek(0, SeekOrigin.Begin); + + using Image encoded = Image.Load(memStream); + encoded.DebugSaveMultiFrame(provider); + + encoded.CompareToOriginalMultiFrame(provider, ImageComparer.Exact, CurDecoder.Instance); + + for (int i = 0; i < image.Frames.Count; i++) + { + CurFrameMetadata curFrame = image.Frames[i].Metadata.GetCurMetadata(); + IcoFrameMetadata icoFrame = encoded.Frames[i].Metadata.GetIcoMetadata(); + + // Compression may differ as we cannot convert that. + Assert.Equal(curFrame.BmpBitsPerPixel, icoFrame.BmpBitsPerPixel); + Assert.Equal(curFrame.EncodingWidth, icoFrame.EncodingWidth); + Assert.Equal(curFrame.EncodingHeight, icoFrame.EncodingHeight); + Assert.Equal(curFrame.ColorTable, icoFrame.ColorTable); + } + } +} diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs index ef9f48a890..7aabdaa588 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs @@ -3,11 +3,10 @@ using System.Runtime.Intrinsics.Arm; using System.Runtime.Intrinsics.X86; -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; +using SixLabors.ImageSharp.ColorProfiles; using SixLabors.ImageSharp.Formats.Jpeg.Components; using SixLabors.ImageSharp.Memory; -using SixLabors.ImageSharp.Tests.Colorspaces.Conversion; +using SixLabors.ImageSharp.Tests.ColorProfiles; using SixLabors.ImageSharp.Tests.TestUtilities; using Xunit.Abstractions; @@ -24,9 +23,9 @@ public class JpegColorConverterTests private const HwIntrinsics IntrinsicsConfig = HwIntrinsics.AllowAll | HwIntrinsics.DisableAVX2; - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new(epsilon: Precision); + private static readonly ApproximateColorProfileComparer ColorSpaceComparer = new(epsilon: Precision); - private static readonly ColorSpaceConverter ColorSpaceConverter = new(); + private static readonly ColorProfileConverter ColorSpaceConverter = new(); public static readonly TheoryData Seeds = new() { 1, 2, 3 }; @@ -38,7 +37,7 @@ public JpegColorConverterTests(ITestOutputHelper output) [Fact] public void GetConverterThrowsExceptionOnInvalidColorSpace() { - JpegColorSpace invalidColorSpace = (JpegColorSpace)(-1); + const JpegColorSpace invalidColorSpace = (JpegColorSpace)(-1); Assert.Throws(() => JpegColorConverterBase.GetConverter(invalidColorSpace, 8)); } @@ -46,7 +45,7 @@ public void GetConverterThrowsExceptionOnInvalidColorSpace() public void GetConverterThrowsExceptionOnInvalidPrecision() { // Valid precisions: 8 & 12 bit - int invalidPrecision = 9; + const int invalidPrecision = 9; Assert.Throws(() => JpegColorConverterBase.GetConverter(JpegColorSpace.YCbCr, invalidPrecision)); } @@ -428,7 +427,8 @@ public void FromRgbToYCbCrAvx2(int seed) => [Theory] [MemberData(nameof(Seeds))] public void FromYCbCrArm(int seed) => - this.TestConversionToRgb(new JpegColorConverterBase.YCbCrArm(8), + this.TestConversionToRgb( + new JpegColorConverterBase.YCbCrArm(8), 3, seed, new JpegColorConverterBase.YCbCrScalar(8)); @@ -436,7 +436,8 @@ public void FromYCbCrArm(int seed) => [Theory] [MemberData(nameof(Seeds))] public void FromRgbToYCbCrArm(int seed) => - this.TestConversionFromRgb(new JpegColorConverterBase.YCbCrArm(8), + this.TestConversionFromRgb( + new JpegColorConverterBase.YCbCrArm(8), 3, seed, new JpegColorConverterBase.YCbCrScalar(8), @@ -502,7 +503,8 @@ public void FromRgbToGrayscaleAvx2(int seed) => [Theory] [MemberData(nameof(Seeds))] public void FromGrayscaleArm(int seed) => - this.TestConversionToRgb(new JpegColorConverterBase.GrayscaleArm(8), + this.TestConversionToRgb( + new JpegColorConverterBase.GrayscaleArm(8), 1, seed, new JpegColorConverterBase.GrayscaleScalar(8)); @@ -510,7 +512,8 @@ public void FromGrayscaleArm(int seed) => [Theory] [MemberData(nameof(Seeds))] public void FromRgbToGrayscaleArm(int seed) => - this.TestConversionFromRgb(new JpegColorConverterBase.GrayscaleArm(8), + this.TestConversionFromRgb( + new JpegColorConverterBase.GrayscaleArm(8), 1, seed, new JpegColorConverterBase.GrayscaleScalar(8), @@ -556,7 +559,8 @@ public void FromRgbToYccKAvx2(int seed) => [Theory] [MemberData(nameof(Seeds))] public void FromYccKArm64(int seed) => - this.TestConversionToRgb(new JpegColorConverterBase.YccKArm64(8), + this.TestConversionToRgb( + new JpegColorConverterBase.YccKArm64(8), 4, seed, new JpegColorConverterBase.YccKScalar(8)); @@ -564,7 +568,8 @@ public void FromYccKArm64(int seed) => [Theory] [MemberData(nameof(Seeds))] public void FromRgbToYccKArm64(int seed) => - this.TestConversionFromRgb(new JpegColorConverterBase.YccKArm64(8), + this.TestConversionFromRgb( + new JpegColorConverterBase.YccKArm64(8), 4, seed, new JpegColorConverterBase.YccKScalar(8), @@ -617,9 +622,9 @@ private static JpegColorConverterBase.ComponentValues CreateRandomValues( int componentCount, int seed) { - var rnd = new Random(seed); + Random rnd = new(seed); - var buffers = new Buffer2D[componentCount]; + Buffer2D[] buffers = new Buffer2D[componentCount]; for (int i = 0; i < componentCount; i++) { float[] values = new float[length]; @@ -630,8 +635,8 @@ private static JpegColorConverterBase.ComponentValues CreateRandomValues( } // no need to dispose when buffer is not array owner - var memory = new Memory(values); - var source = MemoryGroup.Wrap(memory); + Memory memory = new(values); + MemoryGroup source = MemoryGroup.Wrap(memory); buffers[i] = new Buffer2D(source, values.Length, 1); } @@ -786,9 +791,9 @@ private static void ValidateYCbCr(in JpegColorConverterBase.ComponentValues valu float y = values.Component0[i]; float cb = values.Component1[i]; float cr = values.Component2[i]; - Rgb expected = ColorSpaceConverter.ToRgb(new YCbCr(y, cb, cr)); + Rgb expected = ColorSpaceConverter.Convert(new YCbCr(y, cb, cr)); - Rgb actual = new(result.Component0[i], result.Component1[i], result.Component2[i]); + Rgb actual = Rgb.Clamp(new(result.Component0[i], result.Component1[i], result.Component2[i])); bool equal = ColorSpaceComparer.Equals(expected, actual); Assert.True(equal, $"Colors {expected} and {actual} are not equal at index {i}"); @@ -810,9 +815,9 @@ private static void ValidateCyyK(in JpegColorConverterBase.ComponentValues value r /= MaxColorChannelValue; g /= MaxColorChannelValue; b /= MaxColorChannelValue; - var expected = new Rgb(r, g, b); + Rgb expected = Rgb.Clamp(new(r, g, b)); - var actual = new Rgb(result.Component0[i], result.Component1[i], result.Component2[i]); + Rgb actual = Rgb.Clamp(new(result.Component0[i], result.Component1[i], result.Component2[i])); bool equal = ColorSpaceComparer.Equals(expected, actual); Assert.True(equal, $"Colors {expected} and {actual} are not equal at index {i}"); @@ -823,9 +828,9 @@ private static void ValidateRgb(in JpegColorConverterBase.ComponentValues values float r = values.Component0[i] / MaxColorChannelValue; float g = values.Component1[i] / MaxColorChannelValue; float b = values.Component2[i] / MaxColorChannelValue; - var expected = new Rgb(r, g, b); + Rgb expected = Rgb.Clamp(new(r, g, b)); - var actual = new Rgb(result.Component0[i], result.Component1[i], result.Component2[i]); + Rgb actual = Rgb.Clamp(new(result.Component0[i], result.Component1[i], result.Component2[i])); bool equal = ColorSpaceComparer.Equals(expected, actual); Assert.True(equal, $"Colors {expected} and {actual} are not equal at index {i}"); @@ -834,9 +839,9 @@ private static void ValidateRgb(in JpegColorConverterBase.ComponentValues values private static void ValidateGrayScale(in JpegColorConverterBase.ComponentValues values, in JpegColorConverterBase.ComponentValues result, int i) { float y = values.Component0[i] / MaxColorChannelValue; - var expected = new Rgb(y, y, y); + Rgb expected = Rgb.Clamp(new(y, y, y)); - var actual = new Rgb(result.Component0[i], result.Component0[i], result.Component0[i]); + Rgb actual = Rgb.Clamp(new(result.Component0[i], result.Component0[i], result.Component0[i])); bool equal = ColorSpaceComparer.Equals(expected, actual); Assert.True(equal, $"Colors {expected} and {actual} are not equal at index {i}"); @@ -852,9 +857,9 @@ private static void ValidateCmyk(in JpegColorConverterBase.ComponentValues value float r = c * k / MaxColorChannelValue; float g = m * k / MaxColorChannelValue; float b = y * k / MaxColorChannelValue; - var expected = new Rgb(r, g, b); + Rgb expected = Rgb.Clamp(new(r, g, b)); - var actual = new Rgb(result.Component0[i], result.Component1[i], result.Component2[i]); + Rgb actual = Rgb.Clamp(new(result.Component0[i], result.Component1[i], result.Component2[i])); bool equal = ColorSpaceComparer.Equals(expected, actual); Assert.True(equal, $"Colors {expected} and {actual} are not equal at index {i}"); diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Metadata.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Metadata.cs index e68dd1f879..a803372537 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Metadata.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Metadata.cs @@ -146,14 +146,14 @@ public async Task Decode_VerifyQualityAsync(string imagePath, int quality) } [Theory] - [InlineData(TestImages.Jpeg.Baseline.Floorplan, JpegEncodingColor.Luminance)] - [InlineData(TestImages.Jpeg.Baseline.Jpeg420Small, JpegEncodingColor.YCbCrRatio420)] - [InlineData(TestImages.Jpeg.Baseline.Jpeg444, JpegEncodingColor.YCbCrRatio444)] - [InlineData(TestImages.Jpeg.Baseline.JpegRgb, JpegEncodingColor.Rgb)] - [InlineData(TestImages.Jpeg.Baseline.Cmyk, JpegEncodingColor.Cmyk)] - [InlineData(TestImages.Jpeg.Baseline.Jpeg410, JpegEncodingColor.YCbCrRatio410)] - [InlineData(TestImages.Jpeg.Baseline.Jpeg411, JpegEncodingColor.YCbCrRatio411)] - public void Identify_DetectsCorrectColorType(string imagePath, JpegEncodingColor expectedColorType) + [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.Jpeg411, JpegColorType.YCbCrRatio411)] + public void Identify_DetectsCorrectColorType(string imagePath, JpegColorType expectedColorType) { TestFile testFile = TestFile.Create(imagePath); using MemoryStream stream = new(testFile.Bytes, false); @@ -163,12 +163,12 @@ public void Identify_DetectsCorrectColorType(string imagePath, JpegEncodingColor } [Theory] - [WithFile(TestImages.Jpeg.Baseline.Floorplan, PixelTypes.Rgb24, JpegEncodingColor.Luminance)] - [WithFile(TestImages.Jpeg.Baseline.Jpeg420Small, PixelTypes.Rgb24, JpegEncodingColor.YCbCrRatio420)] - [WithFile(TestImages.Jpeg.Baseline.Jpeg444, PixelTypes.Rgb24, JpegEncodingColor.YCbCrRatio444)] - [WithFile(TestImages.Jpeg.Baseline.JpegRgb, PixelTypes.Rgb24, JpegEncodingColor.Rgb)] - [WithFile(TestImages.Jpeg.Baseline.Cmyk, PixelTypes.Rgb24, JpegEncodingColor.Cmyk)] - public void Decode_DetectsCorrectColorType(TestImageProvider provider, JpegEncodingColor expectedColorType) + [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.Instance); @@ -426,6 +426,22 @@ public void EncodedStringTags_Read() VerifyEncodedStrings(exif); } + [Theory] + [WithFile(TestImages.Jpeg.Issues.Issue2067_CommentMarker, PixelTypes.Rgba32)] + public void JpegDecoder_DecodeMetadataComment(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + string expectedComment = "TEST COMMENT"; + using Image image = provider.GetImage(JpegDecoder.Instance); + JpegMetadata metadata = image.Metadata.GetJpegMetadata(); + + Assert.Equal(1, metadata.Comments.Count); + Assert.Equal(expectedComment, metadata.Comments.ElementAtOrDefault(0).ToString()); + image.DebugSave(provider); + image.CompareToOriginal(provider); + + } + // https://github.com/SixLabors/ImageSharp/issues/2758 [Theory] [WithFile(TestImages.Jpeg.Issues.Issue2758, PixelTypes.L8)] diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs index 97be5d8383..950265bd56 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs @@ -20,7 +20,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg; [ValidateDisposedMemoryAllocations] public partial class JpegDecoderTests { - private static MagickReferenceDecoder ReferenceDecoder => new(); + private static MagickReferenceDecoder ReferenceDecoder => MagickReferenceDecoder.Jpeg; public const PixelTypes CommonNonDefaultPixelTypes = PixelTypes.Rgba32 | PixelTypes.Argb32 | PixelTypes.Bgr24 | PixelTypes.RgbaVector; diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.Metadata.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.Metadata.cs index 2b721b9b51..039215bbc5 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.Metadata.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.Metadata.cs @@ -32,19 +32,19 @@ public partial class JpegEncoderTests public void Encode_PreservesIptcProfile() { // arrange - using var input = new Image(1, 1); - var expectedProfile = new IptcProfile(); + using Image input = new(1, 1); + IptcProfile expectedProfile = new(); expectedProfile.SetValue(IptcTag.Country, "ESPAÑA"); expectedProfile.SetValue(IptcTag.City, "unit-test-city"); input.Metadata.IptcProfile = expectedProfile; // act - using var memStream = new MemoryStream(); + using MemoryStream memStream = new(); input.Save(memStream, JpegEncoder); // assert memStream.Position = 0; - using var output = Image.Load(memStream); + using Image output = Image.Load(memStream); IptcProfile actual = output.Metadata.IptcProfile; Assert.NotNull(actual); IEnumerable values = expectedProfile.Values; @@ -55,17 +55,17 @@ public void Encode_PreservesIptcProfile() public void Encode_PreservesExifProfile() { // arrange - using var input = new Image(1, 1); + using Image input = new(1, 1); input.Metadata.ExifProfile = new ExifProfile(); input.Metadata.ExifProfile.SetValue(ExifTag.Software, "unit_test"); // act - using var memStream = new MemoryStream(); + using MemoryStream memStream = new(); input.Save(memStream, JpegEncoder); // assert memStream.Position = 0; - using var output = Image.Load(memStream); + using Image output = Image.Load(memStream); ExifProfile actual = output.Metadata.ExifProfile; Assert.NotNull(actual); IReadOnlyList values = input.Metadata.ExifProfile.Values; @@ -76,16 +76,16 @@ public void Encode_PreservesExifProfile() public void Encode_PreservesIccProfile() { // arrange - using var input = new Image(1, 1); + using Image input = new(1, 1); input.Metadata.IccProfile = new IccProfile(IccTestDataProfiles.Profile_Random_Array); // act - using var memStream = new MemoryStream(); + using MemoryStream memStream = new(); input.Save(memStream, JpegEncoder); // assert memStream.Position = 0; - using var output = Image.Load(memStream); + using Image output = Image.Load(memStream); IccProfile actual = output.Metadata.IccProfile; Assert.NotNull(actual); IccProfile values = input.Metadata.IccProfile; @@ -99,12 +99,10 @@ public void Encode_WithValidExifProfile_DoesNotThrowException(TestImageP { Exception ex = Record.Exception(() => { - var encoder = new JpegEncoder(); - using (var stream = new MemoryStream()) - { - using Image image = provider.GetImage(JpegDecoder.Instance); - image.Save(stream, encoder); - } + JpegEncoder encoder = new(); + using MemoryStream stream = new(); + using Image image = provider.GetImage(JpegDecoder.Instance); + image.Save(stream, encoder); }); Assert.Null(ex); @@ -114,64 +112,119 @@ public void Encode_WithValidExifProfile_DoesNotThrowException(TestImageP [MemberData(nameof(RatioFiles))] public void Encode_PreserveRatio(string imagePath, int xResolution, int yResolution, PixelResolutionUnit resolutionUnit) { - var testFile = TestFile.Create(imagePath); - using (Image input = testFile.CreateRgba32Image()) - { - using (var memStream = new MemoryStream()) - { - input.Save(memStream, JpegEncoder); - - memStream.Position = 0; - using (var output = Image.Load(memStream)) - { - ImageMetadata meta = output.Metadata; - Assert.Equal(xResolution, meta.HorizontalResolution); - Assert.Equal(yResolution, meta.VerticalResolution); - Assert.Equal(resolutionUnit, meta.ResolutionUnits); - } - } - } + TestFile testFile = TestFile.Create(imagePath); + using Image input = testFile.CreateRgba32Image(); + using MemoryStream memStream = new(); + input.Save(memStream, JpegEncoder); + + memStream.Position = 0; + using Image output = Image.Load(memStream); + ImageMetadata meta = output.Metadata; + Assert.Equal(xResolution, meta.HorizontalResolution); + Assert.Equal(yResolution, meta.VerticalResolution); + Assert.Equal(resolutionUnit, meta.ResolutionUnits); } [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, JpegEncoder); - - memStream.Position = 0; - using (var output = Image.Load(memStream)) - { - JpegMetadata meta = output.Metadata.GetJpegMetadata(); - Assert.Equal(quality, meta.Quality); - } - } - } + TestFile testFile = TestFile.Create(imagePath); + using Image input = testFile.CreateRgba32Image(); + using MemoryStream memStream = new(); + input.Save(memStream, JpegEncoder); + + memStream.Position = 0; + using Image output = Image.Load(memStream); + JpegMetadata meta = output.Metadata.GetJpegMetadata(); + Assert.Equal(quality, meta.Quality); + } + + [Theory] + [WithFile(TestImages.Jpeg.Issues.Issue2067_CommentMarker, PixelTypes.Rgba32)] + public void Encode_PreservesComments(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + // arrange + using Image input = provider.GetImage(JpegDecoder.Instance); + using MemoryStream memStream = new(); + + // act + input.Save(memStream, JpegEncoder); + + // assert + memStream.Position = 0; + using Image output = Image.Load(memStream); + JpegMetadata actual = output.Metadata.GetJpegMetadata(); + Assert.NotEmpty(actual.Comments); + Assert.Equal(1, actual.Comments.Count); + Assert.Equal("TEST COMMENT", actual.Comments[0].ToString()); + } + + [Fact] + public void Encode_SavesMultipleComments() + { + // arrange + using Image input = new(1, 1); + JpegMetadata meta = input.Metadata.GetJpegMetadata(); + using MemoryStream memStream = new(); + + // act + meta.Comments.Add(JpegComData.FromString("First comment")); + meta.Comments.Add(JpegComData.FromString("Second Comment")); + input.Save(memStream, JpegEncoder); + + // assert + memStream.Position = 0; + using Image output = Image.Load(memStream); + JpegMetadata actual = output.Metadata.GetJpegMetadata(); + Assert.NotEmpty(actual.Comments); + Assert.Equal(2, actual.Comments.Count); + Assert.Equal(meta.Comments[0].ToString(), actual.Comments[0].ToString()); + Assert.Equal(meta.Comments[1].ToString(), actual.Comments[1].ToString()); + } + + [Fact] + public void Encode_SaveTooLongComment() + { + // arrange + string longString = new('c', 65534); + using Image input = new(1, 1); + JpegMetadata meta = input.Metadata.GetJpegMetadata(); + using MemoryStream memStream = new(); + + // act + meta.Comments.Add(JpegComData.FromString(longString)); + input.Save(memStream, JpegEncoder); + + // assert + memStream.Position = 0; + using Image output = Image.Load(memStream); + JpegMetadata actual = output.Metadata.GetJpegMetadata(); + Assert.NotEmpty(actual.Comments); + Assert.Equal(2, actual.Comments.Count); + Assert.Equal(longString[..65533], actual.Comments[0].ToString()); + Assert.Equal("c", actual.Comments[1].ToString()); } [Theory] - [WithFile(TestImages.Jpeg.Baseline.Floorplan, PixelTypes.Rgb24, JpegEncodingColor.Luminance)] - [WithFile(TestImages.Jpeg.Baseline.Jpeg444, PixelTypes.Rgb24, JpegEncodingColor.YCbCrRatio444)] - [WithFile(TestImages.Jpeg.Baseline.Jpeg420Small, PixelTypes.Rgb24, JpegEncodingColor.YCbCrRatio420)] - [WithFile(TestImages.Jpeg.Baseline.JpegRgb, PixelTypes.Rgb24, JpegEncodingColor.Rgb)] - public void Encode_PreservesColorType(TestImageProvider provider, JpegEncodingColor expectedColorType) + [WithFile(TestImages.Jpeg.Baseline.Floorplan, PixelTypes.Rgb24, JpegColorType.Luminance)] + [WithFile(TestImages.Jpeg.Baseline.Jpeg444, PixelTypes.Rgb24, JpegColorType.YCbCrRatio444)] + [WithFile(TestImages.Jpeg.Baseline.Jpeg420Small, PixelTypes.Rgb24, JpegColorType.YCbCrRatio420)] + [WithFile(TestImages.Jpeg.Baseline.JpegRgb, PixelTypes.Rgb24, JpegColorType.Rgb)] + public void Encode_PreservesColorType(TestImageProvider provider, JpegColorType expectedColorType) where TPixel : unmanaged, IPixel { // arrange using Image input = provider.GetImage(JpegDecoder.Instance); - using var memoryStream = new MemoryStream(); + using MemoryStream memoryStream = new(); // act input.Save(memoryStream, JpegEncoder); // assert memoryStream.Position = 0; - using var output = Image.Load(memoryStream); + using Image output = Image.Load(memoryStream); JpegMetadata meta = output.Metadata.GetJpegMetadata(); Assert.Equal(expectedColorType, meta.ColorType); } diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs index 5842c8e1a0..1f4b3e4656 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs @@ -21,51 +21,51 @@ public partial class JpegEncoderTests 100, }; - public static readonly TheoryData NonSubsampledEncodingSetups = new() + public static readonly TheoryData NonSubsampledEncodingSetups = new() { - { JpegEncodingColor.Rgb, 100, 0.0238f / 100 }, - { JpegEncodingColor.Rgb, 80, 1.3044f / 100 }, - { JpegEncodingColor.Rgb, 40, 2.9879f / 100 }, - { JpegEncodingColor.YCbCrRatio444, 100, 0.0780f / 100 }, - { JpegEncodingColor.YCbCrRatio444, 80, 1.4585f / 100 }, - { JpegEncodingColor.YCbCrRatio444, 40, 3.1413f / 100 }, + { JpegColorType.Rgb, 100, 0.0238f / 100 }, + { JpegColorType.Rgb, 80, 1.3044f / 100 }, + { JpegColorType.Rgb, 40, 2.9879f / 100 }, + { JpegColorType.YCbCrRatio444, 100, 0.0780f / 100 }, + { JpegColorType.YCbCrRatio444, 80, 1.4585f / 100 }, + { JpegColorType.YCbCrRatio444, 40, 3.1413f / 100 }, }; - public static readonly TheoryData SubsampledEncodingSetups = new() + public static readonly TheoryData SubsampledEncodingSetups = new() { - { JpegEncodingColor.YCbCrRatio422, 100, 0.4895f / 100 }, - { JpegEncodingColor.YCbCrRatio422, 80, 1.6043f / 100 }, - { JpegEncodingColor.YCbCrRatio422, 40, 3.1996f / 100 }, - { JpegEncodingColor.YCbCrRatio420, 100, 0.5790f / 100 }, - { JpegEncodingColor.YCbCrRatio420, 80, 1.6692f / 100 }, - { JpegEncodingColor.YCbCrRatio420, 40, 3.2324f / 100 }, - { JpegEncodingColor.YCbCrRatio411, 100, 0.6868f / 100 }, - { JpegEncodingColor.YCbCrRatio411, 80, 1.7139f / 100 }, - { JpegEncodingColor.YCbCrRatio411, 40, 3.2634f / 100 }, - { JpegEncodingColor.YCbCrRatio410, 100, 0.7357f / 100 }, - { JpegEncodingColor.YCbCrRatio410, 80, 1.7495f / 100 }, - { JpegEncodingColor.YCbCrRatio410, 40, 3.2911f / 100 }, + { JpegColorType.YCbCrRatio422, 100, 0.4895f / 100 }, + { JpegColorType.YCbCrRatio422, 80, 1.6043f / 100 }, + { JpegColorType.YCbCrRatio422, 40, 3.1996f / 100 }, + { JpegColorType.YCbCrRatio420, 100, 0.5790f / 100 }, + { JpegColorType.YCbCrRatio420, 80, 1.6692f / 100 }, + { JpegColorType.YCbCrRatio420, 40, 3.2324f / 100 }, + { JpegColorType.YCbCrRatio411, 100, 0.6868f / 100 }, + { JpegColorType.YCbCrRatio411, 80, 1.7139f / 100 }, + { JpegColorType.YCbCrRatio411, 40, 3.2634f / 100 }, + { JpegColorType.YCbCrRatio410, 100, 0.7357f / 100 }, + { JpegColorType.YCbCrRatio410, 80, 1.7495f / 100 }, + { JpegColorType.YCbCrRatio410, 40, 3.2911f / 100 }, }; - public static readonly TheoryData CmykEncodingSetups = new() + public static readonly TheoryData CmykEncodingSetups = new() { - { JpegEncodingColor.Cmyk, 100, 0.0159f / 100 }, - { JpegEncodingColor.Cmyk, 80, 0.3922f / 100 }, - { JpegEncodingColor.Cmyk, 40, 0.6488f / 100 }, + { JpegColorType.Cmyk, 100, 0.0159f / 100 }, + { JpegColorType.Cmyk, 80, 0.3922f / 100 }, + { JpegColorType.Cmyk, 40, 0.6488f / 100 }, }; - public static readonly TheoryData YcckEncodingSetups = new() + public static readonly TheoryData YcckEncodingSetups = new() { - { JpegEncodingColor.Ycck, 100, 0.0356f / 100 }, - { JpegEncodingColor.Ycck, 80, 0.1245f / 100 }, - { JpegEncodingColor.Ycck, 40, 0.2663f / 100 }, + { JpegColorType.Ycck, 100, 0.0356f / 100 }, + { JpegColorType.Ycck, 80, 0.1245f / 100 }, + { JpegColorType.Ycck, 40, 0.2663f / 100 }, }; - public static readonly TheoryData LuminanceEncodingSetups = new() + public static readonly TheoryData LuminanceEncodingSetups = new() { - { JpegEncodingColor.Luminance, 100, 0.0175f / 100 }, - { JpegEncodingColor.Luminance, 80, 0.6730f / 100 }, - { JpegEncodingColor.Luminance, 40, 0.9943f / 100 }, + { JpegColorType.Luminance, 100, 0.0175f / 100 }, + { JpegColorType.Luminance, 80, 0.6730f / 100 }, + { JpegColorType.Luminance, 40, 0.9943f / 100 }, }; [Theory] @@ -74,7 +74,7 @@ public partial class JpegEncoderTests [WithFile(TestImages.Png.BikeGrayscale, nameof(LuminanceEncodingSetups), PixelTypes.L8)] [WithFile(TestImages.Jpeg.Baseline.Cmyk, nameof(CmykEncodingSetups), PixelTypes.Rgb24)] [WithFile(TestImages.Jpeg.Baseline.Ycck, nameof(YcckEncodingSetups), PixelTypes.Rgb24)] - public void EncodeBaseline_Interleaved(TestImageProvider provider, JpegEncodingColor colorType, int quality, float tolerance) + public void EncodeBaseline_Interleaved(TestImageProvider provider, JpegColorType colorType, int quality, float tolerance) where TPixel : unmanaged, IPixel => TestJpegEncoderCore(provider, colorType, quality, tolerance); [Theory] @@ -83,7 +83,7 @@ public void EncodeBaseline_Interleaved(TestImageProvider provide [WithFile(TestImages.Png.BikeGrayscale, nameof(LuminanceEncodingSetups), PixelTypes.L8)] [WithFile(TestImages.Jpeg.Baseline.Cmyk, nameof(CmykEncodingSetups), PixelTypes.Rgb24)] [WithFile(TestImages.Jpeg.Baseline.Ycck, nameof(YcckEncodingSetups), PixelTypes.Rgb24)] - public void EncodeBaseline_NonInterleavedMode(TestImageProvider provider, JpegEncodingColor colorType, int quality, float tolerance) + public void EncodeBaseline_NonInterleavedMode(TestImageProvider provider, JpegColorType colorType, int quality, float tolerance) where TPixel : unmanaged, IPixel { using Image image = provider.GetImage(); @@ -108,7 +108,7 @@ public void EncodeBaseline_NonInterleavedMode(TestImageProvider [WithTestPatternImages(nameof(NonSubsampledEncodingSetups), 153, 21, PixelTypes.Rgb24)] [WithTestPatternImages(nameof(NonSubsampledEncodingSetups), 143, 81, PixelTypes.Rgb24)] [WithTestPatternImages(nameof(NonSubsampledEncodingSetups), 138, 24, PixelTypes.Rgb24)] - public void EncodeBaseline_WorksWithDifferentSizes(TestImageProvider provider, JpegEncodingColor colorType, int quality, float tolerance) + public void EncodeBaseline_WorksWithDifferentSizes(TestImageProvider provider, JpegColorType colorType, int quality, float tolerance) where TPixel : unmanaged, IPixel => TestJpegEncoderCore(provider, colorType, quality); [Theory] @@ -121,7 +121,7 @@ public void EncodeBaseline_WorksWithDifferentSizes(TestImageProvider(TestImageProvider provider, JpegEncodingColor colorType, int quality, float tolerance) + public void EncodeBaseline_WithSmallImages_WorksWithDifferentSizes(TestImageProvider provider, JpegColorType colorType, int quality, float tolerance) where TPixel : unmanaged, IPixel => TestJpegEncoderCore(provider, colorType, quality, ImageComparer.Tolerant(0.12f)); [Theory] @@ -131,28 +131,28 @@ public void EncodeBaseline_WithSmallImages_WorksWithDifferentSizes(TestI [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, JpegEncodingColor.Luminance, quality); + where TPixel : unmanaged, IPixel => TestJpegEncoderCore(provider, JpegColorType.Luminance, quality); [Theory] [WithTestPatternImages(nameof(NonSubsampledEncodingSetups), 96, 96, PixelTypes.Rgb24 | PixelTypes.Bgr24)] [WithTestPatternImages(nameof(NonSubsampledEncodingSetups), 48, 48, PixelTypes.Rgb24 | PixelTypes.Bgr24)] - public void EncodeBaseline_IsNotBoundToSinglePixelType(TestImageProvider provider, JpegEncodingColor colorType, int quality, float tolerance) + public void EncodeBaseline_IsNotBoundToSinglePixelType(TestImageProvider provider, JpegColorType colorType, int quality, float tolerance) where TPixel : unmanaged, IPixel => TestJpegEncoderCore(provider, colorType, quality); [Theory] [WithTestPatternImages(nameof(NonSubsampledEncodingSetups), 48, 48, PixelTypes.Rgb24 | PixelTypes.Bgr24)] - public void EncodeBaseline_WithSmallImages_IsNotBoundToSinglePixelType(TestImageProvider provider, JpegEncodingColor colorType, int quality, float tolerance) + public void EncodeBaseline_WithSmallImages_IsNotBoundToSinglePixelType(TestImageProvider provider, JpegColorType colorType, int quality, float tolerance) where TPixel : unmanaged, IPixel => TestJpegEncoderCore(provider, colorType, quality, comparer: ImageComparer.Tolerant(0.06f)); [Theory] - [WithFile(TestImages.Png.CalliphoraPartial, PixelTypes.Rgb24, JpegEncodingColor.YCbCrRatio444)] - [WithTestPatternImages(587, 821, PixelTypes.Rgb24, JpegEncodingColor.YCbCrRatio444)] - [WithTestPatternImages(677, 683, PixelTypes.Rgb24, JpegEncodingColor.YCbCrRatio420)] - [WithSolidFilledImages(400, 400, nameof(Color.Red), PixelTypes.Rgb24, JpegEncodingColor.YCbCrRatio420)] - public void EncodeBaseline_WorksWithDiscontiguousBuffers(TestImageProvider provider, JpegEncodingColor colorType) + [WithFile(TestImages.Png.CalliphoraPartial, PixelTypes.Rgb24, JpegColorType.YCbCrRatio444)] + [WithTestPatternImages(587, 821, PixelTypes.Rgb24, JpegColorType.YCbCrRatio444)] + [WithTestPatternImages(677, 683, PixelTypes.Rgb24, JpegColorType.YCbCrRatio420)] + [WithSolidFilledImages(400, 400, nameof(Color.Red), PixelTypes.Rgb24, JpegColorType.YCbCrRatio420)] + public void EncodeBaseline_WorksWithDiscontiguousBuffers(TestImageProvider provider, JpegColorType colorType) where TPixel : unmanaged, IPixel { - ImageComparer comparer = colorType == JpegEncodingColor.YCbCrRatio444 + ImageComparer comparer = colorType == JpegColorType.YCbCrRatio444 ? ImageComparer.TolerantPercentage(0.1f) : ImageComparer.TolerantPercentage(5f); @@ -161,9 +161,9 @@ public void EncodeBaseline_WorksWithDiscontiguousBuffers(TestImageProvid } [Theory] - [InlineData(JpegEncodingColor.YCbCrRatio420)] - [InlineData(JpegEncodingColor.YCbCrRatio444)] - public async Task Encode_IsCancellable(JpegEncodingColor colorType) + [InlineData(JpegColorType.YCbCrRatio420)] + [InlineData(JpegColorType.YCbCrRatio444)] + public async Task Encode_IsCancellable(JpegColorType colorType) { CancellationTokenSource cts = new(); using PausedStream pausedStream = new(new MemoryStream()); @@ -201,13 +201,13 @@ public static void Issue2595(TestImageProvider provider) image.Mutate(x => x.Crop(132, 1606)); int[] quality = new int[] { 100, 50 }; - JpegEncodingColor[] colors = new[] { JpegEncodingColor.YCbCrRatio444, JpegEncodingColor.YCbCrRatio420 }; + JpegColorType[] colors = new[] { JpegColorType.YCbCrRatio444, JpegColorType.YCbCrRatio420 }; for (int i = 0; i < quality.Length; i++) { int q = quality[i]; for (int j = 0; j < colors.Length; j++) { - JpegEncodingColor c = colors[j]; + JpegColorType c = colors[j]; image.VerifyEncoder(provider, "jpeg", $"{q}-{c}", new JpegEncoder() { Quality = q, ColorType = c }, GetComparer(q, c)); } } @@ -216,7 +216,7 @@ public static void Issue2595(TestImageProvider provider) /// /// Anton's SUPER-SCIENTIFIC tolerance threshold calculation /// - private static ImageComparer GetComparer(int quality, JpegEncodingColor? colorType) + private static ImageComparer GetComparer(int quality, JpegColorType? colorType) { float tolerance = 0.015f; // ~1.5% @@ -224,10 +224,10 @@ private static ImageComparer GetComparer(int quality, JpegEncodingColor? colorTy { tolerance *= 4.5f; } - else if (quality < 75 || colorType == JpegEncodingColor.YCbCrRatio420) + else if (quality < 75 || colorType == JpegColorType.YCbCrRatio420) { tolerance *= 2.0f; - if (colorType == JpegEncodingColor.YCbCrRatio420) + if (colorType == JpegColorType.YCbCrRatio420) { tolerance *= 2.0f; } @@ -236,15 +236,15 @@ private static ImageComparer GetComparer(int quality, JpegEncodingColor? colorTy return ImageComparer.Tolerant(tolerance); } - private static void TestJpegEncoderCore(TestImageProvider provider, JpegEncodingColor colorType, int quality) + private static void TestJpegEncoderCore(TestImageProvider provider, JpegColorType colorType, int quality) where TPixel : unmanaged, IPixel => TestJpegEncoderCore(provider, colorType, quality, GetComparer(quality, colorType)); - private static void TestJpegEncoderCore(TestImageProvider provider, JpegEncodingColor colorType, int quality, float tolerance) + private static void TestJpegEncoderCore(TestImageProvider provider, JpegColorType colorType, int quality, float tolerance) where TPixel : unmanaged, IPixel => TestJpegEncoderCore(provider, colorType, quality, new TolerantImageComparer(tolerance)); - private static void TestJpegEncoderCore(TestImageProvider provider, JpegEncodingColor colorType, int quality, ImageComparer comparer) + private static void TestJpegEncoderCore(TestImageProvider provider, JpegColorType colorType, int quality, ImageComparer comparer) where TPixel : unmanaged, IPixel { using Image image = provider.GetImage(); diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegMetadataTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegMetadataTests.cs index 05f22667dc..19b5265a17 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegMetadataTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegMetadataTests.cs @@ -1,6 +1,7 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. +using System.Collections.ObjectModel; using SixLabors.ImageSharp.Formats.Jpeg; namespace SixLabors.ImageSharp.Tests.Formats.Jpg; @@ -11,10 +12,10 @@ public class JpegMetadataTests [Fact] public void CloneIsDeep() { - var meta = new JpegMetadata { ColorType = JpegEncodingColor.Luminance }; + var meta = new JpegMetadata { ColorType = JpegColorType.Luminance }; var clone = (JpegMetadata)meta.DeepClone(); - clone.ColorType = JpegEncodingColor.YCbCrRatio420; + clone.ColorType = JpegColorType.YCbCrRatio420; Assert.False(meta.ColorType.Equals(clone.ColorType)); } @@ -57,4 +58,25 @@ public void Quality_ReturnsMaxQuality() Assert.Equal(meta.Quality, qualityLuma); } + + [Fact] + public void Comment_EmptyComment() + { + var meta = new JpegMetadata(); + + Assert.True(Array.Empty().SequenceEqual(meta.Comments)); + } + + [Fact] + public void Comment_OnlyComment() + { + string comment = "test comment"; + var expectedCollection = new Collection { comment }; + + var meta = new JpegMetadata(); + meta.Comments.Add(JpegComData.FromString(comment)); + + Assert.Equal(1, meta.Comments.Count); + Assert.True(expectedCollection.FirstOrDefault() == meta.Comments.FirstOrDefault().ToString()); + } } diff --git a/tests/ImageSharp.Tests/Formats/Jpg/Utils/LibJpegTools.ComponentData.cs b/tests/ImageSharp.Tests/Formats/Jpg/Utils/LibJpegTools.ComponentData.cs index 80365b4724..65d0a01ffe 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/Utils/LibJpegTools.ComponentData.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/Utils/LibJpegTools.ComponentData.cs @@ -42,7 +42,7 @@ public ComponentData(int widthInBlocks, int heightInBlocks, int index) public int QuantizationTableIndex => throw new NotSupportedException(); - public Buffer2D SpectralBlocks { get; private set; } + public Buffer2D SpectralBlocks { get; } public short MinVal { get; private set; } = short.MaxValue; @@ -102,7 +102,7 @@ public void LoadSpectral(IJpegComponent c) public static ComponentData Load(JpegComponent c, int index) { - var result = new ComponentData( + ComponentData result = new( c.WidthInBlocks, c.HeightInBlocks, index); @@ -113,7 +113,7 @@ public static ComponentData Load(JpegComponent c, int index) public Image CreateGrayScaleImage() { - var result = new Image(this.WidthInBlocks * 8, this.HeightInBlocks * 8); + Image result = new(this.WidthInBlocks * 8, this.HeightInBlocks * 8); for (int by = 0; by < this.HeightInBlocks; by++) { @@ -136,9 +136,8 @@ internal void WriteToImage(int bx, int by, Image image) { float val = this.GetBlockValue(block, x, y); - var v = new Vector4(val, val, val, 1); - Rgba32 color = default; - color.FromVector4(v); + Vector4 v = new(val, val, val, 1); + Rgba32 color = Rgba32.FromVector4(v); int yy = (by * 8) + y; int xx = (bx * 8) + x; @@ -198,7 +197,7 @@ public override bool Equals(object obj) return false; } - if (object.ReferenceEquals(this, obj)) + if (ReferenceEquals(this, obj)) { return true; } diff --git a/tests/ImageSharp.Tests/Formats/Jpg/Utils/LibJpegTools.SpectralData.cs b/tests/ImageSharp.Tests/Formats/Jpg/Utils/LibJpegTools.SpectralData.cs index a4bb6b7bfc..9eec547a36 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/Utils/LibJpegTools.SpectralData.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/Utils/LibJpegTools.SpectralData.cs @@ -14,11 +14,11 @@ internal static partial class LibJpegTools /// public class SpectralData : IEquatable { - public int ComponentCount { get; private set; } + public int ComponentCount { get; } - public LibJpegTools.ComponentData[] Components { get; private set; } + public ComponentData[] Components { get; } - internal SpectralData(LibJpegTools.ComponentData[] components) + internal SpectralData(ComponentData[] components) { this.ComponentCount = components.Length; this.Components = components; @@ -31,16 +31,16 @@ public Image TryCreateRGBSpectralImage() return null; } - LibJpegTools.ComponentData c0 = this.Components[0]; - LibJpegTools.ComponentData c1 = this.Components[1]; - LibJpegTools.ComponentData c2 = this.Components[2]; + ComponentData c0 = this.Components[0]; + ComponentData c1 = this.Components[1]; + ComponentData c2 = this.Components[2]; if (c0.Size != c1.Size || c1.Size != c2.Size) { return null; } - var result = new Image(c0.WidthInBlocks * 8, c0.HeightInBlocks * 8); + Image result = new(c0.WidthInBlocks * 8, c0.HeightInBlocks * 8); for (int by = 0; by < c0.HeightInBlocks; by++) { @@ -55,18 +55,14 @@ public Image TryCreateRGBSpectralImage() internal void WriteToImage(int bx, int by, Image image) { - LibJpegTools.ComponentData c0 = this.Components[0]; - LibJpegTools.ComponentData c1 = this.Components[1]; - LibJpegTools.ComponentData c2 = this.Components[2]; + ComponentData c0 = this.Components[0]; + ComponentData c1 = this.Components[1]; + ComponentData c2 = this.Components[2]; Block8x8 block0 = c0.SpectralBlocks[bx, by]; Block8x8 block1 = c1.SpectralBlocks[bx, by]; Block8x8 block2 = c2.SpectralBlocks[bx, by]; - float d0 = c0.MaxVal - c0.MinVal; - float d1 = c1.MaxVal - c1.MinVal; - float d2 = c2.MaxVal - c2.MinVal; - for (int y = 0; y < 8; y++) { for (int x = 0; x < 8; x++) @@ -75,9 +71,8 @@ internal void WriteToImage(int bx, int by, Image image) float val1 = c0.GetBlockValue(block1, x, y); float val2 = c0.GetBlockValue(block2, x, y); - var v = new Vector4(val0, val1, val2, 1); - Rgba32 color = default; - color.FromVector4(v); + Vector4 v = new(val0, val1, val2, 1); + Rgba32 color = Rgba32.FromVector4(v); int yy = (by * 8) + y; int xx = (bx * 8) + x; @@ -105,8 +100,8 @@ public bool Equals(SpectralData other) for (int i = 0; i < this.ComponentCount; i++) { - LibJpegTools.ComponentData a = this.Components[i]; - LibJpegTools.ComponentData b = other.Components[i]; + ComponentData a = this.Components[i]; + ComponentData b = other.Components[i]; if (!a.Equals(b)) { return false; @@ -116,10 +111,7 @@ public bool Equals(SpectralData other) return true; } - public override bool Equals(object obj) - { - return obj is SpectralData other && this.Equals(other); - } + public override bool Equals(object obj) => obj is SpectralData other && this.Equals(other); public override int GetHashCode() { @@ -139,9 +131,6 @@ public override int GetHashCode() return left.Equals(right); } - public static bool operator !=(SpectralData left, SpectralData right) - { - return !(left == right); - } + public static bool operator !=(SpectralData left, SpectralData right) => !(left == right); } } diff --git a/tests/ImageSharp.Tests/Formats/Pbm/PbmMetadataTests.cs b/tests/ImageSharp.Tests/Formats/Pbm/PbmMetadataTests.cs index a69d9d9ba7..243a62d592 100644 --- a/tests/ImageSharp.Tests/Formats/Pbm/PbmMetadataTests.cs +++ b/tests/ImageSharp.Tests/Formats/Pbm/PbmMetadataTests.cs @@ -1,7 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.Formats.Pbm; using static SixLabors.ImageSharp.Tests.TestImages.Pbm; diff --git a/tests/ImageSharp.Tests/Formats/Png/Crc32Tests.cs b/tests/ImageSharp.Tests/Formats/Png/Crc32Tests.cs deleted file mode 100644 index ff91590f95..0000000000 --- a/tests/ImageSharp.Tests/Formats/Png/Crc32Tests.cs +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.Compression.Zlib; -using SixLabors.ImageSharp.Tests.TestUtilities; -using SharpCrc32 = ICSharpCode.SharpZipLib.Checksum.Crc32; - -namespace SixLabors.ImageSharp.Tests.Formats.Png; - -[Trait("Format", "Png")] -public class Crc32Tests -{ - [Theory] - [InlineData(0)] - [InlineData(1)] - [InlineData(2)] - public void CalculateCrc_ReturnsCorrectResultWhenEmpty(uint input) => Assert.Equal(input, Crc32.Calculate(input, default)); - - [Theory] - [InlineData(0)] - [InlineData(8)] - [InlineData(215)] - [InlineData(1024)] - [InlineData(1024 + 15)] - [InlineData(2034)] - [InlineData(4096)] - public void CalculateCrc_MatchesReference(int length) => CalculateCrcAndCompareToReference(length); - - private static void CalculateCrcAndCompareToReference(int length) - { - // arrange - byte[] data = GetBuffer(length); - SharpCrc32 crc = new(); - crc.Update(data); - long expected = crc.Value; - - // act - long actual = Crc32.Calculate(data); - - // assert - Assert.Equal(expected, actual); - } - - private static byte[] GetBuffer(int length) - { - byte[] data = new byte[length]; - new Random(1).NextBytes(data); - - return data; - } - - [Fact] - public void RunCalculateCrcTest_WithHardwareIntrinsics_Works() => FeatureTestRunner.RunWithHwIntrinsicsFeature(RunCalculateCrcTest, HwIntrinsics.AllowAll); - - [Fact] - public void RunCalculateCrcTest_WithoutHardwareIntrinsics_Works() => FeatureTestRunner.RunWithHwIntrinsicsFeature(RunCalculateCrcTest, HwIntrinsics.DisableHWIntrinsic); - - private static void RunCalculateCrcTest() - { - int[] testData = { 0, 8, 215, 1024, 1024 + 15, 2034, 4096 }; - for (int i = 0; i < testData.Length; i++) - { - CalculateCrcAndCompareToReference(testData[i]); - } - } -} diff --git a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs index 11af57e39f..9f3c5f6828 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs @@ -381,6 +381,20 @@ public void Identify(string imagePath, int expectedPixelSize) Assert.Equal(expectedPixelSize, imageInfo.PixelType.BitsPerPixel); } + [Theory] + [InlineData(TestImages.Png.Bad.WrongCrcDataChunk, 1)] + [InlineData(TestImages.Png.Bad.Issue2589, 24)] + public void Identify_IgnoreCrcErrors(string imagePath, int expectedPixelSize) + { + TestFile testFile = TestFile.Create(imagePath); + using MemoryStream stream = new(testFile.Bytes, false); + + ImageInfo imageInfo = Image.Identify(new DecoderOptions() { SegmentIntegrityHandling = SegmentIntegrityHandling.IgnoreData }, stream); + + Assert.NotNull(imageInfo); + Assert.Equal(expectedPixelSize, imageInfo.PixelType.BitsPerPixel); + } + [Theory] [WithFile(TestImages.Png.Bad.MissingDataChunk, PixelTypes.Rgba32)] public void Decode_MissingDataChunk_ThrowsException(TestImageProvider provider) @@ -479,13 +493,13 @@ public void Decode_InvalidDataChunkCrc_ThrowsException(TestImageProvider public void Decode_InvalidDataChunkCrc_IgnoreCrcErrors(TestImageProvider provider, bool compare) where TPixel : unmanaged, IPixel { - using Image image = provider.GetImage(PngDecoder.Instance, new PngDecoderOptions() { PngCrcChunkHandling = PngCrcChunkHandling.IgnoreData }); + using Image image = provider.GetImage(PngDecoder.Instance, new DecoderOptions() { SegmentIntegrityHandling = SegmentIntegrityHandling.IgnoreData }); image.DebugSave(provider); if (compare) { // Magick cannot actually decode this image to compare. - image.CompareToOriginal(provider, new MagickReferenceDecoder(false)); + image.CompareToOriginal(provider, new MagickReferenceDecoder(PngFormat.Instance, false)); } } @@ -552,7 +566,7 @@ public void Issue1047(TestImageProvider provider) // We don't have another x-plat reference decoder that can be compared for this image. if (TestEnvironment.IsWindows) { - image.CompareToOriginal(provider, ImageComparer.Exact, SystemDrawingReferenceDecoder.Instance); + image.CompareToOriginal(provider, ImageComparer.Exact, SystemDrawingReferenceDecoder.Png); } }); Assert.Null(ex); @@ -583,7 +597,7 @@ public void Issue2209_Decode_HasTransparencyIsTrue(TestImageProvider image = provider.GetImage(PngDecoder.Instance); PngMetadata metadata = image.Metadata.GetPngMetadata(); Assert.NotNull(metadata.ColorTable); - Assert.Contains(metadata.ColorTable.Value.ToArray(), x => x.ToRgba32().A < 255); + Assert.Contains(metadata.ColorTable.Value.ToArray(), x => x.ToPixel().A < 255); } // https://github.com/SixLabors/ImageSharp/issues/2209 @@ -596,7 +610,7 @@ public void Issue2209_Identify_HasTransparencyIsTrue(string imagePath) ImageInfo imageInfo = Image.Identify(stream); PngMetadata metadata = imageInfo.Metadata.GetPngMetadata(); Assert.NotNull(metadata.ColorTable); - Assert.Contains(metadata.ColorTable.Value.ToArray(), x => x.ToRgba32().A < 255); + Assert.Contains(metadata.ColorTable.Value.ToArray(), x => x.ToPixel().A < 255); } // https://github.com/SixLabors/ImageSharp/issues/410 @@ -614,7 +628,7 @@ public void Issue410_MalformedApplePng(TestImageProvider provide // We don't have another x-plat reference decoder that can be compared for this image. if (TestEnvironment.IsWindows) { - image.CompareToOriginal(provider, ImageComparer.Exact, SystemDrawingReferenceDecoder.Instance); + image.CompareToOriginal(provider, ImageComparer.Exact, SystemDrawingReferenceDecoder.Png); } }); Assert.NotNull(ex); @@ -660,7 +674,7 @@ static void RunTest(string providerDump, string nonContiguousBuffersStr) public void Binary_PrematureEof() { PngDecoder decoder = PngDecoder.Instance; - PngDecoderOptions options = new() { PngCrcChunkHandling = PngCrcChunkHandling.IgnoreData }; + PngDecoderOptions options = new() { GeneralOptions = new() { SegmentIntegrityHandling = SegmentIntegrityHandling.IgnoreData } }; using EofHitCounter eofHitCounter = EofHitCounter.RunDecoder(TestImages.Png.Bad.FlagOfGermany0000016446, decoder, options); // TODO: Try to reduce this to 1. diff --git a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs index ca5aae961c..009327c17f 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs @@ -254,49 +254,6 @@ public void WorksWithAllBitDepthsAndExcludeAllFilter(TestImageProvider(TestImageProvider provider, PngColorType pngColorType, PngBitDepth pngBitDepth) - where TPixel : unmanaged, IPixel - { - using Stream stream = new MemoryStream(); - PngEncoder.Encode(provider.GetImage(), stream); - - stream.Seek(0, SeekOrigin.Begin); - - using Image image = PngDecoder.Instance.Decode(DecoderOptions.Default, stream); - - PngMetadata metadata = image.Metadata.GetPngMetadata(); - Assert.Equal(pngColorType, metadata.ColorType); - Assert.Equal(pngBitDepth, metadata.BitDepth); - } - [Theory] [WithFile(TestImages.Png.Palette8Bpp, nameof(PaletteLargeOnly), PixelTypes.Rgba32)] public void PaletteColorType_WuQuantizer(TestImageProvider provider, int paletteSize) @@ -392,7 +349,7 @@ public void Encode_WithPngTransparentColorBehaviorClear_Works(PngColorType color TransparentColorMode = PngTransparentColorMode.Clear, ColorType = colorType }; - Rgba32 rgba32 = Color.Blue; + Rgba32 rgba32 = Color.Blue.ToPixel(); image.ProcessPixelRows(accessor => { for (int y = 0; y < image.Height; y++) @@ -407,7 +364,7 @@ public void Encode_WithPngTransparentColorBehaviorClear_Works(PngColorType color for (int x = 0; x < image.Width; x++) { - rowSpan[x].FromRgba32(rgba32); + rowSpan[x] = Rgba32.FromRgba32(rgba32); } } }); @@ -419,7 +376,7 @@ public void Encode_WithPngTransparentColorBehaviorClear_Works(PngColorType color // assert memStream.Position = 0; using Image actual = Image.Load(memStream); - Rgba32 expectedColor = Color.Blue; + Rgba32 expectedColor = Color.Blue.ToPixel(); if (colorType is PngColorType.Grayscale or PngColorType.GrayscaleWithAlpha) { byte luminance = ColorNumerics.Get8BitBT709Luminance(expectedColor.R, expectedColor.G, expectedColor.B); @@ -428,13 +385,14 @@ public void Encode_WithPngTransparentColorBehaviorClear_Works(PngColorType color actual.ProcessPixelRows(accessor => { + Rgba32 transparent = Color.Transparent.ToPixel(); for (int y = 0; y < accessor.Height; y++) { Span rowSpan = accessor.GetRowSpan(y); if (y > 25) { - expectedColor = Color.Transparent; + expectedColor = transparent; } for (int x = 0; x < accessor.Width; x++) @@ -478,8 +436,8 @@ public void Encode_APng(TestImageProvider provider) PngFrameMetadata outputFrameMetadata = output.Frames[i].Metadata.GetPngMetadata(); Assert.Equal(originalFrameMetadata.FrameDelay, outputFrameMetadata.FrameDelay); - Assert.Equal(originalFrameMetadata.BlendMethod, outputFrameMetadata.BlendMethod); - Assert.Equal(originalFrameMetadata.DisposalMethod, outputFrameMetadata.DisposalMethod); + Assert.Equal(originalFrameMetadata.BlendMode, outputFrameMetadata.BlendMode); + Assert.Equal(originalFrameMetadata.DisposalMode, outputFrameMetadata.DisposalMode); } } @@ -518,18 +476,18 @@ public void Encode_AnimatedFormatTransform_FromGif(TestImageProvider(TestImageProvider(TestImageProvider provider) where TPixel : unmanaged, IPixel { - // does saving a file then reopening mean both files are identical??? using Image image = provider.GetImage(); - using var ms = new MemoryStream(); + using MemoryStream ms = new(); - // image.Save(provider.Utility.GetTestOutputFileName("bmp")); image.Save(ms, new PngEncoder()); ms.Position = 0; using Image img2 = PngDecoder.Instance.Decode(DecoderOptions.Default, ms); - ImageComparer.Tolerant().VerifySimilarity(image, img2); - - // img2.Save(provider.Utility.GetTestOutputFileName("bmp", "_loaded"), new BmpEncoder()); + ImageComparer.Exact.VerifySimilarity(image, img2); } [Theory] @@ -37,12 +33,10 @@ public void Resize(TestImageProvider provider) { // does saving a file then reopening mean both files are identical??? using Image image = provider.GetImage(); - using var ms = new MemoryStream(); + using MemoryStream ms = new(); - // image.Save(provider.Utility.GetTestOutputFileName("png")); image.Mutate(x => x.Resize(100, 100)); - // image.Save(provider.Utility.GetTestOutputFileName("png", "resize")); image.Save(ms, new PngEncoder()); ms.Position = 0; using Image img2 = PngDecoder.Instance.Decode(DecoderOptions.Default, ms); diff --git a/tests/ImageSharp.Tests/Formats/Qoi/QoiEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Qoi/QoiEncoderTests.cs index d57b597b06..32ade4a1e9 100644 --- a/tests/ImageSharp.Tests/Formats/Qoi/QoiEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Qoi/QoiEncoderTests.cs @@ -24,7 +24,7 @@ public class QoiEncoderTests public static void Encode(TestImageProvider provider, QoiChannels channels, QoiColorSpace colorSpace) where TPixel : unmanaged, IPixel { - using Image image = provider.GetImage(new MagickReferenceDecoder()); + using Image image = provider.GetImage(new MagickReferenceDecoder(QoiFormat.Instance)); using MemoryStream stream = new(); QoiEncoder encoder = new() { @@ -34,7 +34,7 @@ public static void Encode(TestImageProvider provider, QoiChannel image.Save(stream, encoder); stream.Position = 0; - using Image encodedImage = (Image)Image.Load(stream); + using Image encodedImage = Image.Load(stream); QoiMetadata qoiMetadata = encodedImage.Metadata.GetQoiMetadata(); ImageComparer.Exact.CompareImages(image, encodedImage); diff --git a/tests/ImageSharp.Tests/Formats/Tga/TgaDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Tga/TgaDecoderTests.cs index da5de8e898..dbd7885e52 100644 --- a/tests/ImageSharp.Tests/Formats/Tga/TgaDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tga/TgaDecoderTests.cs @@ -1,7 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using System.Runtime.InteropServices; using System.Runtime.Intrinsics.X86; using Microsoft.DotNet.RemoteExecutor; using SixLabors.ImageSharp.Formats; @@ -724,10 +723,8 @@ public void TgaDecoder_CanDecode_WhenAlphaBitsNotSet(TestImageProvider image = provider.GetImage(TgaDecoder.Instance)) { - // Using here the reference output instead of the the reference decoder, - // because the reference decoder does not ignore the alpha data here. image.DebugSave(provider); - image.CompareToReferenceOutput(ImageComparer.Exact, provider); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); } } @@ -771,6 +768,19 @@ public void TgaDecoder_Decode_Resize(TestImageProvider provider) appendPixelTypeToFileName: false); } + // https://github.com/SixLabors/ImageSharp/issues/2629 + [Theory] + [WithFile(Issue2629, PixelTypes.Rgba32)] + public void TgaDecoder_CanDecode_Issue2629(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + using (Image image = provider.GetImage(TgaDecoder.Instance)) + { + image.DebugSave(provider); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); + } + } + [Theory] [WithFile(Bit16BottomLeft, PixelTypes.Rgba32)] [WithFile(Bit24BottomLeft, PixelTypes.Rgba32)] diff --git a/tests/ImageSharp.Tests/Formats/Tga/TgaEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Tga/TgaEncoderTests.cs index 709a3207aa..615e0fc921 100644 --- a/tests/ImageSharp.Tests/Formats/Tga/TgaEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tga/TgaEncoderTests.cs @@ -15,17 +15,17 @@ public class TgaEncoderTests public static readonly TheoryData BitsPerPixel = new() { - TgaBitsPerPixel.Pixel24, - TgaBitsPerPixel.Pixel32 + TgaBitsPerPixel.Bit24, + TgaBitsPerPixel.Bit32 }; public static readonly TheoryData TgaBitsPerPixelFiles = new() { - { Gray8BitBottomLeft, TgaBitsPerPixel.Pixel8 }, - { Bit16BottomLeft, TgaBitsPerPixel.Pixel16 }, - { Bit24BottomLeft, TgaBitsPerPixel.Pixel24 }, - { Bit32BottomLeft, TgaBitsPerPixel.Pixel32 }, + { Gray8BitBottomLeft, TgaBitsPerPixel.Bit8 }, + { Bit16BottomLeft, TgaBitsPerPixel.Bit16 }, + { Bit24BottomLeft, TgaBitsPerPixel.Bit24 }, + { Bit32BottomLeft, TgaBitsPerPixel.Bit32 }, }; [Theory] @@ -73,46 +73,46 @@ public void TgaEncoder_WithCompression_PreserveBitsPerPixel(string imagePath, Tg [Theory] [WithFile(Bit32BottomLeft, PixelTypes.Rgba32)] - public void TgaEncoder_Bit8_Works(TestImageProvider provider, TgaBitsPerPixel bitsPerPixel = TgaBitsPerPixel.Pixel8) + public void TgaEncoder_Bit8_Works(TestImageProvider provider, TgaBitsPerPixel bitsPerPixel = TgaBitsPerPixel.Bit8) // Using tolerant comparer here. The results from magick differ slightly. Maybe a different ToGrey method is used. The image looks otherwise ok. where TPixel : unmanaged, IPixel => TestTgaEncoderCore(provider, bitsPerPixel, TgaCompression.None, useExactComparer: false, compareTolerance: 0.03f); [Theory] [WithFile(Bit32BottomLeft, PixelTypes.Rgba32)] - public void TgaEncoder_Bit16_Works(TestImageProvider provider, TgaBitsPerPixel bitsPerPixel = TgaBitsPerPixel.Pixel16) + public void TgaEncoder_Bit16_Works(TestImageProvider provider, TgaBitsPerPixel bitsPerPixel = TgaBitsPerPixel.Bit16) where TPixel : unmanaged, IPixel => TestTgaEncoderCore(provider, bitsPerPixel, TgaCompression.None, useExactComparer: false); [Theory] [WithFile(Bit32BottomLeft, PixelTypes.Rgba32)] - public void TgaEncoder_Bit24_Works(TestImageProvider provider, TgaBitsPerPixel bitsPerPixel = TgaBitsPerPixel.Pixel24) + public void TgaEncoder_Bit24_Works(TestImageProvider provider, TgaBitsPerPixel bitsPerPixel = TgaBitsPerPixel.Bit24) where TPixel : unmanaged, IPixel => TestTgaEncoderCore(provider, bitsPerPixel, TgaCompression.None); [Theory] [WithFile(Bit32BottomLeft, PixelTypes.Rgba32)] - public void TgaEncoder_Bit32_Works(TestImageProvider provider, TgaBitsPerPixel bitsPerPixel = TgaBitsPerPixel.Pixel32) + public void TgaEncoder_Bit32_Works(TestImageProvider provider, TgaBitsPerPixel bitsPerPixel = TgaBitsPerPixel.Bit32) where TPixel : unmanaged, IPixel => TestTgaEncoderCore(provider, bitsPerPixel, TgaCompression.None); [Theory] [WithFile(Bit32BottomLeft, PixelTypes.Rgba32)] - public void TgaEncoder_Bit8_WithRunLengthEncoding_Works(TestImageProvider provider, TgaBitsPerPixel bitsPerPixel = TgaBitsPerPixel.Pixel8) + public void TgaEncoder_Bit8_WithRunLengthEncoding_Works(TestImageProvider provider, TgaBitsPerPixel bitsPerPixel = TgaBitsPerPixel.Bit8) // Using tolerant comparer here. The results from magick differ slightly. Maybe a different ToGrey method is used. The image looks otherwise ok. where TPixel : unmanaged, IPixel => TestTgaEncoderCore(provider, bitsPerPixel, TgaCompression.RunLength, useExactComparer: false, compareTolerance: 0.03f); [Theory] [WithFile(Bit32BottomLeft, PixelTypes.Rgba32)] - public void TgaEncoder_Bit16_WithRunLengthEncoding_Works(TestImageProvider provider, TgaBitsPerPixel bitsPerPixel = TgaBitsPerPixel.Pixel16) + public void TgaEncoder_Bit16_WithRunLengthEncoding_Works(TestImageProvider provider, TgaBitsPerPixel bitsPerPixel = TgaBitsPerPixel.Bit16) where TPixel : unmanaged, IPixel => TestTgaEncoderCore(provider, bitsPerPixel, TgaCompression.RunLength, useExactComparer: false); [Theory] [WithFile(Bit32BottomLeft, PixelTypes.Rgba32)] - public void TgaEncoder_Bit24_WithRunLengthEncoding_Works(TestImageProvider provider, TgaBitsPerPixel bitsPerPixel = TgaBitsPerPixel.Pixel24) + public void TgaEncoder_Bit24_WithRunLengthEncoding_Works(TestImageProvider provider, TgaBitsPerPixel bitsPerPixel = TgaBitsPerPixel.Bit24) where TPixel : unmanaged, IPixel => TestTgaEncoderCore(provider, bitsPerPixel, TgaCompression.RunLength); [Theory] [WithFile(Bit32BottomLeft, PixelTypes.Rgba32)] - public void TgaEncoder_Bit32_WithRunLengthEncoding_Works(TestImageProvider provider, TgaBitsPerPixel bitsPerPixel = TgaBitsPerPixel.Pixel32) + public void TgaEncoder_Bit32_WithRunLengthEncoding_Works(TestImageProvider provider, TgaBitsPerPixel bitsPerPixel = TgaBitsPerPixel.Bit32) where TPixel : unmanaged, IPixel => TestTgaEncoderCore(provider, bitsPerPixel, TgaCompression.RunLength); [Theory] @@ -121,16 +121,14 @@ public void TgaEncoder_DoesNotAlwaysUseRunLengthPackets(TestImageProvide where TPixel : unmanaged, IPixel { // The test image has alternating black and white pixels, which should make using always RLE data inefficient. - using (Image image = provider.GetImage()) - { - var options = new TgaEncoder() { Compression = TgaCompression.RunLength }; - using (var memStream = new MemoryStream()) - { - image.Save(memStream, options); - byte[] imageBytes = memStream.ToArray(); - Assert.Equal(expectedBytes, imageBytes.Length); - } - } + using Image image = provider.GetImage(); + TgaEncoder options = new() { BitsPerPixel = TgaBitsPerPixel.Bit24, Compression = TgaCompression.RunLength }; + + using MemoryStream memStream = new(); + image.Save(memStream, options); + byte[] imageBytes = memStream.ToArray(); + + Assert.Equal(expectedBytes, imageBytes.Length); } // Run length encoded pixels should not exceed row boundaries. @@ -152,8 +150,8 @@ public void TgaEncoder_RunLengthDoesNotCrossRowBoundaries() } [Theory] - [WithFile(Bit32BottomLeft, PixelTypes.Rgba32, TgaBitsPerPixel.Pixel32)] - [WithFile(Bit24BottomLeft, PixelTypes.Rgba32, TgaBitsPerPixel.Pixel24)] + [WithFile(Bit32BottomLeft, PixelTypes.Rgba32, TgaBitsPerPixel.Bit32)] + [WithFile(Bit24BottomLeft, PixelTypes.Rgba32, TgaBitsPerPixel.Bit24)] public void TgaEncoder_WorksWithDiscontiguousBuffers(TestImageProvider provider, TgaBitsPerPixel bitsPerPixel) where TPixel : unmanaged, IPixel { @@ -175,6 +173,7 @@ private static void TestTgaEncoderCore( using (var memStream = new MemoryStream()) { + image.DebugSave(provider, encoder); image.Save(memStream, encoder); memStream.Position = 0; using (var encodedImage = (Image)Image.Load(memStream)) diff --git a/tests/ImageSharp.Tests/Formats/Tga/TgaFileHeaderTests.cs b/tests/ImageSharp.Tests/Formats/Tga/TgaFileHeaderTests.cs index bf24ba3500..efbdb8eebb 100644 --- a/tests/ImageSharp.Tests/Formats/Tga/TgaFileHeaderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tga/TgaFileHeaderTests.cs @@ -9,6 +9,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga; [Trait("Format", "Tga")] public class TgaFileHeaderTests { + // TODO: Some of these clash with the ICO magic bytes. Check correctness. + // https://en.wikipedia.org/wiki/Truevision_TGA#Header [Theory] [InlineData(new byte[] { 0, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 250, 0, 195, 0, 32, 8 })] // invalid tga image type. [InlineData(new byte[] { 0, 3, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 250, 0, 195, 0, 32, 8 })] // invalid colormap type. @@ -33,10 +35,10 @@ public void ImageLoad_WithNoValidTgaHeaderBytes_Throws_UnknownImageFormatExcepti } [Theory] - [InlineData(new byte[] { 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 250, 0, 195, 0, 32, 8 }, 250, 195, TgaBitsPerPixel.Pixel32)] - [InlineData(new byte[] { 26, 1, 9, 0, 0, 0, 1, 16, 0, 0, 0, 0, 128, 0, 128, 0, 8, 0 }, 128, 128, TgaBitsPerPixel.Pixel8)] - [InlineData(new byte[] { 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 220, 0, 220, 0, 16, 0 }, 220, 220, TgaBitsPerPixel.Pixel16)] - [InlineData(new byte[] { 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 124, 0, 124, 0, 24, 32 }, 124, 124, TgaBitsPerPixel.Pixel24)] + [InlineData(new byte[] { 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 250, 0, 195, 0, 32, 8 }, 250, 195, TgaBitsPerPixel.Bit32)] + [InlineData(new byte[] { 26, 1, 9, 0, 0, 0, 1, 16, 0, 0, 0, 0, 128, 0, 128, 0, 8, 0 }, 128, 128, TgaBitsPerPixel.Bit8)] + [InlineData(new byte[] { 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 220, 0, 220, 0, 16, 0 }, 220, 220, TgaBitsPerPixel.Bit16)] + [InlineData(new byte[] { 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 124, 0, 124, 0, 24, 32 }, 124, 124, TgaBitsPerPixel.Bit24)] public void Identify_WithValidData_Works(byte[] data, int width, int height, TgaBitsPerPixel bitsPerPixel) { using MemoryStream stream = new(data); diff --git a/tests/ImageSharp.Tests/Formats/Tiff/BigTiffDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/BigTiffDecoderTests.cs index 8e90b1dd57..72f53cab78 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/BigTiffDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tiff/BigTiffDecoderTests.cs @@ -65,7 +65,7 @@ public void Identify(string imagePath, int expectedPixelSize, int expectedWidth, using MemoryStream stream = new(testFile.Bytes, false); ImageInfo info = Image.Identify(stream); - Assert.Equal(expectedPixelSize, info.PixelType?.BitsPerPixel); + Assert.Equal(expectedPixelSize, info.PixelType.BitsPerPixel); Assert.Equal(expectedWidth, info.Width); Assert.Equal(expectedHeight, info.Height); Assert.NotNull(info.Metadata); diff --git a/tests/ImageSharp.Tests/Formats/Tiff/PhotometricInterpretation/PhotometricInterpretationTestBase.cs b/tests/ImageSharp.Tests/Formats/Tiff/PhotometricInterpretation/PhotometricInterpretationTestBase.cs index b174403839..3582dc75a6 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/PhotometricInterpretation/PhotometricInterpretationTestBase.cs +++ b/tests/ImageSharp.Tests/Formats/Tiff/PhotometricInterpretation/PhotometricInterpretationTestBase.cs @@ -47,7 +47,7 @@ internal static void AssertDecode(Rgba32[][] expectedResult, Action(resultWidth, resultHeight)) { - image.Mutate(x => x.BackgroundColor(DefaultColor)); + image.Mutate(x => x.BackgroundColor(Color.FromPixel(DefaultColor))); Buffer2D pixels = image.GetRootFramePixelBuffer(); decodeAction(pixels); diff --git a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderBaseTester.cs b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderBaseTester.cs index 4acdf3e509..b574c7e55c 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderBaseTester.cs +++ b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderBaseTester.cs @@ -12,7 +12,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff; public abstract class TiffDecoderBaseTester { - protected static MagickReferenceDecoder ReferenceDecoder => new(); + protected static MagickReferenceDecoder ReferenceDecoder => new(TiffFormat.Instance); protected static void TestTiffDecoder(TestImageProvider provider, IImageDecoder referenceDecoder = null, bool useExactComparer = true, float compareTolerance = 0.001f) where TPixel : unmanaged, IPixel diff --git a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs index ab49805a35..97f02f3684 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs @@ -671,6 +671,23 @@ public void TiffDecoder_CanDecode_TiledWithNonEqualWidthAndHeight(TestIm public void TiffDecoder_CanDecode_BiColorWithMissingBitsPerSample(TestImageProvider provider) where TPixel : unmanaged, IPixel => TestTiffDecoder(provider); + // https://github.com/SixLabors/ImageSharp/issues/2679 + [Theory] + [WithFile(Issues2679, PixelTypes.Rgba32)] + public void TiffDecoder_CanDecode_JpegCompressedWithIssue2679(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + using Image image = provider.GetImage(TiffDecoder.Instance); + + // The image is handcrafted to simulate issue 2679. ImageMagick will throw an expection here and wont decode, + // so we compare to rererence output instead. + image.DebugSave(provider); + image.CompareToReferenceOutput( + ImageComparer.Exact, + provider, + appendPixelTypeToFileName: false); + } + [Theory] [WithFile(JpegCompressedGray0000539558, PixelTypes.Rgba32)] public void TiffDecoder_ThrowsException_WithCircular_IFD_Offsets(TestImageProvider provider) diff --git a/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderBaseTester.cs b/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderBaseTester.cs index 2a822e7054..1bf9f5a400 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderBaseTester.cs +++ b/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderBaseTester.cs @@ -15,7 +15,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff; [Trait("Format", "Tiff")] public abstract class TiffEncoderBaseTester { - protected static readonly IImageDecoder ReferenceDecoder = new MagickReferenceDecoder(); + protected static readonly IImageDecoder ReferenceDecoder = new MagickReferenceDecoder(TiffFormat.Instance); protected static void TestStripLength( TestImageProvider provider, @@ -30,7 +30,7 @@ protected static void TestStripLength( using Image input = provider.GetImage(); using var memStream = new MemoryStream(); TiffFrameMetadata inputMeta = input.Frames.RootFrame.Metadata.GetTiffMetadata(); - TiffCompression inputCompression = inputMeta.Compression ?? TiffCompression.None; + TiffCompression inputCompression = inputMeta.Compression; // act input.Save(memStream, tiffEncoder); @@ -48,7 +48,6 @@ protected static void TestStripLength( Number[] stripByteCounts = exifProfileOutput.GetValue(ExifTag.StripByteCounts)?.Value; Assert.NotNull(stripByteCounts); Assert.True(stripByteCounts.Length > 1); - Assert.NotNull(outputMeta.BitsPerPixel); foreach (Number sz in stripByteCounts) { diff --git a/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderHeaderTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderHeaderTests.cs index 8724147301..282966ea85 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderHeaderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderHeaderTests.cs @@ -15,7 +15,7 @@ public class TiffEncoderHeaderTests public void WriteHeader_WritesValidHeader() { using MemoryStream stream = new(); - TiffEncoderCore encoder = new(Encoder, Configuration.Default.MemoryAllocator); + TiffEncoderCore encoder = new(Encoder, Configuration.Default); using (TiffStreamWriter writer = new(stream)) { @@ -29,7 +29,7 @@ public void WriteHeader_WritesValidHeader() public void WriteHeader_ReturnsFirstIfdMarker() { using MemoryStream stream = new(); - TiffEncoderCore encoder = new(Encoder, Configuration.Default.MemoryAllocator); + TiffEncoderCore encoder = new(Encoder, Configuration.Default); using TiffStreamWriter writer = new(stream); long firstIfdMarker = TiffEncoderCore.WriteHeader(writer, stackalloc byte[4]); diff --git a/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderMultiframeTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderMultiframeTests.cs index b74093fcc1..dce6ebc38f 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderMultiframeTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderMultiframeTests.cs @@ -70,9 +70,9 @@ public void TiffEncoder_EncodeMultiframe_AddFrames(TestImageProvider image = provider.GetImage(); Assert.Equal(1, image.Frames.Count); - using var image1 = new Image(image.Width, image.Height, Color.Green.ToRgba32()); + using var image1 = new Image(image.Width, image.Height, Color.Green.ToPixel()); - using var image2 = new Image(image.Width, image.Height, Color.Yellow.ToRgba32()); + using var image2 = new Image(image.Width, image.Height, Color.Yellow.ToPixel()); image.Frames.AddFrame(image1.Frames.RootFrame); image.Frames.AddFrame(image2.Frames.RootFrame); @@ -97,8 +97,8 @@ public void TiffEncoder_EncodeMultiframe_AddFrames(TestImageProvider 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(Color.Green.ToPixel(), frame1[10, 10]); + Assert.Equal(Color.Yellow.ToPixel(), frame2[10, 10]); Assert.Equal(TiffCompression.Deflate, frame1.Metadata.GetTiffMetadata().Compression); Assert.Equal(TiffCompression.Deflate, frame1.Metadata.GetTiffMetadata().Compression); @@ -122,11 +122,11 @@ public void TiffEncoder_EncodeMultiframe_Create(TestImageProvider image = provider.GetImage(); - using var image0 = new Image(image.Width, image.Height, Color.Red.ToRgba32()); + using var image0 = new Image(image.Width, image.Height, Color.Red.ToPixel()); - using var image1 = new Image(image.Width, image.Height, Color.Green.ToRgba32()); + using var image1 = new Image(image.Width, image.Height, Color.Green.ToPixel()); - using var image2 = new Image(image.Width, image.Height, Color.Yellow.ToRgba32()); + using var image2 = new Image(image.Width, image.Height, Color.Yellow.ToPixel()); image.Frames.AddFrame(image0.Frames.RootFrame); image.Frames.AddFrame(image1.Frames.RootFrame); @@ -154,9 +154,9 @@ public void TiffEncoder_EncodeMultiframe_Create(TestImageProvider 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(Color.Red.ToPixel(), frame0[10, 10]); + Assert.Equal(Color.Green.ToPixel(), frame1[10, 10]); + Assert.Equal(Color.Yellow.ToPixel(), frame2[10, 10]); Assert.Equal(TiffCompression.Lzw, frame0.Metadata.GetTiffMetadata().Compression); Assert.Equal(TiffCompression.Lzw, frame1.Metadata.GetTiffMetadata().Compression); diff --git a/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderTests.cs index 1fafb4cd04..1972101164 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderTests.cs @@ -31,7 +31,7 @@ public class TiffEncoderTests : TiffEncoderBaseTester public void EncoderOptions_SetPhotometricInterpretation_Works(TiffPhotometricInterpretation? photometricInterpretation, TiffBitsPerPixel expectedBitsPerPixel) { // arrange - TiffEncoder tiffEncoder = new() { PhotometricInterpretation = photometricInterpretation }; + TiffEncoder tiffEncoder = new() { BitsPerPixel = expectedBitsPerPixel, PhotometricInterpretation = photometricInterpretation }; using Image input = expectedBitsPerPixel is TiffBitsPerPixel.Bit16 ? new Image(10, 10) : new Image(10, 10); @@ -57,8 +57,7 @@ public void EncoderOptions_SetPhotometricInterpretation_Works(TiffPhotometricInt public void EncoderOptions_SetBitPerPixel_Works(TiffBitsPerPixel bitsPerPixel) { // arrange - TiffEncoder tiffEncoder = new() - { BitsPerPixel = bitsPerPixel }; + TiffEncoder tiffEncoder = new() { BitsPerPixel = bitsPerPixel }; using Image input = new Image(10, 10); using MemoryStream memStream = new(); @@ -156,7 +155,11 @@ public void EncoderOptions_SetPhotometricInterpretationAndCompression_Works( { // arrange TiffEncoder tiffEncoder = new() - { PhotometricInterpretation = photometricInterpretation, Compression = compression }; + { + BitsPerPixel = expectedBitsPerPixel, + PhotometricInterpretation = photometricInterpretation, + Compression = compression + }; using Image input = expectedBitsPerPixel is TiffBitsPerPixel.Bit16 ? new Image(10, 10) : new Image(10, 10); @@ -199,25 +202,6 @@ public void TiffEncoder_PreservesBitsPerPixel(TestImageProvider Assert.Equal(expectedBitsPerPixel, frameMetaData.BitsPerPixel); } - [Fact] - public void TiffEncoder_PreservesBitsPerPixel_WhenInputIsL8() - { - // arrange - TiffEncoder tiffEncoder = new(); - using Image input = new Image(10, 10); - using MemoryStream memStream = new(); - const TiffBitsPerPixel expectedBitsPerPixel = TiffBitsPerPixel.Bit8; - - // act - input.Save(memStream, tiffEncoder); - - // assert - memStream.Position = 0; - using Image output = Image.Load(memStream); - TiffFrameMetadata frameMetaData = output.Frames.RootFrame.Metadata.GetTiffMetadata(); - Assert.Equal(expectedBitsPerPixel, frameMetaData.BitsPerPixel); - } - [Theory] [WithFile(RgbUncompressed, PixelTypes.Rgba32, TiffCompression.None)] [WithFile(RgbLzwNoPredictor, PixelTypes.Rgba32, TiffCompression.Lzw)] @@ -241,11 +225,11 @@ public void TiffEncoder_PreservesCompression(TestImageProvider p } [Theory] - [WithFile(RgbLzwNoPredictor, PixelTypes.Rgba32, null)] + [WithFile(RgbLzwNoPredictor, PixelTypes.Rgba32, TiffPredictor.None)] [WithFile(RgbLzwPredictor, PixelTypes.Rgba32, TiffPredictor.Horizontal)] - [WithFile(RgbDeflate, PixelTypes.Rgba32, null)] + [WithFile(RgbDeflate, PixelTypes.Rgba32, TiffPredictor.None)] [WithFile(RgbDeflatePredictor, PixelTypes.Rgba32, TiffPredictor.Horizontal)] - public void TiffEncoder_PreservesPredictor(TestImageProvider provider, TiffPredictor? expectedPredictor) + public void TiffEncoder_PreservesPredictor(TestImageProvider provider, TiffPredictor expectedPredictor) where TPixel : unmanaged, IPixel { // arrange diff --git a/tests/ImageSharp.Tests/Formats/WebP/PredictorEncoderTests.cs b/tests/ImageSharp.Tests/Formats/WebP/PredictorEncoderTests.cs index f0961de6bb..b4279b0454 100644 --- a/tests/ImageSharp.Tests/Formats/WebP/PredictorEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/WebP/PredictorEncoderTests.cs @@ -80,7 +80,7 @@ private static void RunColorSpaceTransformTestWithPeakImage() // Convert image pixels to bgra array. byte[] imgBytes = File.ReadAllBytes(TestImageFullPath(TestImages.Webp.Peak)); - using var image = Image.Load(imgBytes); + using Image image = Image.Load(imgBytes); uint[] bgra = ToBgra(image); const int colorTransformBits = 3; @@ -110,7 +110,7 @@ private static void RunColorSpaceTransformTestWithBikeImage() // Convert image pixels to bgra array. byte[] imgBytes = File.ReadAllBytes(TestImageFullPath(TestImages.Webp.Lossy.BikeSmall)); - using var image = Image.Load(imgBytes); + using Image image = Image.Load(imgBytes); uint[] bgra = ToBgra(image); const int colorTransformBits = 4; @@ -149,10 +149,8 @@ private static uint[] ToBgra(Image image) 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; + Rgba32 rgba = color.ToRgba32(); + return new Bgra32(rgba.R, rgba.G, rgba.B, rgba.A); } private static string TestImageFullPath(string path) diff --git a/tests/ImageSharp.Tests/Formats/WebP/WebpDecoderTests.cs b/tests/ImageSharp.Tests/Formats/WebP/WebpDecoderTests.cs index 0dda304b64..657ab25546 100644 --- a/tests/ImageSharp.Tests/Formats/WebP/WebpDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/WebP/WebpDecoderTests.cs @@ -18,7 +18,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Webp; [ValidateDisposedMemoryAllocations] public class WebpDecoderTests { - private static MagickReferenceDecoder ReferenceDecoder => new(); + private static MagickReferenceDecoder ReferenceDecoder => MagickReferenceDecoder.WebP; private static string TestImageLossyHorizontalFilterPath => Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, Lossy.AlphaCompressedHorizontalFilter); @@ -30,8 +30,8 @@ public class WebpDecoderTests [Theory] [InlineData(Lossless.GreenTransform1, 1000, 307, 32)] - [InlineData(Lossless.BikeThreeTransforms, 250, 195, 32)] - [InlineData(Lossless.NoTransform2, 128, 128, 32)] + [InlineData(Lossless.BikeThreeTransforms, 250, 195, 24)] + [InlineData(Lossless.NoTransform2, 128, 128, 24)] [InlineData(Lossy.Alpha1, 1000, 307, 32)] [InlineData(Lossy.Alpha2, 1000, 307, 32)] [InlineData(Lossy.BikeWithExif, 250, 195, 24)] diff --git a/tests/ImageSharp.Tests/Formats/WebP/WebpEncoderTests.cs b/tests/ImageSharp.Tests/Formats/WebP/WebpEncoderTests.cs index d1d83ffb9a..10492af8a7 100644 --- a/tests/ImageSharp.Tests/Formats/WebP/WebpEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/WebP/WebpEncoderTests.cs @@ -2,6 +2,7 @@ // Licensed under the Six Labors Split License. using System.Runtime.InteropServices; +using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.Formats.Gif; using SixLabors.ImageSharp.Formats.Png; using SixLabors.ImageSharp.Formats.Webp; @@ -94,16 +95,16 @@ public void Encode_AnimatedFormatTransform_FromGif(TestImageProvider(TestImageProvider(TestImageProvider provider, WebpFileFormatType expectedFormat) + public void Encode_PreserveEncodingType(TestImageProvider provider, WebpFileFormatType expectedFormat) where TPixel : unmanaged, IPixel { WebpEncoder options = new(); @@ -219,7 +221,7 @@ public void Encode_Lossless_WithDifferentQuality_Works(TestImageProvider }; using Image image = provider.GetImage(); - string testOutputDetails = string.Concat("lossless", "_q", quality); + string testOutputDetails = $"lossless_q{quality}"; image.VerifyEncoder(provider, "webp", testOutputDetails, encoder); } @@ -249,7 +251,7 @@ public void Encode_Lossless_WithDifferentMethodAndQuality_Works(TestImag }; using Image image = provider.GetImage(); - string testOutputDetails = string.Concat("lossless", "_m", method, "_q", quality); + string testOutputDetails = $"lossless_m{method}_q{quality}"; image.VerifyEncoder(provider, "webp", testOutputDetails, encoder); } @@ -289,7 +291,7 @@ public void Encode_Lossless_WithNearLosslessFlag_Works(TestImageProvider }; using Image image = provider.GetImage(); - string testOutputDetails = string.Concat("nearlossless", "_q", nearLosslessQuality); + string testOutputDetails = $"nearlossless_q{nearLosslessQuality}"; image.VerifyEncoder(provider, "webp", testOutputDetails, encoder, customComparer: GetComparer(nearLosslessQuality)); } @@ -313,7 +315,7 @@ public void Encode_Lossless_WithPreserveTransparentColor_Works(TestImage }; using Image image = provider.GetImage(); - string testOutputDetails = string.Concat("lossless", "_m", method); + string testOutputDetails = $"lossless_m{method}"; image.VerifyEncoder(provider, "webp", testOutputDetails, encoder); } @@ -343,7 +345,7 @@ public void Encode_Lossy_WithDifferentQuality_Works(TestImageProvider image = provider.GetImage(); - string testOutputDetails = string.Concat("lossy", "_q", quality); + string testOutputDetails = $"lossy_q{quality}"; image.VerifyEncoder(provider, "webp", testOutputDetails, encoder, customComparer: GetComparer(quality)); } @@ -363,7 +365,7 @@ public void Encode_Lossy_WithDifferentFilterStrength_Works(TestImageProv }; using Image image = provider.GetImage(); - string testOutputDetails = string.Concat("lossy", "_f", filterStrength); + string testOutputDetails = $"lossy_f{filterStrength}"; image.VerifyEncoder(provider, "webp", testOutputDetails, encoder, customComparer: GetComparer(75)); } @@ -383,7 +385,7 @@ public void Encode_Lossy_WithDifferentSpatialNoiseShapingStrength_Works( }; using Image image = provider.GetImage(); - string testOutputDetails = string.Concat("lossy", "_sns", snsStrength); + string testOutputDetails = $"lossy_sns{snsStrength}"; image.VerifyEncoder(provider, "webp", testOutputDetails, encoder, customComparer: GetComparer(75)); } @@ -413,7 +415,7 @@ public void Encode_Lossy_WithDifferentMethodsAndQuality_Works(TestImageP }; using Image image = provider.GetImage(); - string testOutputDetails = string.Concat("lossy", "_m", method, "_q", quality); + string testOutputDetails = $"lossy_m{method}_q{quality}"; image.VerifyEncoder(provider, "webp", testOutputDetails, encoder, customComparer: GetComparer(quality)); } @@ -439,7 +441,7 @@ public void Encode_Lossy_WithAlpha_Works(TestImageProvider provi "with_alpha", encoder, ImageComparer.Tolerant(0.04f), - referenceDecoder: new MagickReferenceDecoder()); + referenceDecoder: MagickReferenceDecoder.WebP); int encodedBytes = File.ReadAllBytes(encodedFile).Length; Assert.True(encodedBytes <= expectedFileSize, $"encoded bytes are {encodedBytes} and should be smaller then expected file size of {expectedFileSize}"); @@ -467,7 +469,7 @@ public void Encode_Lossy_WithAlphaUsingCompression_Works(TestImageProvid "with_alpha_compressed", encoder, ImageComparer.Tolerant(0.04f), - referenceDecoder: new MagickReferenceDecoder()); + referenceDecoder: MagickReferenceDecoder.WebP); int encodedBytes = File.ReadAllBytes(encodedFile).Length; Assert.True(encodedBytes <= expectedFileSize, $"encoded bytes are {encodedBytes} and should be smaller then expected file size of {expectedFileSize}"); diff --git a/tests/ImageSharp.Tests/Formats/WebP/YuvConversionTests.cs b/tests/ImageSharp.Tests/Formats/WebP/YuvConversionTests.cs index 3ae6601b18..f50bc89335 100644 --- a/tests/ImageSharp.Tests/Formats/WebP/YuvConversionTests.cs +++ b/tests/ImageSharp.Tests/Formats/WebP/YuvConversionTests.cs @@ -13,7 +13,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Webp; [Trait("Format", "Webp")] public class YuvConversionTests { - private static MagickReferenceDecoder ReferenceDecoder => new(); + private static MagickReferenceDecoder ReferenceDecoder => MagickReferenceDecoder.WebP; private static string TestImageLossyFullPath => Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, TestImages.Webp.Lossy.NoFilter06); diff --git a/tests/ImageSharp.Tests/Image/ImageFrameCollectionTests.Generic.cs b/tests/ImageSharp.Tests/Image/ImageFrameCollectionTests.Generic.cs index 62d1ef4db9..71c9e07fc3 100644 --- a/tests/ImageSharp.Tests/Image/ImageFrameCollectionTests.Generic.cs +++ b/tests/ImageSharp.Tests/Image/ImageFrameCollectionTests.Generic.cs @@ -237,7 +237,7 @@ public void CreateFrame_CustomFillColor() using (this.Image.Frames.CreateFrame(Color.HotPink)) { Assert.Equal(2, this.Image.Frames.Count); - this.Image.Frames[1].ComparePixelBufferTo(Color.HotPink); + this.Image.Frames[1].ComparePixelBufferTo(Color.HotPink.ToPixel()); } } diff --git a/tests/ImageSharp.Tests/Image/ImageFrameCollectionTests.NonGeneric.cs b/tests/ImageSharp.Tests/Image/ImageFrameCollectionTests.NonGeneric.cs index f9ff6ba69e..f70623f515 100644 --- a/tests/ImageSharp.Tests/Image/ImageFrameCollectionTests.NonGeneric.cs +++ b/tests/ImageSharp.Tests/Image/ImageFrameCollectionTests.NonGeneric.cs @@ -1,7 +1,7 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.Advanced; +using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.Formats.Gif; using SixLabors.ImageSharp.PixelFormats; @@ -23,13 +23,13 @@ public void AddFrame_OfDifferentPixelType() this.Image.Configuration, this.Image.Width, this.Image.Height, - Color.Blue)) + Color.Blue.ToPixel())) { this.Collection.AddFrame(sourceImage.Frames.RootFrame); } Rgba32[] expectedAllBlue = - Enumerable.Repeat((Rgba32)Color.Blue, this.Image.Width * this.Image.Height).ToArray(); + Enumerable.Repeat(Color.Blue.ToPixel(), this.Image.Width * this.Image.Height).ToArray(); Assert.Equal(2, this.Collection.Count); ImageFrame actualFrame = (ImageFrame)this.Collection[1]; @@ -44,13 +44,13 @@ public void InsertFrame_OfDifferentPixelType() this.Image.Configuration, this.Image.Width, this.Image.Height, - Color.Blue)) + Color.Blue.ToPixel())) { this.Collection.InsertFrame(0, sourceImage.Frames.RootFrame); } Rgba32[] expectedAllBlue = - Enumerable.Repeat((Rgba32)Color.Blue, this.Image.Width * this.Image.Height).ToArray(); + Enumerable.Repeat(Color.Blue.ToPixel(), this.Image.Width * this.Image.Height).ToArray(); Assert.Equal(2, this.Collection.Count); ImageFrame actualFrame = (ImageFrame)this.Collection[0]; @@ -177,7 +177,7 @@ public void CreateFrame_CustomFillColor() ImageFrame frame = (ImageFrame)this.Image.Frames[1]; - frame.ComparePixelBufferTo(Color.HotPink); + frame.ComparePixelBufferTo(Color.HotPink.ToPixel()); } [Fact] @@ -279,7 +279,7 @@ public void ConstructGif_FromDifferentPixelTypes(TestImageProvider dest = new(source.Configuration, source.Width, source.Height); - + // Giphy.gif has 5 frames ImportFrameAs(source.Frames, dest.Frames, 0); ImportFrameAs(source.Frames, dest.Frames, 1); @@ -313,10 +313,10 @@ private static void CompareGifMetadata(ImageFrame a, ImageFrame b) GifFrameMetadata aData = a.Metadata.GetGifMetadata(); GifFrameMetadata bData = b.Metadata.GetGifMetadata(); - Assert.Equal(aData.DisposalMethod, bData.DisposalMethod); + Assert.Equal(aData.DisposalMode, bData.DisposalMode); Assert.Equal(aData.FrameDelay, bData.FrameDelay); - if (aData.ColorTableMode == GifColorTableMode.Local && bData.ColorTableMode == GifColorTableMode.Local) + if (aData.ColorTableMode == FrameColorTableMode.Local && bData.ColorTableMode == FrameColorTableMode.Local) { Assert.Equal(aData.LocalColorTable.Value.Length, bData.LocalColorTable.Value.Length); } diff --git a/tests/ImageSharp.Tests/Image/ImageFrameTests.cs b/tests/ImageSharp.Tests/Image/ImageFrameTests.cs index 3b9779ea42..e09ef487a8 100644 --- a/tests/ImageSharp.Tests/Image/ImageFrameTests.cs +++ b/tests/ImageSharp.Tests/Image/ImageFrameTests.cs @@ -35,9 +35,9 @@ public void GetSet(bool enforceDisco) ImageFrame frame = image.Frames.RootFrame; Rgba32 val = frame[3, 4]; Assert.Equal(default(Rgba32), val); - frame[3, 4] = Color.Red; + frame[3, 4] = Color.Red.ToPixel(); val = frame[3, 4]; - Assert.Equal(Color.Red.ToRgba32(), val); + Assert.Equal(Color.Red.ToPixel(), val); } public static TheoryData OutOfRangeData = new TheoryData() diff --git a/tests/ImageSharp.Tests/Image/ImageTests.ImageLoadTestBase.cs b/tests/ImageSharp.Tests/Image/ImageTests.ImageLoadTestBase.cs index 996310d8c3..51e2a01a28 100644 --- a/tests/ImageSharp.Tests/Image/ImageTests.ImageLoadTestBase.cs +++ b/tests/ImageSharp.Tests/Image/ImageTests.ImageLoadTestBase.cs @@ -4,6 +4,7 @@ using Moq; using SixLabors.ImageSharp.Formats; +using SixLabors.ImageSharp.Formats.Png; using SixLabors.ImageSharp.IO; using SixLabors.ImageSharp.Metadata; using SixLabors.ImageSharp.PixelFormats; @@ -57,7 +58,7 @@ protected ImageLoadTestBase() // TODO: Remove all this mocking. It's too complicated and we can now use fakes. this.localStreamReturnImageRgba32 = new Image(1, 1); this.localStreamReturnImageAgnostic = new Image(1, 1); - this.LocalImageInfo = new(new PixelTypeInfo(8), new(1, 1), new ImageMetadata()); + this.LocalImageInfo = new(new(1, 1), new ImageMetadata() { DecodedImageFormat = PngFormat.Instance }); this.localImageFormatMock = new Mock(); diff --git a/tests/ImageSharp.Tests/Image/ImageTests.LoadPixelData.cs b/tests/ImageSharp.Tests/Image/ImageTests.LoadPixelData.cs index 238096be49..5762264d21 100644 --- a/tests/ImageSharp.Tests/Image/ImageTests.LoadPixelData.cs +++ b/tests/ImageSharp.Tests/Image/ImageTests.LoadPixelData.cs @@ -15,19 +15,17 @@ public class LoadPixelData [ValidateDisposedMemoryAllocations] public void FromPixels(bool useSpan) { - Rgba32[] data = { Color.Black, Color.White, Color.White, Color.Black, }; + Rgba32[] data = { Color.Black.ToPixel(), Color.White.ToPixel(), Color.White.ToPixel(), Color.Black.ToPixel(), }; - using (Image img = useSpan - ? Image.LoadPixelData(data.AsSpan(), 2, 2) - : Image.LoadPixelData(data, 2, 2)) - { - Assert.NotNull(img); - Assert.Equal(Color.Black, (Color)img[0, 0]); - Assert.Equal(Color.White, (Color)img[0, 1]); + using Image img = useSpan + ? Image.LoadPixelData(data.AsSpan(), 2, 2) + : Image.LoadPixelData(data, 2, 2); + Assert.NotNull(img); + Assert.Equal(Color.Black, Color.FromPixel(img[0, 0])); + Assert.Equal(Color.White, Color.FromPixel(img[0, 1])); - Assert.Equal(Color.White, (Color)img[1, 0]); - Assert.Equal(Color.Black, (Color)img[1, 1]); - } + Assert.Equal(Color.White, Color.FromPixel(img[1, 0])); + Assert.Equal(Color.Black, Color.FromPixel(img[1, 1])); } [Theory] @@ -36,23 +34,22 @@ public void FromPixels(bool useSpan) public void FromBytes(bool useSpan) { byte[] data = - { - 0, 0, 0, 255, // 0,0 - 255, 255, 255, 255, // 0,1 - 255, 255, 255, 255, // 1,0 - 0, 0, 0, 255, // 1,1 - }; - using (Image img = useSpan - ? Image.LoadPixelData(data.AsSpan(), 2, 2) - : Image.LoadPixelData(data, 2, 2)) { - Assert.NotNull(img); - Assert.Equal(Color.Black, (Color)img[0, 0]); - Assert.Equal(Color.White, (Color)img[0, 1]); + 0, 0, 0, 255, // 0,0 + 255, 255, 255, 255, // 0,1 + 255, 255, 255, 255, // 1,0 + 0, 0, 0, 255, // 1,1 + }; + + using Image img = useSpan + ? Image.LoadPixelData(data.AsSpan(), 2, 2) + : Image.LoadPixelData(data, 2, 2); + Assert.NotNull(img); + Assert.Equal(Color.Black, Color.FromPixel(img[0, 0])); + Assert.Equal(Color.White, Color.FromPixel(img[0, 1])); - Assert.Equal(Color.White, (Color)img[1, 0]); - Assert.Equal(Color.Black, (Color)img[1, 1]); - } + Assert.Equal(Color.White, Color.FromPixel(img[1, 0])); + Assert.Equal(Color.Black, Color.FromPixel(img[1, 1])); } } } diff --git a/tests/ImageSharp.Tests/Image/ImageTests.WrapMemory.cs b/tests/ImageSharp.Tests/Image/ImageTests.WrapMemory.cs index 9aaefa41ef..e3c4a7df18 100644 --- a/tests/ImageSharp.Tests/Image/ImageTests.WrapMemory.cs +++ b/tests/ImageSharp.Tests/Image/ImageTests.WrapMemory.cs @@ -154,8 +154,8 @@ public void WrapSystemDrawingBitmap_WhenObserved() using (var memoryManager = new BitmapMemoryManager(bmp)) { Memory memory = memoryManager.Memory; - Bgra32 bg = Color.Red; - Bgra32 fg = Color.Green; + Bgra32 bg = Color.Red.ToPixel(); + Bgra32 fg = Color.Green.ToPixel(); using (var image = Image.WrapMemory(memory, bmp.Width, bmp.Height)) { @@ -198,8 +198,8 @@ public void WrapSystemDrawingBitmap_WhenOwned() using (var bmp = new Bitmap(51, 23)) { var memoryManager = new BitmapMemoryManager(bmp); - Bgra32 bg = Color.Red; - Bgra32 fg = Color.Green; + Bgra32 bg = Color.Red.ToPixel(); + Bgra32 fg = Color.Green.ToPixel(); using (var image = Image.WrapMemory(memoryManager, bmp.Width, bmp.Height)) { @@ -258,8 +258,8 @@ public void WrapSystemDrawingBitmap_FromBytes_WhenObserved() { Memory pixelMemory = memoryManager.Memory; Memory byteMemory = new CastMemoryManager(pixelMemory).Memory; - Bgra32 bg = Color.Red; - Bgra32 fg = Color.Green; + Bgra32 bg = Color.Red.ToPixel(); + Bgra32 fg = Color.Green.ToPixel(); using (var image = Image.WrapMemory(byteMemory, bmp.Width, bmp.Height)) { @@ -294,19 +294,22 @@ public void WrapSystemDrawingBitmap_FromBytes_WhenObserved() } } - [Fact] - public unsafe void WrapMemory_Throws_OnTooLessWrongSize() + [Theory] + [InlineData(20, 5, 5)] + [InlineData(1023, 32, 32)] + [InlineData(65536, 65537, 65536)] + public unsafe void WrapMemory_Throws_OnTooLessWrongSize(int size, int width, int height) { var cfg = Configuration.CreateDefaultInstance(); var metaData = new ImageMetadata(); - var array = new Rgba32[25]; + var array = new Rgba32[size]; Exception thrownException = null; fixed (void* ptr = array) { try { - using var image = Image.WrapMemory(cfg, ptr, 24, 5, 5, metaData); + using var image = Image.WrapMemory(cfg, ptr, size * sizeof(Rgba32), width, height, metaData); } catch (Exception e) { @@ -317,24 +320,30 @@ public unsafe void WrapMemory_Throws_OnTooLessWrongSize() Assert.IsType(thrownException); } - [Fact] - public unsafe void WrapMemory_FromPointer_CreatedImageIsCorrect() + [Theory] + [InlineData(25, 5, 5)] + [InlineData(26, 5, 5)] + [InlineData(2, 1, 1)] + [InlineData(1024, 32, 32)] + [InlineData(2048, 32, 32)] + public unsafe void WrapMemory_FromPointer_CreatedImageIsCorrect(int size, int width, int height) { var cfg = Configuration.CreateDefaultInstance(); var metaData = new ImageMetadata(); - var array = new Rgba32[25]; + var array = new Rgba32[size]; fixed (void* ptr = array) { - using (var image = Image.WrapMemory(cfg, ptr, 25, 5, 5, metaData)) + using (var image = Image.WrapMemory(cfg, ptr, size * sizeof(Rgba32), width, height, metaData)) { Assert.True(image.DangerousTryGetSinglePixelMemory(out Memory imageMem)); Span imageSpan = imageMem.Span; + Span sourceSpan = array.AsSpan(0, width * height); ref Rgba32 pixel0 = ref imageSpan[0]; - Assert.True(Unsafe.AreSame(ref array[0], ref pixel0)); + Assert.True(Unsafe.AreSame(ref sourceSpan[0], ref pixel0)); ref Rgba32 pixel_1 = ref imageSpan[imageSpan.Length - 1]; - Assert.True(Unsafe.AreSame(ref array[array.Length - 1], ref pixel_1)); + Assert.True(Unsafe.AreSame(ref sourceSpan[sourceSpan.Length - 1], ref pixel_1)); Assert.Equal(cfg, image.Configuration); Assert.Equal(metaData, image.Metadata); @@ -355,8 +364,8 @@ public unsafe void WrapSystemDrawingBitmap_FromPointer() using (var memoryManager = new BitmapMemoryManager(bmp)) { Memory pixelMemory = memoryManager.Memory; - Bgra32 bg = Color.Red; - Bgra32 fg = Color.Green; + Bgra32 bg = Color.Red.ToPixel(); + Bgra32 fg = Color.Green.ToPixel(); fixed (void* p = pixelMemory.Span) { @@ -395,6 +404,7 @@ public unsafe void WrapSystemDrawingBitmap_FromPointer() [InlineData(0, 5, 5)] [InlineData(20, 5, 5)] [InlineData(1023, 32, 32)] + [InlineData(65536, 65537, 65536)] public void WrapMemory_MemoryOfT_InvalidSize(int size, int height, int width) { var array = new Rgba32[size]; @@ -430,6 +440,7 @@ private class TestMemoryOwner : IMemoryOwner [InlineData(0, 5, 5)] [InlineData(20, 5, 5)] [InlineData(1023, 32, 32)] + [InlineData(65536, 65537, 65536)] public void WrapMemory_IMemoryOwnerOfT_InvalidSize(int size, int height, int width) { var array = new Rgba32[size]; @@ -476,6 +487,7 @@ public void WrapMemory_IMemoryOwnerOfT_ValidSize(int size, int height, int width [InlineData(0, 5, 5)] [InlineData(20, 5, 5)] [InlineData(1023, 32, 32)] + [InlineData(65536, 65537, 65536)] public void WrapMemory_IMemoryOwnerOfByte_InvalidSize(int size, int height, int width) { var array = new byte[size * Unsafe.SizeOf()]; @@ -523,6 +535,7 @@ public void WrapMemory_IMemoryOwnerOfByte_ValidSize(int size, int height, int wi [InlineData(0, 5, 5)] [InlineData(20, 5, 5)] [InlineData(1023, 32, 32)] + [InlineData(65536, 65537, 65536)] public void WrapMemory_MemoryOfByte_InvalidSize(int size, int height, int width) { var array = new byte[size * Unsafe.SizeOf()]; diff --git a/tests/ImageSharp.Tests/Image/ImageTests.cs b/tests/ImageSharp.Tests/Image/ImageTests.cs index ca51f7f5cb..ac91ea948e 100644 --- a/tests/ImageSharp.Tests/Image/ImageTests.cs +++ b/tests/ImageSharp.Tests/Image/ImageTests.cs @@ -61,7 +61,7 @@ public void Configuration_Width_Height() public void Configuration_Width_Height_BackgroundColor() { Configuration configuration = Configuration.Default.Clone(); - Rgba32 color = Color.Aquamarine; + Rgba32 color = Color.Aquamarine.ToPixel(); using (Image image = new(configuration, 11, 23, color)) { @@ -116,9 +116,9 @@ public void GetSet(bool enforceDisco) using Image image = new(this.configuration, 10, 10); Rgba32 val = image[3, 4]; Assert.Equal(default(Rgba32), val); - image[3, 4] = Color.Red; + image[3, 4] = Color.Red.ToPixel(); val = image[3, 4]; - Assert.Equal(Color.Red.ToRgba32(), val); + Assert.Equal(Color.Red.ToPixel(), val); } public static TheoryData OutOfRangeData = new() diff --git a/tests/ImageSharp.Tests/ImageInfoTests.cs b/tests/ImageSharp.Tests/ImageInfoTests.cs index 73324eccd7..322b0af196 100644 --- a/tests/ImageSharp.Tests/ImageInfoTests.cs +++ b/tests/ImageSharp.Tests/ImageInfoTests.cs @@ -1,7 +1,7 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.Formats; +using SixLabors.ImageSharp.Formats.Png; using SixLabors.ImageSharp.Metadata; namespace SixLabors.ImageSharp.Tests; @@ -15,12 +15,14 @@ public void ImageInfoInitializesCorrectly() const int height = 60; Size size = new(width, height); Rectangle rectangle = new(0, 0, width, height); - PixelTypeInfo pixelType = new(8); - ImageMetadata meta = new(); - ImageInfo info = new(pixelType, size, meta); + // Initialize the metadata to match standard decoding behavior. + ImageMetadata meta = new() { DecodedImageFormat = PngFormat.Instance }; + meta.GetPngMetadata(); - Assert.Equal(pixelType, info.PixelType); + ImageInfo info = new(size, meta); + + Assert.NotEqual(default, info.PixelType); Assert.Equal(width, info.Width); Assert.Equal(height, info.Height); Assert.Equal(size, info.Size); @@ -35,13 +37,16 @@ public void ImageInfoInitializesCorrectlyWithFrameMetadata() const int height = 60; Size size = new(width, height); Rectangle rectangle = new(0, 0, width, height); - PixelTypeInfo pixelType = new(8); - ImageMetadata meta = new(); - IReadOnlyList frameMetadata = new List() { new() }; - ImageInfo info = new(pixelType, size, meta, frameMetadata); + // Initialize the metadata to match standard decoding behavior. + ImageMetadata meta = new() { DecodedImageFormat = PngFormat.Instance }; + meta.GetPngMetadata(); + + IReadOnlyList frameMetadata = [new()]; + + ImageInfo info = new(size, meta, frameMetadata); - Assert.Equal(pixelType, info.PixelType); + Assert.NotEqual(default, info.PixelType); Assert.Equal(width, info.Width); Assert.Equal(height, info.Height); Assert.Equal(size, info.Size); diff --git a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj index dc081e0bea..41e6e525f8 100644 --- a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj +++ b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj @@ -12,12 +12,12 @@ - net7.0;net6.0 + net8.0 - net6.0 + net8.0 @@ -35,7 +35,11 @@ - + + @@ -76,9 +80,5 @@ - - - - diff --git a/tests/ImageSharp.Tests/Issues/Issue594.cs b/tests/ImageSharp.Tests/Issues/Issue594.cs index 51f1ef7c67..7f976a3731 100644 --- a/tests/ImageSharp.Tests/Issues/Issue594.cs +++ b/tests/ImageSharp.Tests/Issues/Issue594.cs @@ -8,10 +8,8 @@ namespace SixLabors.ImageSharp.Tests.Issues; public class Issue594 { - // This test fails for unknown reason in Release mode on linux and is meant to help reproducing the issue - // see https://github.com/SixLabors/ImageSharp/issues/594 - [Fact(Skip = "Skipped because of issue #594")] - public void NormalizedByte4() + [Fact] + public void NormalizedByte4Test() { // Test PackedValue Assert.Equal(0x0U, new NormalizedByte4(Vector4.Zero).PackedValue); @@ -33,68 +31,25 @@ public void NormalizedByte4() Assert.Equal(0, scaled.W); // Test FromScaledVector4. - var pixel = default(NormalizedByte4); - pixel.FromScaledVector4(scaled); + NormalizedByte4 pixel = NormalizedByte4.FromScaledVector4(scaled); Assert.Equal(0x81818181, pixel.PackedValue); // Test Ordering - float x = 0.1f; - float y = -0.3f; - float z = 0.5f; - float w = -0.7f; - Assert.Equal(0xA740DA0D, new NormalizedByte4(x, y, z, w).PackedValue); - var n = default(NormalizedByte4); - n.FromRgba32(new Rgba32(141, 90, 192, 39)); + const float x = 0.1f; + const float y = -0.3f; + const float z = 0.5f; + const float w = -0.7f; + + pixel = new(x, y, z, w); + Assert.Equal(0xA740DA0D, pixel.PackedValue); + NormalizedByte4 n = NormalizedByte4.FromRgba32(pixel.ToRgba32()); Assert.Equal(0xA740DA0D, n.PackedValue); Assert.Equal(958796544U, new NormalizedByte4(0.0008f, 0.15f, 0.30f, 0.45f).PackedValue); - - // var rgb = default(Rgb24); - // var rgba = default(Rgba32); - // var bgr = default(Bgr24); - // var bgra = default(Bgra32); - // var argb = default(Argb32); - - // new NormalizedByte4(x, y, z, w).ToRgb24(ref rgb); - // Assert.Equal(rgb, new Rgb24(141, 90, 192)); - - // new NormalizedByte4(x, y, z, w).ToRgba32(ref rgba); - // Assert.Equal(rgba, new Rgba32(141, 90, 192, 39)); - - // new NormalizedByte4(x, y, z, w).ToBgr24(ref bgr); - // Assert.Equal(bgr, new Bgr24(141, 90, 192)); - - // new NormalizedByte4(x, y, z, w).ToBgra32(ref bgra); - // Assert.Equal(bgra, new Bgra32(141, 90, 192, 39)); // this assert fails in Release build on linux (#594) - - // new NormalizedByte4(x, y, z, w).ToArgb32(ref argb); - // Assert.Equal(argb, new Argb32(141, 90, 192, 39)); - - // http://community.monogame.net/t/normalizedbyte4-texture2d-gives-different-results-from-xna/8012/8 - // var r = default(NormalizedByte4); - // r.FromRgba32(new Rgba32(9, 115, 202, 127)); - // r.ToRgba32(ref rgba); - // Assert.Equal(rgba, new Rgba32(9, 115, 202, 127)); - - // r.PackedValue = 0xff4af389; - // r.ToRgba32(ref rgba); - // Assert.Equal(rgba, new Rgba32(9, 115, 202, 127)); - - // r = default(NormalizedByte4); - // r.FromArgb32(new Argb32(9, 115, 202, 127)); - // r.ToArgb32(ref argb); - // Assert.Equal(argb, new Argb32(9, 115, 202, 127)); - - // r = default(NormalizedByte4); - // r.FromBgra32(new Bgra32(9, 115, 202, 127)); - // r.ToBgra32(ref bgra); - // Assert.Equal(bgra, new Bgra32(9, 115, 202, 127)); } - // This test fails for unknown reason in Release mode on linux and is meant to help reproducing the issue - // see https://github.com/SixLabors/ImageSharp/issues/594 - [Fact(Skip = "Skipped because of issue #594")] - public void NormalizedShort4() + [Fact] + public void NormalizedShort4Test() { // Test PackedValue Assert.Equal(0x0UL, new NormalizedShort4(Vector4.Zero).PackedValue); @@ -116,59 +71,20 @@ public void NormalizedShort4() Assert.Equal(1, scaled.W); // Test FromScaledVector4. - var pixel = default(NormalizedShort4); - pixel.FromScaledVector4(scaled); + NormalizedShort4 pixel = NormalizedShort4.FromScaledVector4(scaled); Assert.Equal(0x7FFF7FFF7FFF7FFFUL, pixel.PackedValue); // Test Ordering - float x = 0.1f; - float y = -0.3f; - float z = 0.5f; - float w = -0.7f; + const float x = 0.1f; + const float y = -0.3f; + const float z = 0.5f; + const float w = -0.7f; Assert.Equal(0xa6674000d99a0ccd, new NormalizedShort4(x, y, z, w).PackedValue); Assert.Equal(4150390751449251866UL, new NormalizedShort4(0.0008f, 0.15f, 0.30f, 0.45f).PackedValue); - - // var rgb = default(Rgb24); - // var rgba = default(Rgba32); - // var bgr = default(Bgr24); - // var bgra = default(Bgra32); - // var argb = default(Argb32); - - // new NormalizedShort4(x, y, z, w).ToRgb24(ref rgb); - // Assert.Equal(rgb, new Rgb24(141, 90, 192)); - - // new NormalizedShort4(x, y, z, w).ToRgba32(ref rgba); - // Assert.Equal(rgba, new Rgba32(141, 90, 192, 39)); // this assert fails in Release build on linux (#594) - - // new NormalizedShort4(x, y, z, w).ToBgr24(ref bgr); - // Assert.Equal(bgr, new Bgr24(141, 90, 192)); - - // new NormalizedShort4(x, y, z, w).ToBgra32(ref bgra); - // Assert.Equal(bgra, new Bgra32(141, 90, 192, 39)); - - // new NormalizedShort4(x, y, z, w).ToArgb32(ref argb); - // Assert.Equal(argb, new Argb32(141, 90, 192, 39)); - - // var r = default(NormalizedShort4); - // r.FromRgba32(new Rgba32(9, 115, 202, 127)); - // r.ToRgba32(ref rgba); - // Assert.Equal(rgba, new Rgba32(9, 115, 202, 127)); - - // r = default(NormalizedShort4); - // r.FromBgra32(new Bgra32(9, 115, 202, 127)); - // r.ToBgra32(ref bgra); - // Assert.Equal(bgra, new Bgra32(9, 115, 202, 127)); - - // r = default(NormalizedShort4); - // r.FromArgb32(new Argb32(9, 115, 202, 127)); - // r.ToArgb32(ref argb); - // Assert.Equal(argb, new Argb32(9, 115, 202, 127)); } - // This test fails for unknown reason in Release mode on linux and is meant to help reproducing the issue - // see https://github.com/SixLabors/ImageSharp/issues/594 - [Fact(Skip = "Skipped because of issue #594")] - public void Short4() + [Fact] + public void Short4Test() { // Test the limits. Assert.Equal(0x0UL, new Short4(Vector4.Zero).PackedValue); @@ -192,8 +108,7 @@ public void Short4() Assert.Equal(1, scaled.W); // Test FromScaledVector4. - var pixel = default(Short4); - pixel.FromScaledVector4(scaled); + Short4 pixel = Short4.FromScaledVector4(scaled); Assert.Equal(0x7FFF7FFF7FFF7FFFUL, pixel.PackedValue); // Test clamping. @@ -212,52 +127,11 @@ public void Short4() z = 29623; w = 193; Assert.Equal(0x00c173b7316d2d1bUL, new Short4(x, y, z, w).PackedValue); - - // var rgb = default(Rgb24); - // var rgba = default(Rgba32); - // var bgr = default(Bgr24); - // var bgra = default(Bgra32); - // var argb = default(Argb32); - - // new Short4(x, y, z, w).ToRgb24(ref rgb); - // Assert.Equal(rgb, new Rgb24(172, 177, 243)); // this assert fails in Release build on linux (#594) - - // new Short4(x, y, z, w).ToRgba32(ref rgba); - // Assert.Equal(rgba, new Rgba32(172, 177, 243, 128)); - - // new Short4(x, y, z, w).ToBgr24(ref bgr); - // Assert.Equal(bgr, new Bgr24(172, 177, 243)); - - // new Short4(x, y, z, w).ToBgra32(ref bgra); - // Assert.Equal(bgra, new Bgra32(172, 177, 243, 128)); - - // new Short4(x, y, z, w).ToArgb32(ref argb); - // Assert.Equal(argb, new Argb32(172, 177, 243, 128)); - - // var r = default(Short4); - // r.FromRgba32(new Rgba32(20, 38, 0, 255)); - // r.ToRgba32(ref rgba); - // Assert.Equal(rgba, new Rgba32(20, 38, 0, 255)); - - // r = default(Short4); - // r.FromBgra32(new Bgra32(20, 38, 0, 255)); - // r.ToBgra32(ref bgra); - // Assert.Equal(bgra, new Bgra32(20, 38, 0, 255)); - - // r = default(Short4); - // r.FromArgb32(new Argb32(20, 38, 0, 255)); - // r.ToArgb32(ref argb); - // Assert.Equal(argb, new Argb32(20, 38, 0, 255)); } + // TODO: Use tolerant comparer. // Comparison helpers with small tolerance to allow for floating point rounding during computations. - public static bool Equal(float a, float b) - { - return Math.Abs(a - b) < 1e-5; - } + public static bool Equal(float a, float b) => Math.Abs(a - b) < 1e-5; - public static bool Equal(Vector4 a, Vector4 b) - { - return Equal(a.X, b.X) && Equal(a.Y, b.Y) && Equal(a.Z, b.Z) && Equal(a.W, b.W); - } + public static bool Equal(Vector4 a, Vector4 b) => Equal(a.X, b.X) && Equal(a.Y, b.Y) && Equal(a.Z, b.Z) && Equal(a.W, b.W); } diff --git a/tests/ImageSharp.Tests/Metadata/ImageFrameMetadataTests.cs b/tests/ImageSharp.Tests/Metadata/ImageFrameMetadataTests.cs index bcc9675404..cdd6f0cc4f 100644 --- a/tests/ImageSharp.Tests/Metadata/ImageFrameMetadataTests.cs +++ b/tests/ImageSharp.Tests/Metadata/ImageFrameMetadataTests.cs @@ -1,6 +1,7 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. +using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.Formats.Gif; using SixLabors.ImageSharp.Metadata; using SixLabors.ImageSharp.Metadata.Profiles.Icc; @@ -21,20 +22,20 @@ public void ConstructorImageFrameMetadata() { const int frameDelay = 42; const int colorTableLength = 128; - const GifDisposalMethod disposalMethod = GifDisposalMethod.RestoreToBackground; + const FrameDisposalMode disposalMethod = FrameDisposalMode.RestoreToBackground; ImageFrameMetadata metaData = new(); GifFrameMetadata gifFrameMetadata = metaData.GetGifMetadata(); gifFrameMetadata.FrameDelay = frameDelay; gifFrameMetadata.LocalColorTable = Enumerable.Repeat(Color.HotPink, colorTableLength).ToArray(); - gifFrameMetadata.DisposalMethod = disposalMethod; + gifFrameMetadata.DisposalMode = disposalMethod; ImageFrameMetadata clone = new(metaData); GifFrameMetadata cloneGifFrameMetadata = clone.GetGifMetadata(); Assert.Equal(frameDelay, cloneGifFrameMetadata.FrameDelay); Assert.Equal(colorTableLength, cloneGifFrameMetadata.LocalColorTable.Value.Length); - Assert.Equal(disposalMethod, cloneGifFrameMetadata.DisposalMethod); + Assert.Equal(disposalMethod, cloneGifFrameMetadata.DisposalMode); } [Fact] diff --git a/tests/ImageSharp.Tests/Metadata/ImageMetadataTests.cs b/tests/ImageSharp.Tests/Metadata/ImageMetadataTests.cs index 330b701474..ae02c3d57b 100644 --- a/tests/ImageSharp.Tests/Metadata/ImageMetadataTests.cs +++ b/tests/ImageSharp.Tests/Metadata/ImageMetadataTests.cs @@ -16,9 +16,9 @@ public class ImageMetadataTests [Fact] public void ConstructorImageMetadata() { - var metaData = new ImageMetadata(); + ImageMetadata metaData = new(); - var exifProfile = new ExifProfile(); + ExifProfile exifProfile = new(); metaData.ExifProfile = exifProfile; metaData.HorizontalResolution = 4; @@ -34,7 +34,7 @@ public void ConstructorImageMetadata() [Fact] public void CloneIsDeep() { - var metaData = new ImageMetadata + ImageMetadata metaData = new() { ExifProfile = new ExifProfile(), HorizontalResolution = 4, @@ -53,7 +53,7 @@ public void CloneIsDeep() [Fact] public void HorizontalResolution() { - var metaData = new ImageMetadata(); + ImageMetadata metaData = new(); Assert.Equal(96, metaData.HorizontalResolution); metaData.HorizontalResolution = 0; @@ -69,7 +69,7 @@ public void HorizontalResolution() [Fact] public void VerticalResolution() { - var metaData = new ImageMetadata(); + ImageMetadata metaData = new(); Assert.Equal(96, metaData.VerticalResolution); metaData.VerticalResolution = 0; @@ -85,20 +85,19 @@ public void VerticalResolution() [Fact] public void SyncProfiles() { - var exifProfile = new ExifProfile(); + ExifProfile exifProfile = new(); exifProfile.SetValue(ExifTag.XResolution, new Rational(200)); exifProfile.SetValue(ExifTag.YResolution, new Rational(300)); - using (var image = new Image(1, 1)) - { - image.Metadata.ExifProfile = exifProfile; - image.Metadata.HorizontalResolution = 400; - image.Metadata.VerticalResolution = 500; + using Image image = new(1, 1); + image.Metadata.ExifProfile = exifProfile; + image.Metadata.HorizontalResolution = 400; + image.Metadata.VerticalResolution = 500; - image.Metadata.SyncProfiles(); + using MemoryStream memoryStream = new(); + image.SaveAsBmp(memoryStream); - Assert.Equal(400, image.Metadata.ExifProfile.GetValue(ExifTag.XResolution).Value.ToDouble()); - Assert.Equal(500, image.Metadata.ExifProfile.GetValue(ExifTag.YResolution).Value.ToDouble()); - } + Assert.Equal(400, image.Metadata.ExifProfile.GetValue(ExifTag.XResolution).Value.ToDouble()); + Assert.Equal(500, image.Metadata.ExifProfile.GetValue(ExifTag.YResolution).Value.ToDouble()); } } diff --git a/tests/ImageSharp.Tests/PixelFormats/A8Tests.cs b/tests/ImageSharp.Tests/PixelFormats/A8Tests.cs index 95574a4d6c..4b4e84b4b3 100644 --- a/tests/ImageSharp.Tests/PixelFormats/A8Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/A8Tests.cs @@ -2,6 +2,7 @@ // Licensed under the Six Labors Split License. using System.Numerics; +using System.Runtime.CompilerServices; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Tests.PixelFormats; @@ -28,8 +29,8 @@ public void A8_Constructor() [Fact] public void A8_Equality() { - var left = new A8(16); - var right = new A8(32); + A8 left = new(16); + A8 right = new(32); Assert.True(left == new A8(16)); Assert.True(left != right); @@ -40,12 +41,11 @@ public void A8_Equality() public void A8_FromScaledVector4() { // Arrange - A8 alpha = default; - int expected = 128; + const int expected = 128; Vector4 scaled = new A8(.5F).ToScaledVector4(); // Act - alpha.FromScaledVector4(scaled); + A8 alpha = A8.FromScaledVector4(scaled); byte actual = alpha.PackedValue; // Assert @@ -56,7 +56,7 @@ public void A8_FromScaledVector4() public void A8_ToScaledVector4() { // Arrange - var alpha = new A8(.5F); + A8 alpha = new(.5F); // Act Vector4 actual = alpha.ToScaledVector4(); @@ -72,10 +72,10 @@ public void A8_ToScaledVector4() public void A8_ToVector4() { // Arrange - var alpha = new A8(.5F); + A8 alpha = new(.5F); // Act - var actual = alpha.ToVector4(); + Vector4 actual = alpha.ToVector4(); // Assert Assert.Equal(0, actual.X); @@ -87,11 +87,10 @@ public void A8_ToVector4() [Fact] public void A8_ToRgba32() { - var input = new A8(128); - var expected = new Rgba32(0, 0, 0, 128); + A8 input = new(128); + Rgba32 expected = new(0, 0, 0, 128); - Rgba32 actual = default; - input.ToRgba32(ref actual); + Rgba32 actual = input.ToRgba32(); Assert.Equal(expected, actual); } @@ -99,13 +98,27 @@ public void A8_ToRgba32() public void A8_FromBgra5551() { // arrange - var alpha = default(A8); - byte expected = byte.MaxValue; + const byte expected = byte.MaxValue; // act - alpha.FromBgra5551(new Bgra5551(0.0f, 0.0f, 0.0f, 1.0f)); + A8 alpha = A8.FromBgra5551(new Bgra5551(0.0f, 0.0f, 0.0f, 1.0f)); // assert Assert.Equal(expected, alpha.PackedValue); } + + [Fact] + public void A8_PixelInformation() + { + PixelTypeInfo info = A8.GetPixelTypeInfo(); + Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); + Assert.Equal(PixelAlphaRepresentation.Unassociated, info.AlphaRepresentation); + Assert.Equal(PixelColorType.Alpha, info.ColorType); + + PixelComponentInfo componentInfo = info.ComponentInfo.Value; + Assert.Equal(1, componentInfo.ComponentCount); + Assert.Equal(0, componentInfo.Padding); + Assert.Equal(8, componentInfo.GetComponentPrecision(0)); + Assert.Equal(8, componentInfo.GetMaximumComponentPrecision()); + } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Abgr32Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Abgr32Tests.cs index 13c84784cc..98fdce5dbd 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Abgr32Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Abgr32Tests.cs @@ -2,6 +2,7 @@ // Licensed under the Six Labors Split License. using System.Numerics; +using System.Runtime.CompilerServices; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Tests.PixelFormats; @@ -15,8 +16,8 @@ public class Abgr32Tests [Fact] public void AreEqual() { - var color1 = new Abgr32(byte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue); - var color2 = new Abgr32(byte.MaxValue, byte.MaxValue, byte.MaxValue); + Abgr32 color1 = new(byte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue); + Abgr32 color2 = new(byte.MaxValue, byte.MaxValue, byte.MaxValue); Assert.Equal(color1, color2); } @@ -27,8 +28,8 @@ public void AreEqual() [Fact] public void AreNotEqual() { - var color1 = new Abgr32(0, 0, byte.MaxValue, byte.MaxValue); - var color2 = new Abgr32(byte.MaxValue, byte.MaxValue, byte.MaxValue); + Abgr32 color1 = new(0, 0, byte.MaxValue, byte.MaxValue); + Abgr32 color2 = new(byte.MaxValue, byte.MaxValue, byte.MaxValue); Assert.NotEqual(color1, color2); } @@ -46,7 +47,7 @@ public void AreNotEqual() [MemberData(nameof(ColorData))] public void Constructor(byte b, byte g, byte r, byte a) { - var p = new Abgr32(r, g, b, a); + Abgr32 p = new(r, g, b, a); Assert.Equal(r, p.R); Assert.Equal(g, p.G); @@ -57,7 +58,7 @@ public void Constructor(byte b, byte g, byte r, byte a) [Fact] public unsafe void ByteLayoutIsSequentialBgra() { - var color = new Abgr32(1, 2, 3, 4); + Abgr32 color = new(1, 2, 3, 4); byte* ptr = (byte*)&color; Assert.Equal(4, ptr[0]); @@ -70,8 +71,8 @@ public unsafe void ByteLayoutIsSequentialBgra() [MemberData(nameof(ColorData))] public void Equality_WhenTrue(byte r, byte g, byte b, byte a) { - var x = new Abgr32(r, g, b, a); - var y = new Abgr32(r, g, b, a); + Abgr32 x = new(r, g, b, a); + Abgr32 y = new(r, g, b, a); Assert.True(x.Equals(y)); Assert.True(x.Equals((object)y)); @@ -85,8 +86,8 @@ public void Equality_WhenTrue(byte r, byte g, byte b, byte a) [InlineData(1, 255, 0, 0, 0, 255, 0, 0)] public void Equality_WhenFalse(byte b1, byte g1, byte r1, byte a1, byte b2, byte g2, byte r2, byte a2) { - var x = new Abgr32(r1, g1, b1, a1); - var y = new Abgr32(r2, g2, b2, a2); + Abgr32 x = new(r1, g1, b1, a1); + Abgr32 y = new(r2, g2, b2, a2); Assert.False(x.Equals(y)); Assert.False(x.Equals((object)y)); @@ -95,8 +96,7 @@ public void Equality_WhenFalse(byte b1, byte g1, byte r1, byte a1, byte b2, byte [Fact] public void FromRgba32() { - var abgr = default(Abgr32); - abgr.FromRgba32(new Rgba32(1, 2, 3, 4)); + Abgr32 abgr = Abgr32.FromRgba32(new Rgba32(1, 2, 3, 4)); Assert.Equal(1, abgr.R); Assert.Equal(2, abgr.G); @@ -104,7 +104,7 @@ public void FromRgba32() Assert.Equal(4, abgr.A); } - private static Vector4 Vec(byte r, byte g, byte b, byte a = 255) => new Vector4( + private static Vector4 Vec(byte r, byte g, byte b, byte a = 255) => new( r / 255f, g / 255f, b / 255f, @@ -113,8 +113,7 @@ public void FromRgba32() [Fact] public void FromVector4() { - var c = default(Abgr32); - c.FromVector4(Vec(1, 2, 3, 4)); + Abgr32 c = Abgr32.FromVector4(Vec(1, 2, 3, 4)); Assert.Equal(1, c.R); Assert.Equal(2, c.G); @@ -125,7 +124,7 @@ public void FromVector4() [Fact] public void ToVector4() { - var abgr = new Abgr32(1, 2, 3, 4); + Abgr32 abgr = new(1, 2, 3, 4); Assert.Equal(Vec(1, 2, 3, 4), abgr.ToVector4()); } @@ -134,13 +133,30 @@ public void ToVector4() public void Abgr32_FromBgra5551() { // arrange - var abgr = default(Abgr32); - uint expected = uint.MaxValue; + const uint expected = uint.MaxValue; // act - abgr.FromBgra5551(new Bgra5551(1.0f, 1.0f, 1.0f, 1.0f)); + Abgr32 abgr = Abgr32.FromBgra5551(new Bgra5551(1f, 1f, 1f, 1f)); // assert Assert.Equal(expected, abgr.PackedValue); } + + [Fact] + public void Abgr32_PixelInformation() + { + PixelTypeInfo info = Abgr32.GetPixelTypeInfo(); + Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); + Assert.Equal(PixelAlphaRepresentation.Unassociated, info.AlphaRepresentation); + Assert.Equal(PixelColorType.Alpha | PixelColorType.BGR, info.ColorType); + + PixelComponentInfo componentInfo = info.ComponentInfo.Value; + Assert.Equal(4, componentInfo.ComponentCount); + Assert.Equal(0, componentInfo.Padding); + Assert.Equal(8, componentInfo.GetComponentPrecision(0)); + Assert.Equal(8, componentInfo.GetComponentPrecision(1)); + Assert.Equal(8, componentInfo.GetComponentPrecision(2)); + Assert.Equal(8, componentInfo.GetComponentPrecision(3)); + Assert.Equal(8, componentInfo.GetMaximumComponentPrecision()); + } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Argb32Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Argb32Tests.cs index 70012afb02..bcaf9265a3 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Argb32Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Argb32Tests.cs @@ -2,6 +2,7 @@ // Licensed under the Six Labors Split License. using System.Numerics; +using System.Runtime.CompilerServices; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Tests.PixelFormats; @@ -15,10 +16,10 @@ public class Argb32Tests [Fact] public void AreEqual() { - var color1 = new Argb32(0.0f, 0.0f, 0.0f, 0.0f); - var color2 = new Argb32(new Vector4(0.0f)); - var color3 = new Argb32(new Vector4(1.0f, 0.0f, 1.0f, 1.0f)); - var color4 = new Argb32(1.0f, 0.0f, 1.0f, 1.0f); + Argb32 color1 = new(0.0f, 0.0f, 0.0f, 0.0f); + Argb32 color2 = new(new Vector4(0.0f)); + Argb32 color3 = new(new Vector4(1f, 0.0f, 1f, 1f)); + Argb32 color4 = new(1f, 0.0f, 1f, 1f); Assert.Equal(color1, color2); Assert.Equal(color3, color4); @@ -30,10 +31,10 @@ public void AreEqual() [Fact] public void AreNotEqual() { - var color1 = new Argb32(0.0f, 0.0f, 0.0f, 0.0f); - var color2 = new Argb32(new Vector4(1.0f)); - var color3 = new Argb32(new Vector4(1.0f, 0.0f, 0.0f, 1.0f)); - var color4 = new Argb32(1.0f, 1.0f, 0.0f, 1.0f); + Argb32 color1 = new(0.0f, 0.0f, 0.0f, 0.0f); + Argb32 color2 = new(new Vector4(1f)); + Argb32 color3 = new(new Vector4(1f, 0.0f, 0.0f, 1f)); + Argb32 color4 = new(1f, 1f, 0.0f, 1f); Assert.NotEqual(color1, color2); Assert.NotEqual(color3, color4); @@ -45,25 +46,25 @@ public void AreNotEqual() [Fact] public void ConstructorAssignsProperties() { - var color1 = new Argb32(1, .1f, .133f, .864f); + Argb32 color1 = new(1, .1f, .133f, .864f); Assert.Equal(255, color1.R); Assert.Equal((byte)Math.Round(.1f * 255), color1.G); Assert.Equal((byte)Math.Round(.133f * 255), color1.B); Assert.Equal((byte)Math.Round(.864f * 255), color1.A); - var color2 = new Argb32(1, .1f, .133f); + Argb32 color2 = new(1, .1f, .133f); Assert.Equal(255, color2.R); Assert.Equal(Math.Round(.1f * 255), color2.G); Assert.Equal(Math.Round(.133f * 255), color2.B); Assert.Equal(255, color2.A); - var color4 = new Argb32(new Vector3(1, .1f, .133f)); + Argb32 color4 = new(new Vector3(1, .1f, .133f)); Assert.Equal(255, color4.R); Assert.Equal(Math.Round(.1f * 255), color4.G); Assert.Equal(Math.Round(.133f * 255), color4.B); Assert.Equal(255, color4.A); - var color5 = new Argb32(new Vector4(1, .1f, .133f, .5f)); + Argb32 color5 = new(new Vector4(1, .1f, .133f, .5f)); Assert.Equal(255, color5.R); Assert.Equal(Math.Round(.1f * 255), color5.G); Assert.Equal(Math.Round(.133f * 255), color5.B); @@ -93,7 +94,7 @@ public void Argb32_ToVector4() public void Argb32_ToScaledVector4() { // arrange - var argb = new Argb32(Vector4.One); + Argb32 argb = new(Vector4.One); // act Vector4 actual = argb.ToScaledVector4(); @@ -110,11 +111,10 @@ public void Argb32_FromScaledVector4() { // arrange Vector4 scaled = new Argb32(Vector4.One).ToScaledVector4(); - var pixel = default(Argb32); - uint expected = 0xFFFFFFFF; + const uint expected = 0xFFFFFFFF; // act - pixel.FromScaledVector4(scaled); + Argb32 pixel = Argb32.FromScaledVector4(scaled); uint actual = pixel.PackedValue; // assert @@ -125,11 +125,10 @@ public void Argb32_FromScaledVector4() public void Argb32_FromBgra5551() { // arrange - var argb = default(Argb32); - uint expected = uint.MaxValue; + const uint expected = uint.MaxValue; // act - argb.FromBgra5551(new Bgra5551(1.0f, 1.0f, 1.0f, 1.0f)); + Argb32 argb = Argb32.FromBgra5551(new Bgra5551(1f, 1f, 1f, 1f)); // assert Assert.Equal(expected, argb.PackedValue); @@ -141,4 +140,22 @@ public void Argb32_Clamping() Assert.Equal(Vector4.Zero, new Argb32(Vector4.One * -1234.0f).ToVector4()); Assert.Equal(Vector4.One, new Argb32(Vector4.One * +1234.0f).ToVector4()); } + + [Fact] + public void Argb32_PixelInformation() + { + PixelTypeInfo info = Argb32.GetPixelTypeInfo(); + Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); + Assert.Equal(PixelAlphaRepresentation.Unassociated, info.AlphaRepresentation); + Assert.Equal(PixelColorType.Alpha | PixelColorType.RGB, info.ColorType); + + PixelComponentInfo componentInfo = info.ComponentInfo.Value; + Assert.Equal(4, componentInfo.ComponentCount); + Assert.Equal(0, componentInfo.Padding); + Assert.Equal(8, componentInfo.GetComponentPrecision(0)); + Assert.Equal(8, componentInfo.GetComponentPrecision(1)); + Assert.Equal(8, componentInfo.GetComponentPrecision(2)); + Assert.Equal(8, componentInfo.GetComponentPrecision(3)); + Assert.Equal(8, componentInfo.GetMaximumComponentPrecision()); + } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Bgr24Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Bgr24Tests.cs index 730e3996d9..362e20bbae 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgr24Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgr24Tests.cs @@ -2,6 +2,7 @@ // Licensed under the Six Labors Split License. using System.Numerics; +using System.Runtime.CompilerServices; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Tests.PixelFormats; @@ -12,8 +13,8 @@ public class Bgr24Tests [Fact] public void AreEqual() { - var color1 = new Bgr24(byte.MaxValue, 0, byte.MaxValue); - var color2 = new Bgr24(byte.MaxValue, 0, byte.MaxValue); + Bgr24 color1 = new(byte.MaxValue, 0, byte.MaxValue); + Bgr24 color2 = new(byte.MaxValue, 0, byte.MaxValue); Assert.Equal(color1, color2); } @@ -21,8 +22,8 @@ public void AreEqual() [Fact] public void AreNotEqual() { - var color1 = new Bgr24(byte.MaxValue, 0, 0); - var color2 = new Bgr24(byte.MaxValue, 0, byte.MaxValue); + Bgr24 color1 = new(byte.MaxValue, 0, 0); + Bgr24 color2 = new(byte.MaxValue, 0, byte.MaxValue); Assert.NotEqual(color1, color2); } @@ -33,7 +34,7 @@ public void AreNotEqual() [MemberData(nameof(ColorData))] public void Constructor(byte r, byte g, byte b) { - var p = new Rgb24(r, g, b); + Rgb24 p = new(r, g, b); Assert.Equal(r, p.R); Assert.Equal(g, p.G); @@ -43,7 +44,7 @@ public void Constructor(byte r, byte g, byte b) [Fact] public unsafe void ByteLayoutIsSequentialBgr() { - var color = new Bgr24(1, 2, 3); + Bgr24 color = new(1, 2, 3); byte* ptr = (byte*)&color; Assert.Equal(3, ptr[0]); @@ -55,8 +56,8 @@ public unsafe void ByteLayoutIsSequentialBgr() [MemberData(nameof(ColorData))] public void Equals_WhenTrue(byte r, byte g, byte b) { - var x = new Bgr24(r, g, b); - var y = new Bgr24(r, g, b); + Bgr24 x = new(r, g, b); + Bgr24 y = new(r, g, b); Assert.True(x.Equals(y)); Assert.True(x.Equals((object)y)); @@ -69,8 +70,8 @@ public void Equals_WhenTrue(byte r, byte g, byte b) [InlineData(1, 255, 0, 0, 255, 0)] public void Equals_WhenFalse(byte r1, byte g1, byte b1, byte r2, byte g2, byte b2) { - var a = new Bgr24(r1, g1, b1); - var b = new Bgr24(r2, g2, b2); + Bgr24 a = new(r1, g1, b1); + Bgr24 b = new(r2, g2, b2); Assert.False(a.Equals(b)); Assert.False(a.Equals((object)b)); @@ -79,15 +80,14 @@ public void Equals_WhenFalse(byte r1, byte g1, byte b1, byte r2, byte g2, byte b [Fact] public void FromRgba32() { - var rgb = default(Bgr24); - rgb.FromRgba32(new Rgba32(1, 2, 3, 4)); + Bgr24 rgb = Bgr24.FromRgba32(new Rgba32(1, 2, 3, 4)); Assert.Equal(1, rgb.R); Assert.Equal(2, rgb.G); Assert.Equal(3, rgb.B); } - private static Vector4 Vec(byte r, byte g, byte b, byte a = 255) => new Vector4( + private static Vector4 Vec(byte r, byte g, byte b, byte a = 255) => new( r / 255f, g / 255f, b / 255f, @@ -96,8 +96,7 @@ public void FromRgba32() [Fact] public void FromVector4() { - var rgb = default(Bgr24); - rgb.FromVector4(Vec(1, 2, 3, 4)); + Bgr24 rgb = Bgr24.FromVector4(Vec(1, 2, 3, 4)); Assert.Equal(1, rgb.R); Assert.Equal(2, rgb.G); @@ -107,7 +106,7 @@ public void FromVector4() [Fact] public void ToVector4() { - var rgb = new Bgr24(1, 2, 3); + Bgr24 rgb = new(1, 2, 3); Assert.Equal(Vec(1, 2, 3), rgb.ToVector4()); } @@ -115,15 +114,29 @@ public void ToVector4() [Fact] public void Bgr24_FromBgra5551() { - // arrange - var bgr = default(Bgr24); - // act - bgr.FromBgra5551(new Bgra5551(1.0f, 1.0f, 1.0f, 1.0f)); + Bgr24 bgr = Bgr24.FromBgra5551(new Bgra5551(1f, 1f, 1f, 1f)); // assert Assert.Equal(255, bgr.R); Assert.Equal(255, bgr.G); Assert.Equal(255, bgr.B); } + + [Fact] + public void Bgr24_PixelInformation() + { + PixelTypeInfo info = Bgr24.GetPixelTypeInfo(); + Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); + Assert.Equal(PixelAlphaRepresentation.None, info.AlphaRepresentation); + Assert.Equal(PixelColorType.BGR, info.ColorType); + + PixelComponentInfo componentInfo = info.ComponentInfo.Value; + Assert.Equal(3, componentInfo.ComponentCount); + Assert.Equal(0, componentInfo.Padding); + Assert.Equal(8, componentInfo.GetComponentPrecision(0)); + Assert.Equal(8, componentInfo.GetComponentPrecision(1)); + Assert.Equal(8, componentInfo.GetComponentPrecision(2)); + Assert.Equal(8, componentInfo.GetMaximumComponentPrecision()); + } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Bgr565Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Bgr565Tests.cs index 8245a578f9..3c4a104233 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgr565Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgr565Tests.cs @@ -2,6 +2,7 @@ // Licensed under the Six Labors Split License. using System.Numerics; +using System.Runtime.CompilerServices; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Tests.PixelFormats; @@ -15,10 +16,10 @@ public class Bgr565Tests [Fact] public void AreEqual() { - var color1 = new Bgr565(0.0f, 0.0f, 0.0f); - var color2 = new Bgr565(new Vector3(0.0f)); - var color3 = new Bgr565(new Vector3(1.0f, 0.0f, 1.0f)); - var color4 = new Bgr565(1.0f, 0.0f, 1.0f); + Bgr565 color1 = new(0.0f, 0.0f, 0.0f); + Bgr565 color2 = new(new Vector3(0.0f)); + Bgr565 color3 = new(new Vector3(1.0f, 0.0f, 1.0f)); + Bgr565 color4 = new(1.0f, 0.0f, 1.0f); Assert.Equal(color1, color2); Assert.Equal(color3, color4); @@ -30,10 +31,10 @@ public void AreEqual() [Fact] public void AreNotEqual() { - var color1 = new Bgr565(0.0f, 0.0f, 0.0f); - var color2 = new Bgr565(new Vector3(1.0f)); - var color3 = new Bgr565(new Vector3(1.0f, 0.0f, 0.0f)); - var color4 = new Bgr565(1.0f, 1.0f, 0.0f); + Bgr565 color1 = new(0.0f, 0.0f, 0.0f); + Bgr565 color2 = new(new Vector3(1.0f)); + Bgr565 color3 = new(new Vector3(1.0f, 0.0f, 0.0f)); + Bgr565 color4 = new(1.0f, 1.0f, 0.0f); Assert.NotEqual(color1, color2); Assert.NotEqual(color3, color4); @@ -66,7 +67,7 @@ public void Bgr565_ToVector3() public void Bgr565_ToScaledVector4() { // arrange - var bgr = new Bgr565(Vector3.One); + Bgr565 bgr = new(Vector3.One); // act Vector4 actual = bgr.ToScaledVector4(); @@ -83,11 +84,10 @@ public void Bgr565_FromScaledVector4() { // arrange Vector4 scaled = new Bgr565(Vector3.One).ToScaledVector4(); - int expected = 0xFFFF; - var pixel = default(Bgr565); + const int expected = 0xFFFF; // act - pixel.FromScaledVector4(scaled); + Bgr565 pixel = Bgr565.FromScaledVector4(scaled); ushort actual = pixel.PackedValue; // assert @@ -98,11 +98,10 @@ public void Bgr565_FromScaledVector4() public void Bgr565_FromBgra5551() { // arrange - var bgr = default(Bgr565); - ushort expected = ushort.MaxValue; + const ushort expected = ushort.MaxValue; // act - bgr.FromBgra5551(new Bgra5551(1.0f, 1.0f, 1.0f, 1.0f)); + Bgr565 bgr = Bgr565.FromBgra5551(new Bgra5551(1.0f, 1.0f, 1.0f, 1.0f)); // assert Assert.Equal(expected, bgr.PackedValue); @@ -112,14 +111,12 @@ public void Bgr565_FromBgra5551() public void Bgr565_FromArgb32() { // arrange - var bgr1 = default(Bgr565); - var bgr2 = default(Bgr565); - ushort expected1 = ushort.MaxValue; - ushort expected2 = ushort.MaxValue; + const ushort expected1 = ushort.MaxValue; + const ushort expected2 = ushort.MaxValue; // act - bgr1.FromArgb32(new Argb32(1.0f, 1.0f, 1.0f, 1.0f)); - bgr2.FromArgb32(new Argb32(1.0f, 1.0f, 1.0f, 0.0f)); + Bgr565 bgr1 = Bgr565.FromArgb32(new Argb32(1.0f, 1.0f, 1.0f, 1.0f)); + Bgr565 bgr2 = Bgr565.FromArgb32(new Argb32(1.0f, 1.0f, 1.0f, 0.0f)); // assert Assert.Equal(expected1, bgr1.PackedValue); @@ -130,14 +127,12 @@ public void Bgr565_FromArgb32() public void Bgr565_FromRgba32() { // arrange - var bgr1 = default(Bgr565); - var bgr2 = default(Bgr565); - ushort expected1 = ushort.MaxValue; - ushort expected2 = ushort.MaxValue; + const ushort expected1 = ushort.MaxValue; + const ushort expected2 = ushort.MaxValue; // act - bgr1.FromRgba32(new Rgba32(1.0f, 1.0f, 1.0f, 1.0f)); - bgr2.FromRgba32(new Rgba32(1.0f, 1.0f, 1.0f, 0.0f)); + Bgr565 bgr1 = Bgr565.FromRgba32(new Rgba32(1.0f, 1.0f, 1.0f, 1.0f)); + Bgr565 bgr2 = Bgr565.FromRgba32(new Rgba32(1.0f, 1.0f, 1.0f, 0.0f)); // assert Assert.Equal(expected1, bgr1.PackedValue); @@ -148,12 +143,11 @@ public void Bgr565_FromRgba32() public void Bgr565_ToRgba32() { // arrange - var bgra = new Bgr565(Vector3.One); - var expected = new Rgba32(Vector4.One); - var actual = default(Rgba32); + Bgr565 pixel = new(Vector3.One); + Rgba32 expected = new(Vector4.One); // act - bgra.ToRgba32(ref actual); + Rgba32 actual = pixel.ToRgba32(); Assert.Equal(expected, actual); } @@ -162,11 +156,10 @@ public void Bgr565_ToRgba32() public void Bgra565_FromRgb48() { // arrange - var bgr = default(Bgr565); - ushort expectedPackedValue = ushort.MaxValue; + const ushort expectedPackedValue = ushort.MaxValue; // act - bgr.FromRgb48(new Rgb48(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue)); + Bgr565 bgr = Bgr565.FromRgb48(new Rgb48(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue)); // assert Assert.Equal(expectedPackedValue, bgr.PackedValue); @@ -176,11 +169,10 @@ public void Bgra565_FromRgb48() public void Bgra565_FromRgba64() { // arrange - var bgr = default(Bgr565); - ushort expectedPackedValue = ushort.MaxValue; + const ushort expectedPackedValue = ushort.MaxValue; // act - bgr.FromRgba64(new Rgba64(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue, ushort.MaxValue)); + Bgr565 bgr = Bgr565.FromRgba64(new Rgba64(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue, ushort.MaxValue)); // assert Assert.Equal(expectedPackedValue, bgr.PackedValue); @@ -190,11 +182,10 @@ public void Bgra565_FromRgba64() public void Bgr565_FromBgr24() { // arrange - var bgr = default(Bgr565); - ushort expected = ushort.MaxValue; + const ushort expected = ushort.MaxValue; // act - bgr.FromBgr24(new Bgr24(byte.MaxValue, byte.MaxValue, byte.MaxValue)); + Bgr565 bgr = Bgr565.FromBgr24(new Bgr24(byte.MaxValue, byte.MaxValue, byte.MaxValue)); // assert Assert.Equal(expected, bgr.PackedValue); @@ -204,11 +195,10 @@ public void Bgr565_FromBgr24() public void Bgr565_FromRgb24() { // arrange - var bgr = default(Bgr565); - ushort expected = ushort.MaxValue; + const ushort expected = ushort.MaxValue; // act - bgr.FromRgb24(new Rgb24(byte.MaxValue, byte.MaxValue, byte.MaxValue)); + Bgr565 bgr = Bgr565.FromRgb24(new Rgb24(byte.MaxValue, byte.MaxValue, byte.MaxValue)); // assert Assert.Equal(expected, bgr.PackedValue); @@ -218,11 +208,10 @@ public void Bgr565_FromRgb24() public void Bgr565_FromGrey8() { // arrange - var bgr = default(Bgr565); - ushort expected = ushort.MaxValue; + const ushort expected = ushort.MaxValue; // act - bgr.FromL8(new L8(byte.MaxValue)); + Bgr565 bgr = Bgr565.FromL8(new L8(byte.MaxValue)); // assert Assert.Equal(expected, bgr.PackedValue); @@ -232,11 +221,10 @@ public void Bgr565_FromGrey8() public void Bgr565_FromGrey16() { // arrange - var bgr = default(Bgr565); - ushort expected = ushort.MaxValue; + const ushort expected = ushort.MaxValue; // act - bgr.FromL16(new L16(ushort.MaxValue)); + Bgr565 bgr = Bgr565.FromL16(new L16(ushort.MaxValue)); // assert Assert.Equal(expected, bgr.PackedValue); @@ -248,4 +236,21 @@ public void Bgr565_Clamping() Assert.Equal(Vector3.Zero, new Bgr565(Vector3.One * -1234F).ToVector3()); Assert.Equal(Vector3.One, new Bgr565(Vector3.One * 1234F).ToVector3()); } + + [Fact] + public void Bgr565_PixelInformation() + { + PixelTypeInfo info = Bgr565.GetPixelTypeInfo(); + Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); + Assert.Equal(PixelAlphaRepresentation.None, info.AlphaRepresentation); + Assert.Equal(PixelColorType.BGR, info.ColorType); + + PixelComponentInfo componentInfo = info.ComponentInfo.Value; + Assert.Equal(3, componentInfo.ComponentCount); + Assert.Equal(0, componentInfo.Padding); + Assert.Equal(5, componentInfo.GetComponentPrecision(0)); + Assert.Equal(6, componentInfo.GetComponentPrecision(1)); + Assert.Equal(5, componentInfo.GetComponentPrecision(2)); + Assert.Equal(6, componentInfo.GetMaximumComponentPrecision()); + } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Bgra32Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Bgra32Tests.cs index 04c8813d58..277975896e 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgra32Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgra32Tests.cs @@ -2,6 +2,7 @@ // Licensed under the Six Labors Split License. using System.Numerics; +using System.Runtime.CompilerServices; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Tests.PixelFormats; @@ -15,8 +16,8 @@ public class Bgra32Tests [Fact] public void AreEqual() { - var color1 = new Bgra32(byte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue); - var color2 = new Bgra32(byte.MaxValue, byte.MaxValue, byte.MaxValue); + Bgra32 color1 = new(byte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue); + Bgra32 color2 = new(byte.MaxValue, byte.MaxValue, byte.MaxValue); Assert.Equal(color1, color2); } @@ -27,8 +28,8 @@ public void AreEqual() [Fact] public void AreNotEqual() { - var color1 = new Bgra32(0, 0, byte.MaxValue, byte.MaxValue); - var color2 = new Bgra32(byte.MaxValue, byte.MaxValue, byte.MaxValue); + Bgra32 color1 = new(0, 0, byte.MaxValue, byte.MaxValue); + Bgra32 color2 = new(byte.MaxValue, byte.MaxValue, byte.MaxValue); Assert.NotEqual(color1, color2); } @@ -46,7 +47,7 @@ public void AreNotEqual() [MemberData(nameof(ColorData))] public void Constructor(byte b, byte g, byte r, byte a) { - var p = new Bgra32(r, g, b, a); + Bgra32 p = new(r, g, b, a); Assert.Equal(r, p.R); Assert.Equal(g, p.G); @@ -57,7 +58,7 @@ public void Constructor(byte b, byte g, byte r, byte a) [Fact] public unsafe void ByteLayoutIsSequentialBgra() { - var color = new Bgra32(1, 2, 3, 4); + Bgra32 color = new(1, 2, 3, 4); byte* ptr = (byte*)&color; Assert.Equal(3, ptr[0]); @@ -70,8 +71,8 @@ public unsafe void ByteLayoutIsSequentialBgra() [MemberData(nameof(ColorData))] public void Equality_WhenTrue(byte b, byte g, byte r, byte a) { - var x = new Bgra32(r, g, b, a); - var y = new Bgra32(r, g, b, a); + Bgra32 x = new(r, g, b, a); + Bgra32 y = new(r, g, b, a); Assert.True(x.Equals(y)); Assert.True(x.Equals((object)y)); @@ -85,8 +86,8 @@ public void Equality_WhenTrue(byte b, byte g, byte r, byte a) [InlineData(1, 255, 0, 0, 0, 255, 0, 0)] public void Equality_WhenFalse(byte b1, byte g1, byte r1, byte a1, byte b2, byte g2, byte r2, byte a2) { - var x = new Bgra32(r1, g1, b1, a1); - var y = new Bgra32(r2, g2, b2, a2); + Bgra32 x = new(r1, g1, b1, a1); + Bgra32 y = new(r2, g2, b2, a2); Assert.False(x.Equals(y)); Assert.False(x.Equals((object)y)); @@ -95,8 +96,7 @@ public void Equality_WhenFalse(byte b1, byte g1, byte r1, byte a1, byte b2, byte [Fact] public void FromRgba32() { - var bgra = default(Bgra32); - bgra.FromRgba32(new Rgba32(1, 2, 3, 4)); + Bgra32 bgra = Bgra32.FromRgba32(new Rgba32(1, 2, 3, 4)); Assert.Equal(1, bgra.R); Assert.Equal(2, bgra.G); @@ -104,7 +104,7 @@ public void FromRgba32() Assert.Equal(4, bgra.A); } - private static Vector4 Vec(byte r, byte g, byte b, byte a = 255) => new Vector4( + private static Vector4 Vec(byte r, byte g, byte b, byte a = 255) => new( r / 255f, g / 255f, b / 255f, @@ -113,8 +113,7 @@ public void FromRgba32() [Fact] public void FromVector4() { - var c = default(Bgra32); - c.FromVector4(Vec(1, 2, 3, 4)); + Bgra32 c = Bgra32.FromVector4(Vec(1, 2, 3, 4)); Assert.Equal(1, c.R); Assert.Equal(2, c.G); @@ -125,7 +124,7 @@ public void FromVector4() [Fact] public void ToVector4() { - var rgb = new Bgra32(1, 2, 3, 4); + Bgra32 rgb = new(1, 2, 3, 4); Assert.Equal(Vec(1, 2, 3, 4), rgb.ToVector4()); } @@ -134,13 +133,30 @@ public void ToVector4() public void Bgra32_FromBgra5551() { // arrange - var bgra = default(Bgra32); - uint expected = uint.MaxValue; + const uint expected = uint.MaxValue; // act - bgra.FromBgra5551(new Bgra5551(1.0f, 1.0f, 1.0f, 1.0f)); + Bgra32 bgra = Bgra32.FromBgra5551(new Bgra5551(1.0f, 1.0f, 1.0f, 1.0f)); // assert Assert.Equal(expected, bgra.PackedValue); } + + [Fact] + public void Bgra32_PixelInformation() + { + PixelTypeInfo info = Bgra32.GetPixelTypeInfo(); + Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); + Assert.Equal(PixelAlphaRepresentation.Unassociated, info.AlphaRepresentation); + Assert.Equal(PixelColorType.BGR | PixelColorType.Alpha, info.ColorType); + + PixelComponentInfo componentInfo = info.ComponentInfo.Value; + Assert.Equal(4, componentInfo.ComponentCount); + Assert.Equal(0, componentInfo.Padding); + Assert.Equal(8, componentInfo.GetComponentPrecision(0)); + Assert.Equal(8, componentInfo.GetComponentPrecision(1)); + Assert.Equal(8, componentInfo.GetComponentPrecision(2)); + Assert.Equal(8, componentInfo.GetComponentPrecision(3)); + Assert.Equal(8, componentInfo.GetMaximumComponentPrecision()); + } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Bgra4444Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Bgra4444Tests.cs index 543b5814f9..5d20b5cf12 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgra4444Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgra4444Tests.cs @@ -2,6 +2,7 @@ // Licensed under the Six Labors Split License. using System.Numerics; +using System.Runtime.CompilerServices; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Tests.PixelFormats; @@ -15,10 +16,10 @@ public class Bgra4444Tests [Fact] public void AreEqual() { - var color1 = new Bgra4444(0.0f, 0.0f, 0.0f, 0.0f); - var color2 = new Bgra4444(new Vector4(0.0f)); - var color3 = new Bgra4444(new Vector4(1.0f, 0.0f, 1.0f, 1.0f)); - var color4 = new Bgra4444(1.0f, 0.0f, 1.0f, 1.0f); + Bgra4444 color1 = new(0.0f, 0.0f, 0.0f, 0.0f); + Bgra4444 color2 = new(new Vector4(0.0f)); + Bgra4444 color3 = new(new Vector4(1.0f, 0.0f, 1.0f, 1.0f)); + Bgra4444 color4 = new(1.0f, 0.0f, 1.0f, 1.0f); Assert.Equal(color1, color2); Assert.Equal(color3, color4); @@ -30,10 +31,10 @@ public void AreEqual() [Fact] public void AreNotEqual() { - var color1 = new Bgra4444(0.0f, 0.0f, 0.0f, 0.0f); - var color2 = new Bgra4444(new Vector4(1.0f)); - var color3 = new Bgra4444(new Vector4(1.0f, 0.0f, 0.0f, 1.0f)); - var color4 = new Bgra4444(1.0f, 1.0f, 0.0f, 1.0f); + Bgra4444 color1 = new(0.0f, 0.0f, 0.0f, 0.0f); + Bgra4444 color2 = new(new Vector4(1.0f)); + Bgra4444 color3 = new(new Vector4(1.0f, 0.0f, 0.0f, 1.0f)); + Bgra4444 color4 = new(1.0f, 1.0f, 0.0f, 1.0f); Assert.NotEqual(color1, color2); Assert.NotEqual(color3, color4); @@ -66,10 +67,10 @@ public void Bgra4444_ToVector4() public void Bgra4444_ToScaledVector4() { // arrange - var bgra = new Bgra4444(Vector4.One); + Bgra4444 pixel = new(Vector4.One); // act - Vector4 actual = bgra.ToScaledVector4(); + Vector4 actual = pixel.ToScaledVector4(); // assert Assert.Equal(1, actual.X); @@ -82,12 +83,11 @@ public void Bgra4444_ToScaledVector4() public void Bgra4444_ToRgba32() { // arrange - var bgra = new Bgra4444(Vector4.One); - var expected = new Rgba32(Vector4.One); - var actual = default(Rgba32); + Bgra4444 pixel = new(Vector4.One); + Rgba32 expected = new(Vector4.One); // act - bgra.ToRgba32(ref actual); + Rgba32 actual = pixel.ToRgba32(); Assert.Equal(expected, actual); } @@ -97,12 +97,11 @@ public void Bgra4444_FromScaledVector4() { // arrange Vector4 scaled = new Bgra4444(Vector4.One).ToScaledVector4(); - int expected = 0xFFFF; - var bgra = default(Bgra4444); + const int expected = 0xFFFF; // act - bgra.FromScaledVector4(scaled); - ushort actual = bgra.PackedValue; + Bgra4444 pixel = Bgra4444.FromScaledVector4(scaled); + ushort actual = pixel.PackedValue; // assert Assert.Equal(expected, actual); @@ -112,42 +111,38 @@ public void Bgra4444_FromScaledVector4() public void Bgra4444_FromBgra5551() { // arrange - var bgra = default(Bgra4444); - ushort expected = ushort.MaxValue; + const ushort expected = ushort.MaxValue; // act - bgra.FromBgra5551(new Bgra5551(1.0f, 1.0f, 1.0f, 1.0f)); + Bgra4444 pixel = Bgra4444.FromBgra5551(new Bgra5551(1.0f, 1.0f, 1.0f, 1.0f)); // assert - Assert.Equal(expected, bgra.PackedValue); + Assert.Equal(expected, pixel.PackedValue); } [Fact] public void Bgra4444_FromArgb32() { // arrange - var bgra = default(Bgra4444); - ushort expectedPackedValue = ushort.MaxValue; + const ushort expectedPackedValue = ushort.MaxValue; // act - bgra.FromArgb32(new Argb32(255, 255, 255, 255)); + Bgra4444 pixel = Bgra4444.FromArgb32(new Argb32(255, 255, 255, 255)); // assert - Assert.Equal(expectedPackedValue, bgra.PackedValue); + Assert.Equal(expectedPackedValue, pixel.PackedValue); } [Fact] public void Bgra4444_FromRgba32() { // arrange - var bgra1 = default(Bgra4444); - var bgra2 = default(Bgra4444); - ushort expectedPackedValue1 = ushort.MaxValue; - ushort expectedPackedValue2 = 0xFF0F; + const ushort expectedPackedValue1 = ushort.MaxValue; + const ushort expectedPackedValue2 = 0xFF0F; // act - bgra1.FromRgba32(new Rgba32(255, 255, 255, 255)); - bgra2.FromRgba32(new Rgba32(255, 0, 255, 255)); + Bgra4444 bgra1 = Bgra4444.FromRgba32(new Rgba32(255, 255, 255, 255)); + Bgra4444 bgra2 = Bgra4444.FromRgba32(new Rgba32(255, 0, 255, 255)); // assert Assert.Equal(expectedPackedValue1, bgra1.PackedValue); @@ -158,84 +153,78 @@ public void Bgra4444_FromRgba32() public void Bgra4444_FromRgb48() { // arrange - var bgra = default(Bgra4444); - ushort expectedPackedValue = ushort.MaxValue; + const ushort expectedPackedValue = ushort.MaxValue; // act - bgra.FromRgb48(new Rgb48(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue)); + Bgra4444 pixel = Bgra4444.FromRgb48(new Rgb48(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue)); // assert - Assert.Equal(expectedPackedValue, bgra.PackedValue); + Assert.Equal(expectedPackedValue, pixel.PackedValue); } [Fact] public void Bgra4444_FromRgba64() { // arrange - var bgra = default(Bgra4444); - ushort expectedPackedValue = ushort.MaxValue; + const ushort expectedPackedValue = ushort.MaxValue; // act - bgra.FromRgba64(new Rgba64(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue, ushort.MaxValue)); + Bgra4444 pixel = Bgra4444.FromRgba64(new Rgba64(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue, ushort.MaxValue)); // assert - Assert.Equal(expectedPackedValue, bgra.PackedValue); + Assert.Equal(expectedPackedValue, pixel.PackedValue); } [Fact] public void Bgra4444_FromGrey16() { // arrange - var bgra = default(Bgra4444); - ushort expectedPackedValue = ushort.MaxValue; + const ushort expectedPackedValue = ushort.MaxValue; // act - bgra.FromL16(new L16(ushort.MaxValue)); + Bgra4444 pixel = Bgra4444.FromL16(new L16(ushort.MaxValue)); // assert - Assert.Equal(expectedPackedValue, bgra.PackedValue); + Assert.Equal(expectedPackedValue, pixel.PackedValue); } [Fact] public void Bgra4444_FromGrey8() { // arrange - var bgra = default(Bgra4444); - ushort expectedPackedValue = ushort.MaxValue; + const ushort expectedPackedValue = ushort.MaxValue; // act - bgra.FromL8(new L8(byte.MaxValue)); + Bgra4444 pixel = Bgra4444.FromL8(new L8(byte.MaxValue)); // assert - Assert.Equal(expectedPackedValue, bgra.PackedValue); + Assert.Equal(expectedPackedValue, pixel.PackedValue); } [Fact] public void Bgra4444_FromBgr24() { // arrange - var bgra = default(Bgra4444); - ushort expectedPackedValue = ushort.MaxValue; + const ushort expectedPackedValue = ushort.MaxValue; // act - bgra.FromBgr24(new Bgr24(byte.MaxValue, byte.MaxValue, byte.MaxValue)); + Bgra4444 pixel = Bgra4444.FromBgr24(new Bgr24(byte.MaxValue, byte.MaxValue, byte.MaxValue)); // assert - Assert.Equal(expectedPackedValue, bgra.PackedValue); + Assert.Equal(expectedPackedValue, pixel.PackedValue); } [Fact] public void Bgra4444_FromRgb24() { // arrange - var bgra = default(Bgra4444); - ushort expectedPackedValue = ushort.MaxValue; + const ushort expectedPackedValue = ushort.MaxValue; // act - bgra.FromRgb24(new Rgb24(byte.MaxValue, byte.MaxValue, byte.MaxValue)); + Bgra4444 pixel = Bgra4444.FromRgb24(new Rgb24(byte.MaxValue, byte.MaxValue, byte.MaxValue)); // assert - Assert.Equal(expectedPackedValue, bgra.PackedValue); + Assert.Equal(expectedPackedValue, pixel.PackedValue); } [Fact] @@ -244,4 +233,22 @@ public void Bgra4444_Clamping() Assert.Equal(Vector4.Zero, new Bgra4444(Vector4.One * -1234.0f).ToVector4()); Assert.Equal(Vector4.One, new Bgra4444(Vector4.One * 1234.0f).ToVector4()); } + + [Fact] + public void Bgra4444_PixelInformation() + { + PixelTypeInfo info = Bgra4444.GetPixelTypeInfo(); + Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); + Assert.Equal(PixelAlphaRepresentation.Unassociated, info.AlphaRepresentation); + Assert.Equal(PixelColorType.BGR | PixelColorType.Alpha, info.ColorType); + + PixelComponentInfo componentInfo = info.ComponentInfo.Value; + Assert.Equal(4, componentInfo.ComponentCount); + Assert.Equal(0, componentInfo.Padding); + Assert.Equal(4, componentInfo.GetComponentPrecision(0)); + Assert.Equal(4, componentInfo.GetComponentPrecision(1)); + Assert.Equal(4, componentInfo.GetComponentPrecision(2)); + Assert.Equal(4, componentInfo.GetComponentPrecision(3)); + Assert.Equal(4, componentInfo.GetMaximumComponentPrecision()); + } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Bgra5551Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Bgra5551Tests.cs index ec54173101..38f809e49f 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgra5551Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgra5551Tests.cs @@ -2,6 +2,7 @@ // Licensed under the Six Labors Split License. using System.Numerics; +using System.Runtime.CompilerServices; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Tests.PixelFormats; @@ -15,10 +16,10 @@ public class Bgra5551Tests [Fact] public void AreEqual() { - var color1 = new Bgra5551(0.0f, 0.0f, 0.0f, 0.0f); - var color2 = new Bgra5551(new Vector4(0.0f)); - var color3 = new Bgra5551(new Vector4(1.0f, 0.0f, 0.0f, 1.0f)); - var color4 = new Bgra5551(1.0f, 0.0f, 0.0f, 1.0f); + Bgra5551 color1 = new(0.0f, 0.0f, 0.0f, 0.0f); + Bgra5551 color2 = new(new Vector4(0.0f)); + Bgra5551 color3 = new(new Vector4(1f, 0.0f, 0.0f, 1f)); + Bgra5551 color4 = new(1f, 0.0f, 0.0f, 1f); Assert.Equal(color1, color2); Assert.Equal(color3, color4); @@ -30,10 +31,10 @@ public void AreEqual() [Fact] public void AreNotEqual() { - var color1 = new Bgra5551(0.0f, 0.0f, 0.0f, 0.0f); - var color2 = new Bgra5551(new Vector4(1.0f)); - var color3 = new Bgra5551(new Vector4(1.0f, 0.0f, 0.0f, 1.0f)); - var color4 = new Bgra5551(1.0f, 1.0f, 0.0f, 1.0f); + Bgra5551 color1 = new(0.0f, 0.0f, 0.0f, 0.0f); + Bgra5551 color2 = new(new Vector4(1f)); + Bgra5551 color3 = new(new Vector4(1f, 0.0f, 0.0f, 1f)); + Bgra5551 color4 = new(1f, 1f, 0.0f, 1f); Assert.NotEqual(color1, color2); Assert.NotEqual(color3, color4); @@ -42,10 +43,10 @@ public void AreNotEqual() [Fact] public void Bgra5551_PackedValue() { - float x = 0x1a; - float y = 0x16; - float z = 0xd; - float w = 0x1; + const float x = 0x1a; + const float y = 0x16; + const float z = 0xd; + const float w = 0x1; Assert.Equal(0xeacd, new Bgra5551(x / 0x1f, y / 0x1f, z / 0x1f, w).PackedValue); Assert.Equal(3088, new Bgra5551(0.1f, -0.3f, 0.5f, -0.7f).PackedValue); @@ -71,10 +72,10 @@ public void Bgra5551_ToVector4() public void Bgra5551_ToScaledVector4() { // arrange - var bgra = new Bgra5551(Vector4.One); + Bgra5551 pixel = new(Vector4.One); // act - Vector4 actual = bgra.ToScaledVector4(); + Vector4 actual = pixel.ToScaledVector4(); // assert Assert.Equal(1, actual.X); @@ -87,12 +88,11 @@ public void Bgra5551_ToScaledVector4() public void Bgra5551_ToRgba32() { // arrange - var bgra = new Bgra5551(Vector4.One); - var expected = new Rgba32(Vector4.One); - var actual = default(Rgba32); + Bgra5551 pixel = new(Vector4.One); + Rgba32 expected = new(Vector4.One); // act - bgra.ToRgba32(ref actual); + Rgba32 actual = pixel.ToRgba32(); Assert.Equal(expected, actual); } @@ -102,11 +102,10 @@ public void Bgra5551_FromScaledVector4() { // arrange Vector4 scaled = new Bgra5551(Vector4.One).ToScaledVector4(); - int expected = 0xFFFF; - var pixel = default(Bgra5551); + const int expected = 0xFFFF; // act - pixel.FromScaledVector4(scaled); + Bgra5551 pixel = Bgra5551.FromScaledVector4(scaled); ushort actual = pixel.PackedValue; // assert @@ -117,13 +116,11 @@ public void Bgra5551_FromScaledVector4() public void Bgra5551_FromBgra5551() { // arrange - var bgra = default(Bgra5551); - var actual = default(Bgra5551); - var expected = new Bgra5551(1.0f, 0.0f, 1.0f, 1.0f); + Bgra5551 expected = new(1f, 0.0f, 1f, 1f); // act - bgra.FromBgra5551(expected); - actual.FromBgra5551(bgra); + Bgra5551 pixel = Bgra5551.FromBgra5551(expected); + Bgra5551 actual = Bgra5551.FromBgra5551(pixel); // assert Assert.Equal(expected, actual); @@ -133,14 +130,12 @@ public void Bgra5551_FromBgra5551() public void Bgra5551_FromRgba32() { // arrange - var bgra1 = default(Bgra5551); - var bgra2 = default(Bgra5551); - ushort expectedPackedValue1 = ushort.MaxValue; - ushort expectedPackedValue2 = 0xFC1F; + const ushort expectedPackedValue1 = ushort.MaxValue; + const ushort expectedPackedValue2 = 0xFC1F; // act - bgra1.FromRgba32(new Rgba32(255, 255, 255, 255)); - bgra2.FromRgba32(new Rgba32(255, 0, 255, 255)); + Bgra5551 bgra1 = Bgra5551.FromRgba32(new Rgba32(255, 255, 255, 255)); + Bgra5551 bgra2 = Bgra5551.FromRgba32(new Rgba32(255, 0, 255, 255)); // assert Assert.Equal(expectedPackedValue1, bgra1.PackedValue); @@ -151,14 +146,12 @@ public void Bgra5551_FromRgba32() public void Bgra5551_FromBgra32() { // arrange - var bgra1 = default(Bgra5551); - var bgra2 = default(Bgra5551); - ushort expectedPackedValue1 = ushort.MaxValue; - ushort expectedPackedValue2 = 0xFC1F; + const ushort expectedPackedValue1 = ushort.MaxValue; + const ushort expectedPackedValue2 = 0xFC1F; // act - bgra1.FromBgra32(new Bgra32(255, 255, 255, 255)); - bgra2.FromBgra32(new Bgra32(255, 0, 255, 255)); + Bgra5551 bgra1 = Bgra5551.FromBgra32(new Bgra32(255, 255, 255, 255)); + Bgra5551 bgra2 = Bgra5551.FromBgra32(new Bgra32(255, 0, 255, 255)); // assert Assert.Equal(expectedPackedValue1, bgra1.PackedValue); @@ -169,98 +162,91 @@ public void Bgra5551_FromBgra32() public void Bgra5551_FromArgb32() { // arrange - var bgra = default(Bgra5551); - ushort expectedPackedValue = ushort.MaxValue; + const ushort expectedPackedValue = ushort.MaxValue; // act - bgra.FromArgb32(new Argb32(255, 255, 255, 255)); + Bgra5551 pixel = Bgra5551.FromArgb32(new Argb32(255, 255, 255, 255)); // assert - Assert.Equal(expectedPackedValue, bgra.PackedValue); + Assert.Equal(expectedPackedValue, pixel.PackedValue); } [Fact] public void Bgra5551_FromRgb48() { // arrange - var bgra = default(Bgra5551); - ushort expectedPackedValue = ushort.MaxValue; + const ushort expectedPackedValue = ushort.MaxValue; // act - bgra.FromRgb48(new Rgb48(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue)); + Bgra5551 pixel = Bgra5551.FromRgb48(new Rgb48(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue)); // assert - Assert.Equal(expectedPackedValue, bgra.PackedValue); + Assert.Equal(expectedPackedValue, pixel.PackedValue); } [Fact] public void Bgra5551_FromRgba64() { // arrange - var bgra = default(Bgra5551); - ushort expectedPackedValue = ushort.MaxValue; + const ushort expectedPackedValue = ushort.MaxValue; // act - bgra.FromRgba64(new Rgba64(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue, ushort.MaxValue)); + Bgra5551 pixel = Bgra5551.FromRgba64(new Rgba64(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue, ushort.MaxValue)); // assert - Assert.Equal(expectedPackedValue, bgra.PackedValue); + Assert.Equal(expectedPackedValue, pixel.PackedValue); } [Fact] public void Bgra5551_FromGrey16() { // arrange - var bgra = default(Bgra5551); - ushort expectedPackedValue = ushort.MaxValue; + const ushort expectedPackedValue = ushort.MaxValue; // act - bgra.FromL16(new L16(ushort.MaxValue)); + Bgra5551 pixel = Bgra5551.FromL16(new L16(ushort.MaxValue)); // assert - Assert.Equal(expectedPackedValue, bgra.PackedValue); + Assert.Equal(expectedPackedValue, pixel.PackedValue); } [Fact] public void Bgra5551_FromGrey8() { // arrange - var bgra = default(Bgra5551); - ushort expectedPackedValue = ushort.MaxValue; + const ushort expectedPackedValue = ushort.MaxValue; // act - bgra.FromL8(new L8(byte.MaxValue)); + Bgra5551 pixel = Bgra5551.FromL8(new L8(byte.MaxValue)); // assert - Assert.Equal(expectedPackedValue, bgra.PackedValue); + Assert.Equal(expectedPackedValue, pixel.PackedValue); } [Fact] public void Bgra5551_FromBgr24() { // arrange - var bgra = default(Bgra5551); - ushort expectedPackedValue = ushort.MaxValue; + const ushort expectedPackedValue = ushort.MaxValue; // act - bgra.FromBgr24(new Bgr24(byte.MaxValue, byte.MaxValue, byte.MaxValue)); + Bgra5551 pixel = Bgra5551.FromBgr24(new Bgr24(byte.MaxValue, byte.MaxValue, byte.MaxValue)); // assert - Assert.Equal(expectedPackedValue, bgra.PackedValue); + Assert.Equal(expectedPackedValue, pixel.PackedValue); } [Fact] public void Bgra5551_FromRgb24() { // arrange - var bgra = default(Bgra5551); - ushort expectedPackedValue = ushort.MaxValue; + const ushort expectedPackedValue = ushort.MaxValue; // act - bgra.FromRgb24(new Rgb24(byte.MaxValue, byte.MaxValue, byte.MaxValue)); + Bgra5551 pixel = Bgra5551.FromRgb24(new Rgb24(byte.MaxValue, byte.MaxValue, byte.MaxValue)); // assert - Assert.Equal(expectedPackedValue, bgra.PackedValue); + Assert.Equal(expectedPackedValue, pixel.PackedValue); } [Fact] @@ -269,4 +255,22 @@ public void Bgra5551_Clamping() Assert.Equal(Vector4.Zero, new Bgra5551(Vector4.One * -1234.0f).ToVector4()); Assert.Equal(Vector4.One, new Bgra5551(Vector4.One * 1234.0f).ToVector4()); } + + [Fact] + public void Bgra5551_PixelInformation() + { + PixelTypeInfo info = Bgra5551.GetPixelTypeInfo(); + Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); + Assert.Equal(PixelAlphaRepresentation.Unassociated, info.AlphaRepresentation); + Assert.Equal(PixelColorType.BGR | PixelColorType.Alpha, info.ColorType); + + PixelComponentInfo componentInfo = info.ComponentInfo.Value; + Assert.Equal(4, componentInfo.ComponentCount); + Assert.Equal(0, componentInfo.Padding); + Assert.Equal(5, componentInfo.GetComponentPrecision(0)); + Assert.Equal(5, componentInfo.GetComponentPrecision(1)); + Assert.Equal(5, componentInfo.GetComponentPrecision(2)); + Assert.Equal(1, componentInfo.GetComponentPrecision(3)); + Assert.Equal(5, componentInfo.GetMaximumComponentPrecision()); + } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Byte4Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Byte4Tests.cs index 435f073915..e73d646408 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Byte4Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Byte4Tests.cs @@ -2,6 +2,7 @@ // Licensed under the Six Labors Split License. using System.Numerics; +using System.Runtime.CompilerServices; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Tests.PixelFormats; @@ -15,10 +16,10 @@ public class Byte4Tests [Fact] public void AreEqual() { - var color1 = new Byte4(0.0f, 0.0f, 0.0f, 0.0f); - var color2 = new Byte4(new Vector4(0.0f)); - var color3 = new Byte4(new Vector4(1.0f, 0.0f, 1.0f, 1.0f)); - var color4 = new Byte4(1.0f, 0.0f, 1.0f, 1.0f); + Byte4 color1 = new(0f, 0f, 0f, 0f); + Byte4 color2 = new(new Vector4(0f)); + Byte4 color3 = new(new Vector4(1f, 0f, 1f, 1f)); + Byte4 color4 = new(1f, 0f, 1f, 1f); Assert.Equal(color1, color2); Assert.Equal(color3, color4); @@ -30,10 +31,10 @@ public void AreEqual() [Fact] public void AreNotEqual() { - var color1 = new Byte4(0.0f, 0.0f, 0.0f, 0.0f); - var color2 = new Byte4(new Vector4(1.0f)); - var color3 = new Byte4(new Vector4(1.0f, 0.0f, 0.0f, 1.0f)); - var color4 = new Byte4(1.0f, 1.0f, 0.0f, 1.0f); + Byte4 color1 = new(0f, 0f, 0f, 0f); + Byte4 color2 = new(new Vector4(1f)); + Byte4 color3 = new(new Vector4(1f, 0f, 0f, 1f)); + Byte4 color4 = new(1f, 1f, 0f, 1f); Assert.NotEqual(color1, color2); Assert.NotEqual(color3, color4); @@ -63,10 +64,10 @@ public void Byte4_ToVector4() public void Byte4_ToScaledVector4() { // arrange - var byte4 = new Byte4(Vector4.One * 255); + Byte4 pixel = new(Vector4.One * 255); // act - Vector4 actual = byte4.ToScaledVector4(); + Vector4 actual = pixel.ToScaledVector4(); // assert Assert.Equal(1, actual.X); @@ -79,12 +80,11 @@ public void Byte4_ToScaledVector4() public void Byte4_ToRgba32() { // arrange - var byte4 = new Byte4(byte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue); - var expected = new Rgba32(Vector4.One); - var actual = default(Rgba32); + Byte4 pixel = new(byte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue); + Rgba32 expected = new(Vector4.One); // act - byte4.ToRgba32(ref actual); + Rgba32 actual = pixel.ToRgba32(); Assert.Equal(expected, actual); } @@ -94,11 +94,10 @@ public void Byte4_FromScaledVector4() { // arrange Vector4 scaled = new Byte4(Vector4.One * 255).ToScaledVector4(); - var pixel = default(Byte4); - uint expected = 0xFFFFFFFF; + const uint expected = 0xFFFFFFFF; // act - pixel.FromScaledVector4(scaled); + Byte4 pixel = Byte4.FromScaledVector4(scaled); uint actual = pixel.PackedValue; // assert @@ -109,126 +108,117 @@ public void Byte4_FromScaledVector4() public void Byte4_FromArgb32() { // arrange - var byte4 = default(Byte4); - uint expectedPackedValue = uint.MaxValue; + const uint expectedPackedValue = uint.MaxValue; // act - byte4.FromArgb32(new Argb32(255, 255, 255, 255)); + Byte4 pixel = Byte4.FromArgb32(new Argb32(255, 255, 255, 255)); // assert - Assert.Equal(expectedPackedValue, byte4.PackedValue); + Assert.Equal(expectedPackedValue, pixel.PackedValue); } [Fact] public void Byte4_FromBgr24() { // arrange - var byte4 = default(Byte4); - uint expectedPackedValue = uint.MaxValue; + const uint expectedPackedValue = uint.MaxValue; // act - byte4.FromBgr24(new Bgr24(byte.MaxValue, byte.MaxValue, byte.MaxValue)); + Byte4 pixel = Byte4.FromBgr24(new Bgr24(byte.MaxValue, byte.MaxValue, byte.MaxValue)); // assert - Assert.Equal(expectedPackedValue, byte4.PackedValue); + Assert.Equal(expectedPackedValue, pixel.PackedValue); } [Fact] public void Byte4_FromGrey8() { // arrange - var byte4 = default(Byte4); - uint expectedPackedValue = uint.MaxValue; + const uint expectedPackedValue = uint.MaxValue; // act - byte4.FromL8(new L8(byte.MaxValue)); + Byte4 pixel = Byte4.FromL8(new L8(byte.MaxValue)); // assert - Assert.Equal(expectedPackedValue, byte4.PackedValue); + Assert.Equal(expectedPackedValue, pixel.PackedValue); } [Fact] public void Byte4_FromGrey16() { // arrange - var byte4 = default(Byte4); - uint expectedPackedValue = uint.MaxValue; + const uint expectedPackedValue = uint.MaxValue; // act - byte4.FromL16(new L16(ushort.MaxValue)); + Byte4 pixel = Byte4.FromL16(new L16(ushort.MaxValue)); // assert - Assert.Equal(expectedPackedValue, byte4.PackedValue); + Assert.Equal(expectedPackedValue, pixel.PackedValue); } [Fact] public void Byte4_FromRgb24() { // arrange - var byte4 = default(Byte4); - uint expectedPackedValue = uint.MaxValue; + const uint expectedPackedValue = uint.MaxValue; // act - byte4.FromRgb24(new Rgb24(byte.MaxValue, byte.MaxValue, byte.MaxValue)); + Byte4 pixel = Byte4.FromRgb24(new Rgb24(byte.MaxValue, byte.MaxValue, byte.MaxValue)); // assert - Assert.Equal(expectedPackedValue, byte4.PackedValue); + Assert.Equal(expectedPackedValue, pixel.PackedValue); } [Fact] public void Byte4_FromBgra5551() { // arrange - var byte4 = default(Byte4); - uint expected = 0xFFFFFFFF; + const uint expected = 0xFFFFFFFF; // act - byte4.FromBgra5551(new Bgra5551(1.0f, 1.0f, 1.0f, 1.0f)); + Byte4 pixel = Byte4.FromBgra5551(new Bgra5551(1f, 1f, 1f, 1f)); // assert - Assert.Equal(expected, byte4.PackedValue); + Assert.Equal(expected, pixel.PackedValue); } [Fact] public void Byte4_FromRgba32() { // arrange - var byte4 = default(Byte4); - uint expectedPackedValue1 = uint.MaxValue; + const uint expectedPackedValue1 = uint.MaxValue; // act - byte4.FromRgba32(new Rgba32(255, 255, 255, 255)); + Byte4 pixel = Byte4.FromRgba32(new Rgba32(255, 255, 255, 255)); // assert - Assert.Equal(expectedPackedValue1, byte4.PackedValue); + Assert.Equal(expectedPackedValue1, pixel.PackedValue); } [Fact] public void Byte4_FromRgb48() { // arrange - var byte4 = default(Byte4); - uint expectedPackedValue = uint.MaxValue; + const uint expectedPackedValue = uint.MaxValue; // act - byte4.FromRgb48(new Rgb48(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue)); + Byte4 pixel = Byte4.FromRgb48(new Rgb48(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue)); // assert - Assert.Equal(expectedPackedValue, byte4.PackedValue); + Assert.Equal(expectedPackedValue, pixel.PackedValue); } [Fact] public void Byte4_FromRgba64() { // arrange - var byte4 = default(Byte4); - uint expectedPackedValue = uint.MaxValue; + const uint expectedPackedValue = uint.MaxValue; // act - byte4.FromRgba64(new Rgba64(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue, ushort.MaxValue)); + Byte4 pixel = Byte4.FromRgba64(new Rgba64(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue, ushort.MaxValue)); // assert - Assert.Equal(expectedPackedValue, byte4.PackedValue); + Assert.Equal(expectedPackedValue, pixel.PackedValue); } [Fact] @@ -237,4 +227,22 @@ public void Byte4_Clamping() Assert.Equal(Vector4.Zero, new Byte4(Vector4.One * -1234.0f).ToVector4()); Assert.Equal(Vector4.One * 255, new Byte4(Vector4.One * 1234.0f).ToVector4()); } + + [Fact] + public void Byte4_PixelInformation() + { + PixelTypeInfo info = Byte4.GetPixelTypeInfo(); + Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); + Assert.Equal(PixelAlphaRepresentation.Unassociated, info.AlphaRepresentation); + Assert.Equal(PixelColorType.RGB | PixelColorType.Alpha, info.ColorType); + + PixelComponentInfo componentInfo = info.ComponentInfo.Value; + Assert.Equal(4, componentInfo.ComponentCount); + Assert.Equal(0, componentInfo.Padding); + Assert.Equal(8, componentInfo.GetComponentPrecision(0)); + Assert.Equal(8, componentInfo.GetComponentPrecision(1)); + Assert.Equal(8, componentInfo.GetComponentPrecision(2)); + Assert.Equal(8, componentInfo.GetComponentPrecision(3)); + Assert.Equal(8, componentInfo.GetMaximumComponentPrecision()); + } } diff --git a/tests/ImageSharp.Tests/PixelFormats/HalfSingleTests.cs b/tests/ImageSharp.Tests/PixelFormats/HalfSingleTests.cs index 9ffaf3e21c..9366c51c98 100644 --- a/tests/ImageSharp.Tests/PixelFormats/HalfSingleTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/HalfSingleTests.cs @@ -2,6 +2,7 @@ // Licensed under the Six Labors Split License. using System.Numerics; +using System.Runtime.CompilerServices; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Tests.PixelFormats; @@ -25,11 +26,11 @@ public void HalfSingle_PackedValue() public void HalfSingle_ToVector4() { // arrange - var halfSingle = new HalfSingle(0.5f); - var expected = new Vector4(0.5f, 0, 0, 1); + HalfSingle pixel = new(0.5f); + Vector4 expected = new(0.5f, 0, 0, 1); // act - var actual = halfSingle.ToVector4(); + Vector4 actual = pixel.ToVector4(); // assert Assert.Equal(expected, actual); @@ -39,10 +40,10 @@ public void HalfSingle_ToVector4() public void HalfSingle_ToScaledVector4() { // arrange - var halfSingle = new HalfSingle(-1F); + HalfSingle pixel = new(-1F); // act - Vector4 actual = halfSingle.ToScaledVector4(); + Vector4 actual = pixel.ToScaledVector4(); // assert Assert.Equal(0, actual.X); @@ -56,14 +57,28 @@ public void HalfSingle_FromScaledVector4() { // arrange Vector4 scaled = new HalfSingle(-1F).ToScaledVector4(); - int expected = 48128; - var halfSingle = default(HalfSingle); + const int expected = 48128; // act - halfSingle.FromScaledVector4(scaled); - ushort actual = halfSingle.PackedValue; + HalfSingle pixel = HalfSingle.FromScaledVector4(scaled); + ushort actual = pixel.PackedValue; // assert Assert.Equal(expected, actual); } + + [Fact] + public void HalfSingle_PixelInformation() + { + PixelTypeInfo info = HalfSingle.GetPixelTypeInfo(); + Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); + Assert.Equal(PixelAlphaRepresentation.None, info.AlphaRepresentation); + Assert.Equal(PixelColorType.Red, info.ColorType); + + PixelComponentInfo componentInfo = info.ComponentInfo.Value; + Assert.Equal(1, componentInfo.ComponentCount); + Assert.Equal(0, componentInfo.Padding); + Assert.Equal(16, componentInfo.GetComponentPrecision(0)); + Assert.Equal(16, componentInfo.GetMaximumComponentPrecision()); + } } diff --git a/tests/ImageSharp.Tests/PixelFormats/HalfVector2Tests.cs b/tests/ImageSharp.Tests/PixelFormats/HalfVector2Tests.cs index eda9315363..c5a89df1e9 100644 --- a/tests/ImageSharp.Tests/PixelFormats/HalfVector2Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/HalfVector2Tests.cs @@ -2,6 +2,7 @@ // Licensed under the Six Labors Split License. using System.Numerics; +using System.Runtime.CompilerServices; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Tests.PixelFormats; @@ -30,7 +31,7 @@ public void HalfVector2_ToVector2() public void HalfVector2_ToScaledVector4() { // arrange - var halfVector = new HalfVector2(Vector2.One); + HalfVector2 halfVector = new(Vector2.One); // act Vector4 actual = halfVector.ToScaledVector4(); @@ -47,11 +48,10 @@ public void HalfVector2_FromScaledVector4() { // arrange Vector4 scaled = new HalfVector2(Vector2.One).ToScaledVector4(); - uint expected = 1006648320u; - var halfVector = default(HalfVector2); + const uint expected = 1006648320u; // act - halfVector.FromScaledVector4(scaled); + HalfVector2 halfVector = HalfVector2.FromScaledVector4(scaled); uint actual = halfVector.PackedValue; // assert @@ -62,11 +62,11 @@ public void HalfVector2_FromScaledVector4() public void HalfVector2_ToVector4() { // arrange - var halfVector = new HalfVector2(.5F, .25F); - var expected = new Vector4(0.5f, .25F, 0, 1); + HalfVector2 halfVector = new(.5F, .25F); + Vector4 expected = new(0.5f, .25F, 0, 1); // act - var actual = halfVector.ToVector4(); + Vector4 actual = halfVector.ToVector4(); // assert Assert.Equal(expected, actual); @@ -75,17 +75,30 @@ public void HalfVector2_ToVector4() [Fact] public void HalfVector2_FromBgra5551() { - // arrange - var halfVector2 = default(HalfVector2); - // act - halfVector2.FromBgra5551(new Bgra5551(1.0f, 1.0f, 1.0f, 1.0f)); + HalfVector2 pixel = HalfVector2.FromBgra5551(new Bgra5551(1f, 1f, 1f, 1f)); // assert - Vector4 actual = halfVector2.ToScaledVector4(); + Vector4 actual = pixel.ToScaledVector4(); Assert.Equal(1F, actual.X); Assert.Equal(1F, actual.Y); Assert.Equal(0, actual.Z); Assert.Equal(1, actual.W); } + + [Fact] + public void HalfVector2_PixelInformation() + { + PixelTypeInfo info = HalfVector2.GetPixelTypeInfo(); + Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); + Assert.Equal(PixelAlphaRepresentation.None, info.AlphaRepresentation); + Assert.Equal(PixelColorType.Red | PixelColorType.Green, info.ColorType); + + PixelComponentInfo componentInfo = info.ComponentInfo.Value; + Assert.Equal(2, componentInfo.ComponentCount); + Assert.Equal(0, componentInfo.Padding); + Assert.Equal(16, componentInfo.GetComponentPrecision(0)); + Assert.Equal(16, componentInfo.GetComponentPrecision(1)); + Assert.Equal(16, componentInfo.GetMaximumComponentPrecision()); + } } diff --git a/tests/ImageSharp.Tests/PixelFormats/HalfVector4Tests.cs b/tests/ImageSharp.Tests/PixelFormats/HalfVector4Tests.cs index 77120192bb..16c78a23d3 100644 --- a/tests/ImageSharp.Tests/PixelFormats/HalfVector4Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/HalfVector4Tests.cs @@ -2,6 +2,7 @@ // Licensed under the Six Labors Split License. using System.Numerics; +using System.Runtime.CompilerServices; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Tests.PixelFormats; @@ -38,10 +39,10 @@ public void HalfVector4_ToVector4() public void HalfVector4_ToScaledVector4() { // arrange - var halfVector4 = new HalfVector4(-Vector4.One); + HalfVector4 pixel = new(-Vector4.One); // act - Vector4 actual = halfVector4.ToScaledVector4(); + Vector4 actual = pixel.ToScaledVector4(); // assert Assert.Equal(0, actual.X); @@ -54,13 +55,12 @@ public void HalfVector4_ToScaledVector4() public void HalfVector4_FromScaledVector4() { // arrange - var halfVector4 = default(HalfVector4); Vector4 scaled = new HalfVector4(-Vector4.One).ToScaledVector4(); - ulong expected = 13547034390470638592uL; + const ulong expected = 13547034390470638592uL; // act - halfVector4.FromScaledVector4(scaled); - ulong actual = halfVector4.PackedValue; + HalfVector4 pixel = HalfVector4.FromScaledVector4(scaled); + ulong actual = pixel.PackedValue; // assert Assert.Equal(expected, actual); @@ -70,13 +70,30 @@ public void HalfVector4_FromScaledVector4() public void HalfVector4_FromBgra5551() { // arrange - var halfVector4 = default(HalfVector4); Vector4 expected = Vector4.One; // act - halfVector4.FromBgra5551(new Bgra5551(1.0f, 1.0f, 1.0f, 1.0f)); + HalfVector4 pixel = HalfVector4.FromBgra5551(new Bgra5551(1.0f, 1.0f, 1.0f, 1.0f)); // assert - Assert.Equal(expected, halfVector4.ToScaledVector4()); + Assert.Equal(expected, pixel.ToScaledVector4()); + } + + [Fact] + public void HalfVector4_PixelInformation() + { + PixelTypeInfo info = HalfVector4.GetPixelTypeInfo(); + Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); + Assert.Equal(PixelAlphaRepresentation.Unassociated, info.AlphaRepresentation); + Assert.Equal(PixelColorType.RGB | PixelColorType.Alpha, info.ColorType); + + PixelComponentInfo componentInfo = info.ComponentInfo.Value; + Assert.Equal(4, componentInfo.ComponentCount); + Assert.Equal(0, componentInfo.Padding); + Assert.Equal(16, componentInfo.GetComponentPrecision(0)); + Assert.Equal(16, componentInfo.GetComponentPrecision(1)); + Assert.Equal(16, componentInfo.GetComponentPrecision(2)); + Assert.Equal(16, componentInfo.GetComponentPrecision(3)); + Assert.Equal(16, componentInfo.GetMaximumComponentPrecision()); } } diff --git a/tests/ImageSharp.Tests/PixelFormats/L16Tests.cs b/tests/ImageSharp.Tests/PixelFormats/L16Tests.cs index 685da2ddf8..7f0a4217c1 100644 --- a/tests/ImageSharp.Tests/PixelFormats/L16Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/L16Tests.cs @@ -2,6 +2,7 @@ // Licensed under the Six Labors Split License. using System.Numerics; +using System.Runtime.CompilerServices; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Tests.PixelFormats; @@ -12,8 +13,8 @@ public class L16Tests [Fact] public void AreEqual() { - var color1 = new L16(3000); - var color2 = new L16(3000); + L16 color1 = new(3000); + L16 color2 = new(3000); Assert.Equal(color1, color2); } @@ -21,8 +22,8 @@ public void AreEqual() [Fact] public void AreNotEqual() { - var color1 = new L16(12345); - var color2 = new L16(54321); + L16 color1 = new(12345); + L16 color2 = new(54321); Assert.NotEqual(color1, color2); } @@ -39,13 +40,12 @@ public void L16_PackedValue_EqualsInput(ushort input) public void L16_FromScaledVector4() { // Arrange - L16 gray = default; const ushort expected = 32767; Vector4 scaled = new L16(expected).ToScaledVector4(); // Act - gray.FromScaledVector4(scaled); - ushort actual = gray.PackedValue; + L16 pixel = L16.FromScaledVector4(scaled); + ushort actual = pixel.PackedValue; // Assert Assert.Equal(expected, actual); @@ -58,10 +58,10 @@ public void L16_FromScaledVector4() public void L16_ToScaledVector4(ushort input) { // Arrange - var gray = new L16(input); + L16 pixel = new(input); // Act - Vector4 actual = gray.ToScaledVector4(); + Vector4 actual = pixel.ToScaledVector4(); // Assert float vectorInput = input / 65535F; @@ -75,13 +75,12 @@ public void L16_ToScaledVector4(ushort input) public void L16_FromVector4() { // Arrange - L16 gray = default; const ushort expected = 32767; - var vector = new L16(expected).ToVector4(); + Vector4 vector = new L16(expected).ToVector4(); // Act - gray.FromVector4(vector); - ushort actual = gray.PackedValue; + L16 pixel = L16.FromVector4(vector); + ushort actual = pixel.PackedValue; // Assert Assert.Equal(expected, actual); @@ -94,10 +93,10 @@ public void L16_FromVector4() public void L16_ToVector4(ushort input) { // Arrange - var gray = new L16(input); + L16 pixel = new(input); // Act - var actual = gray.ToVector4(); + Vector4 actual = pixel.ToVector4(); // Assert float vectorInput = input / 65535F; @@ -111,14 +110,13 @@ public void L16_ToVector4(ushort input) public void L16_FromRgba32() { // Arrange - L16 gray = default; const byte rgb = 128; - ushort scaledRgb = ColorNumerics.UpscaleFrom8BitTo16Bit(rgb); + ushort scaledRgb = ColorNumerics.From8BitTo16Bit(rgb); ushort expected = ColorNumerics.Get16BitBT709Luminance(scaledRgb, scaledRgb, scaledRgb); // Act - gray.FromRgba32(new Rgba32(rgb, rgb, rgb)); - ushort actual = gray.PackedValue; + L16 pixel = L16.FromRgba32(new Rgba32(rgb, rgb, rgb)); + ushort actual = pixel.PackedValue; // Assert Assert.Equal(expected, actual); @@ -131,12 +129,11 @@ public void L16_FromRgba32() public void L16_ToRgba32(ushort input) { // Arrange - ushort expected = ColorNumerics.DownScaleFrom16BitTo8Bit(input); - var gray = new L16(input); + ushort expected = ColorNumerics.From16BitTo8Bit(input); + L16 pixel = new(input); // Act - Rgba32 actual = default; - gray.ToRgba32(ref actual); + Rgba32 actual = pixel.ToRgba32(); // Assert Assert.Equal(expected, actual.R); @@ -149,13 +146,27 @@ public void L16_ToRgba32(ushort input) public void L16_FromBgra5551() { // arrange - var gray = default(L16); - ushort expected = ushort.MaxValue; + const ushort expected = ushort.MaxValue; // act - gray.FromBgra5551(new Bgra5551(1.0f, 1.0f, 1.0f, 1.0f)); + L16 pixel = L16.FromBgra5551(new Bgra5551(1.0f, 1.0f, 1.0f, 1.0f)); // assert - Assert.Equal(expected, gray.PackedValue); + Assert.Equal(expected, pixel.PackedValue); + } + + [Fact] + public void L16_PixelInformation() + { + PixelTypeInfo info = L16.GetPixelTypeInfo(); + Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); + Assert.Equal(PixelAlphaRepresentation.None, info.AlphaRepresentation); + Assert.Equal(PixelColorType.Luminance, info.ColorType); + + PixelComponentInfo componentInfo = info.ComponentInfo.Value; + Assert.Equal(1, componentInfo.ComponentCount); + Assert.Equal(0, componentInfo.Padding); + Assert.Equal(16, componentInfo.GetComponentPrecision(0)); + Assert.Equal(16, componentInfo.GetMaximumComponentPrecision()); } } diff --git a/tests/ImageSharp.Tests/PixelFormats/L8Tests.cs b/tests/ImageSharp.Tests/PixelFormats/L8Tests.cs index afdc039a28..1ca865ef41 100644 --- a/tests/ImageSharp.Tests/PixelFormats/L8Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/L8Tests.cs @@ -2,6 +2,7 @@ // Licensed under the Six Labors Split License. using System.Numerics; +using System.Runtime.CompilerServices; using SixLabors.ImageSharp.PixelFormats; // ReSharper disable InconsistentNaming @@ -24,8 +25,8 @@ public void L8_PackedValue_EqualsInput(byte input) [Fact] public void AreEqual() { - var color1 = new L8(100); - var color2 = new L8(100); + L8 color1 = new(100); + L8 color2 = new(100); Assert.Equal(color1, color2); } @@ -33,8 +34,8 @@ public void AreEqual() [Fact] public void AreNotEqual() { - var color1 = new L8(100); - var color2 = new L8(200); + L8 color1 = new(100); + L8 color2 = new(200); Assert.NotEqual(color1, color2); } @@ -43,13 +44,12 @@ public void AreNotEqual() public void L8_FromScaledVector4() { // Arrange - L8 gray = default; const byte expected = 128; Vector4 scaled = new L8(expected).ToScaledVector4(); // Act - gray.FromScaledVector4(scaled); - byte actual = gray.PackedValue; + L8 pixel = L8.FromScaledVector4(scaled); + byte actual = pixel.PackedValue; // Assert Assert.Equal(expected, actual); @@ -60,10 +60,10 @@ public void L8_FromScaledVector4() public void L8_ToScaledVector4(byte input) { // Arrange - var gray = new L8(input); + L8 pixel = new(input); // Act - Vector4 actual = gray.ToScaledVector4(); + Vector4 actual = pixel.ToScaledVector4(); // Assert float scaledInput = input / 255F; @@ -78,12 +78,11 @@ public void L8_ToScaledVector4(byte input) public void L8_FromVector4(byte luminance) { // Arrange - L8 gray = default; - var vector = new L8(luminance).ToVector4(); + Vector4 vector = new L8(luminance).ToVector4(); // Act - gray.FromVector4(vector); - byte actual = gray.PackedValue; + L8 pixel = L8.FromVector4(vector); + byte actual = pixel.PackedValue; // Assert Assert.Equal(luminance, actual); @@ -94,10 +93,10 @@ public void L8_FromVector4(byte luminance) public void L8_ToVector4(byte input) { // Arrange - var gray = new L8(input); + L8 pixel = new(input); // Act - var actual = gray.ToVector4(); + Vector4 actual = pixel.ToVector4(); // Assert float scaledInput = input / 255F; @@ -112,12 +111,11 @@ public void L8_ToVector4(byte input) public void L8_FromRgba32(byte rgb) { // Arrange - L8 gray = default; byte expected = ColorNumerics.Get8BitBT709Luminance(rgb, rgb, rgb); // Act - gray.FromRgba32(new Rgba32(rgb, rgb, rgb)); - byte actual = gray.PackedValue; + L8 pixel = L8.FromRgba32(new Rgba32(rgb, rgb, rgb)); + byte actual = pixel.PackedValue; // Assert Assert.Equal(expected, actual); @@ -128,11 +126,10 @@ public void L8_FromRgba32(byte rgb) public void L8_ToRgba32(byte luminance) { // Arrange - var gray = new L8(luminance); + L8 pixel = new(luminance); // Act - Rgba32 actual = default; - gray.ToRgba32(ref actual); + Rgba32 actual = pixel.ToRgba32(); // Assert Assert.Equal(luminance, actual.R); @@ -145,11 +142,10 @@ public void L8_ToRgba32(byte luminance) public void L8_FromBgra5551() { // arrange - var grey = default(L8); - byte expected = byte.MaxValue; + const byte expected = byte.MaxValue; // act - grey.FromBgra5551(new Bgra5551(1.0f, 1.0f, 1.0f, 1.0f)); + L8 grey = L8.FromBgra5551(new Bgra5551(1f, 1f, 1f, 1f)); // assert Assert.Equal(expected, grey.PackedValue); @@ -164,13 +160,11 @@ public class Rgba32Compatibility [MemberData(nameof(LuminanceData))] public void L8_FromRgba32_IsInverseOf_ToRgba32(byte luminance) { - var original = new L8(luminance); + L8 original = new(luminance); - Rgba32 rgba = default; - original.ToRgba32(ref rgba); + Rgba32 rgba = original.ToRgba32(); - L8 mirror = default; - mirror.FromRgba32(rgba); + L8 mirror = L8.FromRgba32(rgba); Assert.Equal(original, mirror); } @@ -179,13 +173,10 @@ public void L8_FromRgba32_IsInverseOf_ToRgba32(byte luminance) [MemberData(nameof(LuminanceData))] public void Rgba32_ToL8_IsInverseOf_L8_ToRgba32(byte luminance) { - var original = new L8(luminance); + L8 original = new(luminance); - Rgba32 rgba = default; - original.ToRgba32(ref rgba); - - L8 mirror = default; - mirror.FromRgba32(rgba); + Rgba32 rgba = original.ToRgba32(); + L8 mirror = L8.FromRgba32(rgba); Assert.Equal(original, mirror); } @@ -194,13 +185,12 @@ public void Rgba32_ToL8_IsInverseOf_L8_ToRgba32(byte luminance) [MemberData(nameof(LuminanceData))] public void ToVector4_IsRgba32Compatible(byte luminance) { - var original = new L8(luminance); + L8 original = new(luminance); - Rgba32 rgba = default; - original.ToRgba32(ref rgba); + Rgba32 rgba = original.ToRgba32(); - var l8Vector = original.ToVector4(); - var rgbaVector = original.ToVector4(); + Vector4 l8Vector = original.ToVector4(); + Vector4 rgbaVector = rgba.ToVector4(); Assert.Equal(l8Vector, rgbaVector, new ApproximateFloatComparer(1e-5f)); } @@ -209,15 +199,13 @@ public void ToVector4_IsRgba32Compatible(byte luminance) [MemberData(nameof(LuminanceData))] public void FromVector4_IsRgba32Compatible(byte luminance) { - var original = new L8(luminance); + L8 original = new(luminance); - Rgba32 rgba = default; - original.ToRgba32(ref rgba); + Rgba32 rgba = original.ToRgba32(); - var rgbaVector = original.ToVector4(); + Vector4 rgbaVector = rgba.ToVector4(); - L8 mirror = default; - mirror.FromVector4(rgbaVector); + L8 mirror = L8.FromVector4(rgbaVector); Assert.Equal(original, mirror); } @@ -226,10 +214,9 @@ public void FromVector4_IsRgba32Compatible(byte luminance) [MemberData(nameof(LuminanceData))] public void ToScaledVector4_IsRgba32Compatible(byte luminance) { - var original = new L8(luminance); + L8 original = new(luminance); - Rgba32 rgba = default; - original.ToRgba32(ref rgba); + Rgba32 rgba = original.ToRgba32(); Vector4 l8Vector = original.ToScaledVector4(); Vector4 rgbaVector = original.ToScaledVector4(); @@ -241,17 +228,30 @@ public void ToScaledVector4_IsRgba32Compatible(byte luminance) [MemberData(nameof(LuminanceData))] public void FromScaledVector4_IsRgba32Compatible(byte luminance) { - var original = new L8(luminance); + L8 original = new(luminance); - Rgba32 rgba = default; - original.ToRgba32(ref rgba); + Rgba32 rgba = original.ToRgba32(); - Vector4 rgbaVector = original.ToScaledVector4(); + Vector4 rgbaVector = rgba.ToScaledVector4(); - L8 mirror = default; - mirror.FromScaledVector4(rgbaVector); + L8 mirror = L8.FromScaledVector4(rgbaVector); Assert.Equal(original, mirror); } + + [Fact] + public void L8_PixelInformation() + { + PixelTypeInfo info = L8.GetPixelTypeInfo(); + Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); + Assert.Equal(PixelAlphaRepresentation.None, info.AlphaRepresentation); + Assert.Equal(PixelColorType.Luminance, info.ColorType); + + PixelComponentInfo componentInfo = info.ComponentInfo.Value; + Assert.Equal(1, componentInfo.ComponentCount); + Assert.Equal(0, componentInfo.Padding); + Assert.Equal(8, componentInfo.GetComponentPrecision(0)); + Assert.Equal(8, componentInfo.GetMaximumComponentPrecision()); + } } } diff --git a/tests/ImageSharp.Tests/PixelFormats/La16Tests.cs b/tests/ImageSharp.Tests/PixelFormats/La16Tests.cs index 92b4a4e1a1..f6cbfc4426 100644 --- a/tests/ImageSharp.Tests/PixelFormats/La16Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/La16Tests.cs @@ -2,6 +2,7 @@ // Licensed under the Six Labors Split License. using System.Numerics; +using System.Runtime.CompilerServices; using SixLabors.ImageSharp.PixelFormats; // ReSharper disable InconsistentNaming @@ -24,8 +25,8 @@ public void La16_PackedValue_EqualsPackedInput(byte input, ushort packed) [Fact] public void AreEqual() { - var color1 = new La16(100, 50); - var color2 = new La16(100, 50); + La16 color1 = new(100, 50); + La16 color2 = new(100, 50); Assert.Equal(color1, color2); } @@ -33,8 +34,8 @@ public void AreEqual() [Fact] public void AreNotEqual() { - var color1 = new La16(100, 50); - var color2 = new La16(200, 50); + La16 color1 = new(100, 50); + La16 color2 = new(200, 50); Assert.NotEqual(color1, color2); } @@ -43,12 +44,11 @@ public void AreNotEqual() public void La16_FromScaledVector4() { // Arrange - La16 gray = default; const ushort expected = 32896; Vector4 scaled = new La16(128, 128).ToScaledVector4(); // Act - gray.FromScaledVector4(scaled); + La16 gray = La16.FromScaledVector4(scaled); ushort actual = gray.PackedValue; // Assert @@ -60,7 +60,7 @@ public void La16_FromScaledVector4() public void La16_ToScaledVector4(byte input) { // Arrange - var gray = new La16(input, input); + La16 gray = new(input, input); // Act Vector4 actual = gray.ToScaledVector4(); @@ -78,11 +78,10 @@ public void La16_ToScaledVector4(byte input) public void La16_FromVector4(byte luminance) { // Arrange - La16 gray = default; - var vector = new La16(luminance, luminance).ToVector4(); + Vector4 vector = new La16(luminance, luminance).ToVector4(); // Act - gray.FromVector4(vector); + La16 gray = La16.FromVector4(vector); byte actualL = gray.L; byte actualA = gray.A; @@ -96,10 +95,10 @@ public void La16_FromVector4(byte luminance) public void La16_ToVector4(byte input) { // Arrange - var gray = new La16(input, input); + La16 gray = new(input, input); // Act - var actual = gray.ToVector4(); + Vector4 actual = gray.ToVector4(); // Assert float scaledInput = input / 255F; @@ -114,11 +113,10 @@ public void La16_ToVector4(byte input) public void La16_FromRgba32(byte rgb) { // Arrange - La16 gray = default; byte expected = ColorNumerics.Get8BitBT709Luminance(rgb, rgb, rgb); // Act - gray.FromRgba32(new Rgba32(rgb, rgb, rgb)); + La16 gray = La16.FromRgba32(new Rgba32(rgb, rgb, rgb)); byte actual = gray.L; // Assert @@ -131,11 +129,10 @@ public void La16_FromRgba32(byte rgb) public void La16_ToRgba32(byte luminance) { // Arrange - var gray = new La16(luminance, luminance); + La16 gray = new(luminance, luminance); // Act - Rgba32 actual = default; - gray.ToRgba32(ref actual); + Rgba32 actual = gray.ToRgba32(); // Assert Assert.Equal(luminance, actual.R); @@ -148,11 +145,10 @@ public void La16_ToRgba32(byte luminance) public void La16_FromBgra5551() { // arrange - var grey = default(La16); - byte expected = byte.MaxValue; + const byte expected = byte.MaxValue; // act - grey.FromBgra5551(new Bgra5551(1.0f, 1.0f, 1.0f, 1.0f)); + La16 grey = La16.FromBgra5551(new Bgra5551(1.0f, 1.0f, 1.0f, 1.0f)); // assert Assert.Equal(expected, grey.L); @@ -168,13 +164,11 @@ public class Rgba32Compatibility [MemberData(nameof(LuminanceData))] public void La16_FromRgba32_IsInverseOf_ToRgba32(byte luminance) { - var original = new La16(luminance, luminance); + La16 original = new(luminance, luminance); - Rgba32 rgba = default; - original.ToRgba32(ref rgba); + Rgba32 rgba = original.ToRgba32(); - La16 mirror = default; - mirror.FromRgba32(rgba); + La16 mirror = La16.FromRgba32(rgba); Assert.Equal(original, mirror); } @@ -183,13 +177,11 @@ public void La16_FromRgba32_IsInverseOf_ToRgba32(byte luminance) [MemberData(nameof(LuminanceData))] public void Rgba32_ToLa16_IsInverseOf_La16_ToRgba32(byte luminance) { - var original = new La16(luminance, luminance); + La16 original = new(luminance, luminance); - Rgba32 rgba = default; - original.ToRgba32(ref rgba); + Rgba32 rgba = original.ToRgba32(); - La16 mirror = default; - mirror.FromRgba32(rgba); + La16 mirror = La16.FromRgba32(rgba); Assert.Equal(original, mirror); } @@ -198,13 +190,12 @@ public void Rgba32_ToLa16_IsInverseOf_La16_ToRgba32(byte luminance) [MemberData(nameof(LuminanceData))] public void ToVector4_IsRgba32Compatible(byte luminance) { - var original = new La16(luminance, luminance); + La16 original = new(luminance, luminance); - Rgba32 rgba = default; - original.ToRgba32(ref rgba); + Rgba32 rgba = original.ToRgba32(); - var la16Vector = original.ToVector4(); - var rgbaVector = original.ToVector4(); + Vector4 la16Vector = original.ToVector4(); + Vector4 rgbaVector = rgba.ToVector4(); Assert.Equal(la16Vector, rgbaVector, new ApproximateFloatComparer(1e-5f)); } @@ -213,15 +204,12 @@ public void ToVector4_IsRgba32Compatible(byte luminance) [MemberData(nameof(LuminanceData))] public void FromVector4_IsRgba32Compatible(byte luminance) { - var original = new La16(luminance, luminance); + La16 original = new(luminance, luminance); - Rgba32 rgba = default; - original.ToRgba32(ref rgba); + Rgba32 rgba = original.ToRgba32(); + Vector4 rgbaVector = rgba.ToVector4(); - var rgbaVector = original.ToVector4(); - - La16 mirror = default; - mirror.FromVector4(rgbaVector); + La16 mirror = La16.FromVector4(rgbaVector); Assert.Equal(original, mirror); } @@ -230,13 +218,12 @@ public void FromVector4_IsRgba32Compatible(byte luminance) [MemberData(nameof(LuminanceData))] public void ToScaledVector4_IsRgba32Compatible(byte luminance) { - var original = new La16(luminance, luminance); + La16 original = new(luminance, luminance); - Rgba32 rgba = default; - original.ToRgba32(ref rgba); + Rgba32 rgba = original.ToRgba32(); Vector4 la16Vector = original.ToScaledVector4(); - Vector4 rgbaVector = original.ToScaledVector4(); + Vector4 rgbaVector = rgba.ToScaledVector4(); Assert.Equal(la16Vector, rgbaVector, new ApproximateFloatComparer(1e-5f)); } @@ -245,17 +232,30 @@ public void ToScaledVector4_IsRgba32Compatible(byte luminance) [MemberData(nameof(LuminanceData))] public void FromScaledVector4_IsRgba32Compatible(byte luminance) { - var original = new La16(luminance, luminance); - - Rgba32 rgba = default; - original.ToRgba32(ref rgba); + La16 original = new(luminance, luminance); - Vector4 rgbaVector = original.ToScaledVector4(); + Rgba32 rgba = original.ToRgba32(); + Vector4 rgbaVector = rgba.ToScaledVector4(); - La16 mirror = default; - mirror.FromScaledVector4(rgbaVector); + La16 mirror = La16.FromScaledVector4(rgbaVector); Assert.Equal(original, mirror); } + + [Fact] + public void La16_PixelInformation() + { + PixelTypeInfo info = La16.GetPixelTypeInfo(); + Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); + Assert.Equal(PixelAlphaRepresentation.Unassociated, info.AlphaRepresentation); + Assert.Equal(PixelColorType.Luminance | PixelColorType.Alpha, info.ColorType); + + PixelComponentInfo componentInfo = info.ComponentInfo.Value; + Assert.Equal(2, componentInfo.ComponentCount); + Assert.Equal(0, componentInfo.Padding); + Assert.Equal(8, componentInfo.GetComponentPrecision(0)); + Assert.Equal(8, componentInfo.GetComponentPrecision(1)); + Assert.Equal(8, componentInfo.GetMaximumComponentPrecision()); + } } } diff --git a/tests/ImageSharp.Tests/PixelFormats/La32Tests.cs b/tests/ImageSharp.Tests/PixelFormats/La32Tests.cs index d333818c78..fd5556d3bc 100644 --- a/tests/ImageSharp.Tests/PixelFormats/La32Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/La32Tests.cs @@ -2,6 +2,7 @@ // Licensed under the Six Labors Split License. using System.Numerics; +using System.Runtime.CompilerServices; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Tests.PixelFormats; @@ -12,8 +13,8 @@ public class La32Tests [Fact] public void AreEqual() { - var color1 = new La32(3000, 100); - var color2 = new La32(3000, 100); + La32 color1 = new(3000, 100); + La32 color2 = new(3000, 100); Assert.Equal(color1, color2); } @@ -21,8 +22,8 @@ public void AreEqual() [Fact] public void AreNotEqual() { - var color1 = new La32(12345, 100); - var color2 = new La32(54321, 100); + La32 color1 = new(12345, 100); + La32 color2 = new(54321, 100); Assert.NotEqual(color1, color2); } @@ -39,14 +40,13 @@ public void La32_PackedValue_EqualsInput(ushort input, uint packed) public void La32_FromScaledVector4() { // Arrange - La32 gray = default; const ushort expected = 32767; Vector4 scaled = new La32(expected, expected).ToScaledVector4(); // Act - gray.FromScaledVector4(scaled); - ushort actual = gray.L; - ushort actualA = gray.A; + La32 pixel = La32.FromScaledVector4(scaled); + ushort actual = pixel.L; + ushort actualA = pixel.A; // Assert Assert.Equal(expected, actual); @@ -60,10 +60,10 @@ public void La32_FromScaledVector4() public void La32_ToScaledVector4(ushort input) { // Arrange - var gray = new La32(input, input); + La32 pixel = new(input, input); // Act - Vector4 actual = gray.ToScaledVector4(); + Vector4 actual = pixel.ToScaledVector4(); // Assert float vectorInput = input / 65535F; @@ -77,14 +77,13 @@ public void La32_ToScaledVector4(ushort input) public void La32_FromVector4() { // Arrange - La32 gray = default; const ushort expected = 32767; - var vector = new La32(expected, expected).ToVector4(); + Vector4 vector = new La32(expected, expected).ToVector4(); // Act - gray.FromVector4(vector); - ushort actual = gray.L; - ushort actualA = gray.A; + La32 pixel = La32.FromVector4(vector); + ushort actual = pixel.L; + ushort actualA = pixel.A; // Assert Assert.Equal(expected, actual); @@ -98,10 +97,10 @@ public void La32_FromVector4() public void La32_ToVector4(ushort input) { // Arrange - var gray = new La32(input, input); + La32 pixel = new(input, input); // Act - var actual = gray.ToVector4(); + Vector4 actual = pixel.ToVector4(); // Assert float vectorInput = input / 65535F; @@ -115,18 +114,17 @@ public void La32_ToVector4(ushort input) public void La32_FromRgba32() { // Arrange - La32 gray = default; const byte rgb = 128; - ushort scaledRgb = ColorNumerics.UpscaleFrom8BitTo16Bit(rgb); + ushort scaledRgb = ColorNumerics.From8BitTo16Bit(rgb); ushort expected = ColorNumerics.Get16BitBT709Luminance(scaledRgb, scaledRgb, scaledRgb); // Act - gray.FromRgba32(new Rgba32(rgb, rgb, rgb)); - ushort actual = gray.L; + La32 pixel = La32.FromRgba32(new Rgba32(rgb, rgb, rgb)); + ushort actual = pixel.L; // Assert Assert.Equal(expected, actual); - Assert.Equal(ushort.MaxValue, gray.A); + Assert.Equal(ushort.MaxValue, pixel.A); } [Theory] @@ -136,12 +134,11 @@ public void La32_FromRgba32() public void La32_ToRgba32(ushort input) { // Arrange - ushort expected = ColorNumerics.DownScaleFrom16BitTo8Bit(input); - var gray = new La32(input, ushort.MaxValue); + ushort expected = ColorNumerics.From16BitTo8Bit(input); + La32 pixel = new(input, ushort.MaxValue); // Act - Rgba32 actual = default; - gray.ToRgba32(ref actual); + Rgba32 actual = pixel.ToRgba32(); // Assert Assert.Equal(expected, actual.R); @@ -154,14 +151,29 @@ public void La32_ToRgba32(ushort input) public void La32_FromBgra5551() { // arrange - var gray = default(La32); - ushort expected = ushort.MaxValue; + const ushort expected = ushort.MaxValue; // act - gray.FromBgra5551(new Bgra5551(1.0f, 1.0f, 1.0f, 1.0f)); + La32 pixel = La32.FromBgra5551(new Bgra5551(1f, 1f, 1f, 1f)); // assert - Assert.Equal(expected, gray.L); - Assert.Equal(expected, gray.A); + Assert.Equal(expected, pixel.L); + Assert.Equal(expected, pixel.A); + } + + [Fact] + public void La32_PixelInformation() + { + PixelTypeInfo info = La32.GetPixelTypeInfo(); + Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); + Assert.Equal(PixelAlphaRepresentation.Unassociated, info.AlphaRepresentation); + Assert.Equal(PixelColorType.Luminance | PixelColorType.Alpha, info.ColorType); + + PixelComponentInfo componentInfo = info.ComponentInfo.Value; + Assert.Equal(2, componentInfo.ComponentCount); + Assert.Equal(0, componentInfo.Padding); + Assert.Equal(16, componentInfo.GetComponentPrecision(0)); + Assert.Equal(16, componentInfo.GetComponentPrecision(1)); + Assert.Equal(16, componentInfo.GetMaximumComponentPrecision()); } } diff --git a/tests/ImageSharp.Tests/PixelFormats/NormalizedByte2Tests.cs b/tests/ImageSharp.Tests/PixelFormats/NormalizedByte2Tests.cs index 14c590d0b5..ffbddb1398 100644 --- a/tests/ImageSharp.Tests/PixelFormats/NormalizedByte2Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/NormalizedByte2Tests.cs @@ -2,6 +2,7 @@ // Licensed under the Six Labors Split License. using System.Numerics; +using System.Runtime.CompilerServices; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Tests.PixelFormats; @@ -39,10 +40,10 @@ public void NormalizedByte2_ToVector4() public void NormalizedByte2_ToScaledVector4() { // arrange - var byte2 = new NormalizedByte2(-Vector2.One); + NormalizedByte2 pixel = new(-Vector2.One); // act - Vector4 actual = byte2.ToScaledVector4(); + Vector4 actual = pixel.ToScaledVector4(); // assert Assert.Equal(0, actual.X); @@ -56,12 +57,11 @@ public void NormalizedByte2_FromScaledVector4() { // arrange Vector4 scaled = new NormalizedByte2(-Vector2.One).ToScaledVector4(); - var byte2 = default(NormalizedByte2); - uint expected = 0x8181; + const uint expected = 0x8181; // act - byte2.FromScaledVector4(scaled); - uint actual = byte2.PackedValue; + NormalizedByte2 pixel = NormalizedByte2.FromScaledVector4(scaled); + uint actual = pixel.PackedValue; // assert Assert.Equal(expected, actual); @@ -71,13 +71,28 @@ public void NormalizedByte2_FromScaledVector4() public void NormalizedByte2_FromBgra5551() { // arrange - var normalizedByte2 = default(NormalizedByte2); - var expected = new Vector4(1, 1, 0, 1); + Vector4 expected = new(1, 1, 0, 1); // act - normalizedByte2.FromBgra5551(new Bgra5551(1.0f, 1.0f, 1.0f, 1.0f)); + NormalizedByte2 pixel = NormalizedByte2.FromBgra5551(new Bgra5551(1f, 1f, 1f, 1f)); // assert - Assert.Equal(expected, normalizedByte2.ToVector4()); + Assert.Equal(expected, pixel.ToVector4()); + } + + [Fact] + public void NormalizedByte2_PixelInformation() + { + PixelTypeInfo info = NormalizedByte2.GetPixelTypeInfo(); + Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); + Assert.Equal(PixelAlphaRepresentation.None, info.AlphaRepresentation); + Assert.Equal(PixelColorType.Red | PixelColorType.Green, info.ColorType); + + PixelComponentInfo componentInfo = info.ComponentInfo.Value; + Assert.Equal(2, componentInfo.ComponentCount); + Assert.Equal(0, componentInfo.Padding); + Assert.Equal(8, componentInfo.GetComponentPrecision(0)); + Assert.Equal(8, componentInfo.GetComponentPrecision(1)); + Assert.Equal(8, componentInfo.GetMaximumComponentPrecision()); } } diff --git a/tests/ImageSharp.Tests/PixelFormats/NormalizedByte4Tests.cs b/tests/ImageSharp.Tests/PixelFormats/NormalizedByte4Tests.cs index ca73a6c1f4..5a025f6c4e 100644 --- a/tests/ImageSharp.Tests/PixelFormats/NormalizedByte4Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/NormalizedByte4Tests.cs @@ -2,6 +2,7 @@ // Licensed under the Six Labors Split License. using System.Numerics; +using System.Runtime.CompilerServices; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Tests.PixelFormats; @@ -15,10 +16,10 @@ public class NormalizedByte4Tests [Fact] public void AreEqual() { - var color1 = new NormalizedByte4(0.0f, 0.0f, 0.0f, 0.0f); - var color2 = new NormalizedByte4(new Vector4(0.0f)); - var color3 = new NormalizedByte4(new Vector4(1.0f, 0.0f, 1.0f, 1.0f)); - var color4 = new NormalizedByte4(1.0f, 0.0f, 1.0f, 1.0f); + NormalizedByte4 color1 = new(0.0f, 0.0f, 0.0f, 0.0f); + NormalizedByte4 color2 = new(new Vector4(0.0f)); + NormalizedByte4 color3 = new(new Vector4(1f, 0.0f, 1f, 1f)); + NormalizedByte4 color4 = new(1f, 0.0f, 1f, 1f); Assert.Equal(color1, color2); Assert.Equal(color3, color4); @@ -30,10 +31,10 @@ public void AreEqual() [Fact] public void AreNotEqual() { - var color1 = new NormalizedByte4(0.0f, 0.0f, 0.0f, 0.0f); - var color2 = new NormalizedByte4(new Vector4(1.0f)); - var color3 = new NormalizedByte4(new Vector4(1.0f, 0.0f, 0.0f, 1.0f)); - var color4 = new NormalizedByte4(1.0f, 1.0f, 0.0f, 1.0f); + NormalizedByte4 color1 = new(0.0f, 0.0f, 0.0f, 0.0f); + NormalizedByte4 color2 = new(new Vector4(1f)); + NormalizedByte4 color3 = new(new Vector4(1f, 0.0f, 0.0f, 1f)); + NormalizedByte4 color4 = new(1f, 1f, 0.0f, 1f); Assert.NotEqual(color1, color2); Assert.NotEqual(color3, color4); @@ -63,7 +64,7 @@ public void NormalizedByte4_ToVector4() public void NormalizedByte4_ToScaledVector4() { // arrange - var short4 = new NormalizedByte4(-Vector4.One); + NormalizedByte4 short4 = new(-Vector4.One); // act Vector4 actual = short4.ToScaledVector4(); @@ -79,12 +80,11 @@ public void NormalizedByte4_ToScaledVector4() public void NormalizedByte4_FromScaledVector4() { // arrange - var pixel = default(NormalizedByte4); Vector4 scaled = new NormalizedByte4(-Vector4.One).ToScaledVector4(); - uint expected = 0x81818181; + const uint expected = 0x81818181; // act - pixel.FromScaledVector4(scaled); + NormalizedByte4 pixel = NormalizedByte4.FromScaledVector4(scaled); uint actual = pixel.PackedValue; // assert @@ -95,139 +95,147 @@ public void NormalizedByte4_FromScaledVector4() public void NormalizedByte4_FromArgb32() { // arrange - var byte4 = default(NormalizedByte4); Vector4 expected = Vector4.One; // act - byte4.FromArgb32(new Argb32(255, 255, 255, 255)); + NormalizedByte4 pixel = NormalizedByte4.FromArgb32(new Argb32(255, 255, 255, 255)); // assert - Assert.Equal(expected, byte4.ToScaledVector4()); + Assert.Equal(expected, pixel.ToScaledVector4()); } [Fact] public void NormalizedByte4_FromBgr24() { // arrange - var byte4 = default(NormalizedByte4); Vector4 expected = Vector4.One; // act - byte4.FromBgr24(new Bgr24(byte.MaxValue, byte.MaxValue, byte.MaxValue)); + NormalizedByte4 pixel = NormalizedByte4.FromBgr24(new Bgr24(byte.MaxValue, byte.MaxValue, byte.MaxValue)); // assert - Assert.Equal(expected, byte4.ToScaledVector4()); + Assert.Equal(expected, pixel.ToScaledVector4()); } [Fact] public void NormalizedByte4_FromGrey8() { // arrange - var byte4 = default(NormalizedByte4); Vector4 expected = Vector4.One; // act - byte4.FromL8(new L8(byte.MaxValue)); + NormalizedByte4 pixel = NormalizedByte4.FromL8(new L8(byte.MaxValue)); // assert - Assert.Equal(expected, byte4.ToScaledVector4()); + Assert.Equal(expected, pixel.ToScaledVector4()); } [Fact] public void NormalizedByte4_FromGrey16() { // arrange - var byte4 = default(NormalizedByte4); Vector4 expected = Vector4.One; // act - byte4.FromL16(new L16(ushort.MaxValue)); + NormalizedByte4 pixel = NormalizedByte4.FromL16(new L16(ushort.MaxValue)); // assert - Assert.Equal(expected, byte4.ToScaledVector4()); + Assert.Equal(expected, pixel.ToScaledVector4()); } [Fact] public void NormalizedByte4_FromRgb24() { // arrange - var byte4 = default(NormalizedByte4); Vector4 expected = Vector4.One; // act - byte4.FromRgb24(new Rgb24(byte.MaxValue, byte.MaxValue, byte.MaxValue)); + NormalizedByte4 pixel = NormalizedByte4.FromRgb24(new Rgb24(byte.MaxValue, byte.MaxValue, byte.MaxValue)); // assert - Assert.Equal(expected, byte4.ToScaledVector4()); + Assert.Equal(expected, pixel.ToScaledVector4()); } [Fact] public void NormalizedByte4_FromRgba32() { // arrange - var byte4 = default(NormalizedByte4); Vector4 expected = Vector4.One; // act - byte4.FromRgba32(new Rgba32(255, 255, 255, 255)); + NormalizedByte4 pixel = NormalizedByte4.FromRgba32(new Rgba32(255, 255, 255, 255)); // assert - Assert.Equal(expected, byte4.ToScaledVector4()); + Assert.Equal(expected, pixel.ToScaledVector4()); } [Fact] public void NormalizedByte4_FromBgra5551() { // arrange - var normalizedByte4 = default(NormalizedByte4); Vector4 expected = Vector4.One; // act - normalizedByte4.FromBgra5551(new Bgra5551(1.0f, 1.0f, 1.0f, 1.0f)); + NormalizedByte4 pixel = NormalizedByte4.FromBgra5551(new Bgra5551(1f, 1f, 1f, 1f)); // assert - Assert.Equal(expected, normalizedByte4.ToVector4()); + Assert.Equal(expected, pixel.ToVector4()); } [Fact] public void NormalizedByte4_FromRgb48() { // arrange - var byte4 = default(NormalizedByte4); Vector4 expected = Vector4.One; // act - byte4.FromRgb48(new Rgb48(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue)); + NormalizedByte4 pixel = NormalizedByte4.FromRgb48(new Rgb48(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue)); // assert - Assert.Equal(expected, byte4.ToScaledVector4()); + Assert.Equal(expected, pixel.ToScaledVector4()); } [Fact] public void NormalizedByte4_FromRgba64() { // arrange - var byte4 = default(NormalizedByte4); Vector4 expected = Vector4.One; // act - byte4.FromRgba64(new Rgba64(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue, ushort.MaxValue)); + NormalizedByte4 pixel = NormalizedByte4.FromRgba64(new Rgba64(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue, ushort.MaxValue)); // assert - Assert.Equal(expected, byte4.ToScaledVector4()); + Assert.Equal(expected, pixel.ToScaledVector4()); } [Fact] public void NormalizedByte4_ToRgba32() { // arrange - var byte4 = new NormalizedByte4(byte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue); - var expected = new Rgba32(Vector4.One); - var actual = default(Rgba32); + NormalizedByte4 pixel = new(byte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue); + Rgba32 expected = new(Vector4.One); // act - byte4.ToRgba32(ref actual); + Rgba32 actual = pixel.ToRgba32(); Assert.Equal(expected, actual); } + + [Fact] + public void NormalizedByte4_PixelInformation() + { + PixelTypeInfo info = NormalizedByte4.GetPixelTypeInfo(); + Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); + Assert.Equal(PixelAlphaRepresentation.Unassociated, info.AlphaRepresentation); + Assert.Equal(PixelColorType.RGB | PixelColorType.Alpha, info.ColorType); + + PixelComponentInfo componentInfo = info.ComponentInfo.Value; + Assert.Equal(4, componentInfo.ComponentCount); + Assert.Equal(0, componentInfo.Padding); + Assert.Equal(8, componentInfo.GetComponentPrecision(0)); + Assert.Equal(8, componentInfo.GetComponentPrecision(1)); + Assert.Equal(8, componentInfo.GetComponentPrecision(2)); + Assert.Equal(8, componentInfo.GetComponentPrecision(3)); + Assert.Equal(8, componentInfo.GetMaximumComponentPrecision()); + } } diff --git a/tests/ImageSharp.Tests/PixelFormats/NormalizedShort2Tests.cs b/tests/ImageSharp.Tests/PixelFormats/NormalizedShort2Tests.cs index 70bfa1be71..be7b390527 100644 --- a/tests/ImageSharp.Tests/PixelFormats/NormalizedShort2Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/NormalizedShort2Tests.cs @@ -2,6 +2,7 @@ // Licensed under the Six Labors Split License. using System.Numerics; +using System.Runtime.CompilerServices; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Tests.PixelFormats; @@ -43,7 +44,7 @@ public void NormalizedShort2_ToVector4() public void NormalizedShort2_ToScaledVector4() { // arrange - var short2 = new NormalizedShort2(-Vector2.One); + NormalizedShort2 short2 = new(-Vector2.One); // act Vector4 actual = short2.ToScaledVector4(); @@ -60,11 +61,10 @@ public void NormalizedShort2_FromScaledVector4() { // arrange Vector4 scaled = new NormalizedShort2(-Vector2.One).ToScaledVector4(); - var short2 = default(NormalizedShort2); - uint expected = 0x80018001; + const uint expected = 0x80018001; // act - short2.FromScaledVector4(scaled); + NormalizedShort2 short2 = NormalizedShort2.FromScaledVector4(scaled); uint actual = short2.PackedValue; // assert @@ -75,13 +75,28 @@ public void NormalizedShort2_FromScaledVector4() public void NormalizedShort2_FromBgra5551() { // arrange - var normalizedShort2 = default(NormalizedShort2); - var expected = new Vector4(1, 1, 0, 1); + Vector4 expected = new(1, 1, 0, 1); // act - normalizedShort2.FromBgra5551(new Bgra5551(1.0f, 1.0f, 1.0f, 1.0f)); + NormalizedShort2 normalizedShort2 = NormalizedShort2.FromBgra5551(new Bgra5551(1f, 1f, 1f, 1f)); // assert Assert.Equal(expected, normalizedShort2.ToVector4()); } + + [Fact] + public void NormalizedShort2_PixelInformation() + { + PixelTypeInfo info = NormalizedShort2.GetPixelTypeInfo(); + Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); + Assert.Equal(PixelAlphaRepresentation.None, info.AlphaRepresentation); + Assert.Equal(PixelColorType.Red | PixelColorType.Green, info.ColorType); + + PixelComponentInfo componentInfo = info.ComponentInfo.Value; + Assert.Equal(2, componentInfo.ComponentCount); + Assert.Equal(0, componentInfo.Padding); + Assert.Equal(16, componentInfo.GetComponentPrecision(0)); + Assert.Equal(16, componentInfo.GetComponentPrecision(1)); + Assert.Equal(16, componentInfo.GetMaximumComponentPrecision()); + } } diff --git a/tests/ImageSharp.Tests/PixelFormats/NormalizedShort4Tests.cs b/tests/ImageSharp.Tests/PixelFormats/NormalizedShort4Tests.cs index 997c6df82b..281ae7ee52 100644 --- a/tests/ImageSharp.Tests/PixelFormats/NormalizedShort4Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/NormalizedShort4Tests.cs @@ -2,6 +2,7 @@ // Licensed under the Six Labors Split License. using System.Numerics; +using System.Runtime.CompilerServices; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Tests.PixelFormats; @@ -15,10 +16,10 @@ public class NormalizedShort4Tests [Fact] public void AreEqual() { - var color1 = new NormalizedShort4(0.0f, 0.0f, 0.0f, 0.0f); - var color2 = new NormalizedShort4(new Vector4(0.0f)); - var color3 = new NormalizedShort4(new Vector4(1.0f, 0.0f, 1.0f, 1.0f)); - var color4 = new NormalizedShort4(1.0f, 0.0f, 1.0f, 1.0f); + NormalizedShort4 color1 = new(0.0f, 0.0f, 0.0f, 0.0f); + NormalizedShort4 color2 = new(new Vector4(0.0f)); + NormalizedShort4 color3 = new(new Vector4(1f, 0.0f, 1f, 1f)); + NormalizedShort4 color4 = new(1f, 0.0f, 1f, 1f); Assert.Equal(color1, color2); Assert.Equal(color3, color4); @@ -30,10 +31,10 @@ public void AreEqual() [Fact] public void AreNotEqual() { - var color1 = new NormalizedShort4(0.0f, 0.0f, 0.0f, 0.0f); - var color2 = new NormalizedShort4(new Vector4(1.0f)); - var color3 = new NormalizedShort4(new Vector4(1.0f, 0.0f, 0.0f, 1.0f)); - var color4 = new NormalizedShort4(1.0f, 1.0f, 0.0f, 1.0f); + NormalizedShort4 color1 = new(0.0f, 0.0f, 0.0f, 0.0f); + NormalizedShort4 color2 = new(new Vector4(1f)); + NormalizedShort4 color3 = new(new Vector4(1f, 0.0f, 0.0f, 1f)); + NormalizedShort4 color4 = new(1f, 1f, 0.0f, 1f); Assert.NotEqual(color1, color2); Assert.NotEqual(color3, color4); @@ -64,7 +65,7 @@ public void NormalizedShort4_ToVector4() public void NormalizedShort4_ToScaledVector4() { // arrange - var short4 = new NormalizedShort4(Vector4.One); + NormalizedShort4 short4 = new(Vector4.One); // act Vector4 actual = short4.ToScaledVector4(); @@ -80,12 +81,11 @@ public void NormalizedShort4_ToScaledVector4() public void NormalizedShort4_FromScaledVector4() { // arrange - var pixel = default(NormalizedShort4); Vector4 scaled = new NormalizedShort4(Vector4.One).ToScaledVector4(); - ulong expected = 0x7FFF7FFF7FFF7FFF; + const ulong expected = 0x7FFF7FFF7FFF7FFF; // act - pixel.FromScaledVector4(scaled); + NormalizedShort4 pixel = NormalizedShort4.FromScaledVector4(scaled); ulong actual = pixel.PackedValue; // assert @@ -96,124 +96,115 @@ public void NormalizedShort4_FromScaledVector4() public void NormalizedShort4_FromArgb32() { // arrange - var byte4 = default(NormalizedShort4); Vector4 expected = Vector4.One; // act - byte4.FromArgb32(new Argb32(255, 255, 255, 255)); + NormalizedShort4 pixel = NormalizedShort4.FromArgb32(new Argb32(255, 255, 255, 255)); // assert - Assert.Equal(expected, byte4.ToScaledVector4()); + Assert.Equal(expected, pixel.ToScaledVector4()); } [Fact] public void NormalizedShort4_FromBgr24() { // arrange - var byte4 = default(NormalizedShort4); Vector4 expected = Vector4.One; // act - byte4.FromBgr24(new Bgr24(byte.MaxValue, byte.MaxValue, byte.MaxValue)); + NormalizedShort4 pixel = NormalizedShort4.FromBgr24(new Bgr24(byte.MaxValue, byte.MaxValue, byte.MaxValue)); // assert - Assert.Equal(expected, byte4.ToScaledVector4()); + Assert.Equal(expected, pixel.ToScaledVector4()); } [Fact] public void NormalizedShort4_FromGrey8() { // arrange - var byte4 = default(NormalizedShort4); Vector4 expected = Vector4.One; // act - byte4.FromL8(new L8(byte.MaxValue)); + NormalizedShort4 pixel = NormalizedShort4.FromL8(new L8(byte.MaxValue)); // assert - Assert.Equal(expected, byte4.ToScaledVector4()); + Assert.Equal(expected, pixel.ToScaledVector4()); } [Fact] public void NormalizedShort4_FromGrey16() { // arrange - var byte4 = default(NormalizedShort4); Vector4 expected = Vector4.One; // act - byte4.FromL16(new L16(ushort.MaxValue)); + NormalizedShort4 pixel = NormalizedShort4.FromL16(new L16(ushort.MaxValue)); // assert - Assert.Equal(expected, byte4.ToScaledVector4()); + Assert.Equal(expected, pixel.ToScaledVector4()); } [Fact] public void NormalizedShort4_FromRgb24() { // arrange - var byte4 = default(NormalizedShort4); Vector4 expected = Vector4.One; // act - byte4.FromRgb24(new Rgb24(byte.MaxValue, byte.MaxValue, byte.MaxValue)); + NormalizedShort4 pixel = NormalizedShort4.FromRgb24(new Rgb24(byte.MaxValue, byte.MaxValue, byte.MaxValue)); // assert - Assert.Equal(expected, byte4.ToScaledVector4()); + Assert.Equal(expected, pixel.ToScaledVector4()); } [Fact] public void NormalizedShort4_FromRgba32() { // arrange - var byte4 = default(NormalizedShort4); Vector4 expected = Vector4.One; // act - byte4.FromRgba32(new Rgba32(255, 255, 255, 255)); + NormalizedShort4 pixel = NormalizedShort4.FromRgba32(new Rgba32(255, 255, 255, 255)); // assert - Assert.Equal(expected, byte4.ToScaledVector4()); + Assert.Equal(expected, pixel.ToScaledVector4()); } [Fact] public void NormalizedShort4_FromRgb48() { // arrange - var byte4 = default(NormalizedShort4); Vector4 expected = Vector4.One; // act - byte4.FromRgb48(new Rgb48(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue)); + NormalizedShort4 pixel = NormalizedShort4.FromRgb48(new Rgb48(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue)); // assert - Assert.Equal(expected, byte4.ToScaledVector4()); + Assert.Equal(expected, pixel.ToScaledVector4()); } [Fact] public void NormalizedShort4_FromRgba64() { // arrange - var byte4 = default(NormalizedShort4); Vector4 expected = Vector4.One; // act - byte4.FromRgba64(new Rgba64(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue, ushort.MaxValue)); + NormalizedShort4 pixel = NormalizedShort4.FromRgba64(new Rgba64(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue, ushort.MaxValue)); // assert - Assert.Equal(expected, byte4.ToScaledVector4()); + Assert.Equal(expected, pixel.ToScaledVector4()); } [Fact] public void NormalizedShort4_ToRgba32() { // arrange - var byte4 = new NormalizedShort4(byte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue); - var expected = new Rgba32(Vector4.One); - var actual = default(Rgba32); + NormalizedShort4 pixel = new(byte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue); + Rgba32 expected = new(Vector4.One); // act - byte4.ToRgba32(ref actual); + Rgba32 actual = pixel.ToRgba32(); Assert.Equal(expected, actual); } @@ -222,13 +213,30 @@ public void NormalizedShort4_ToRgba32() public void NormalizedShort4_FromBgra5551() { // arrange - var normalizedShort4 = default(NormalizedShort4); Vector4 expected = Vector4.One; // act - normalizedShort4.FromBgra5551(new Bgra5551(1.0f, 1.0f, 1.0f, 1.0f)); + NormalizedShort4 normalizedShort4 = NormalizedShort4.FromBgra5551(new Bgra5551(1f, 1f, 1f, 1f)); // assert Assert.Equal(expected, normalizedShort4.ToVector4()); } + + [Fact] + public void NormalizedShort4_PixelInformation() + { + PixelTypeInfo info = NormalizedShort4.GetPixelTypeInfo(); + Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); + Assert.Equal(PixelAlphaRepresentation.Unassociated, info.AlphaRepresentation); + Assert.Equal(PixelColorType.RGB | PixelColorType.Alpha, info.ColorType); + + PixelComponentInfo componentInfo = info.ComponentInfo.Value; + Assert.Equal(4, componentInfo.ComponentCount); + Assert.Equal(0, componentInfo.Padding); + Assert.Equal(16, componentInfo.GetComponentPrecision(0)); + Assert.Equal(16, componentInfo.GetComponentPrecision(1)); + Assert.Equal(16, componentInfo.GetComponentPrecision(2)); + Assert.Equal(16, componentInfo.GetComponentPrecision(3)); + Assert.Equal(16, componentInfo.GetMaximumComponentPrecision()); + } } diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelBlenderTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelBlenderTests.cs index 68cdf2d633..924e94d929 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelBlenderTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelBlenderTests.cs @@ -43,15 +43,15 @@ public void ReturnsCorrectBlender(TestPixel pixel, Type type, Pi public static TheoryData ColorBlendingExpectedResults = new() { - { Color.MistyRose, Color.MidnightBlue, 1, PixelColorBlendingMode.Normal, Color.MidnightBlue }, - { Color.MistyRose, Color.MidnightBlue, 1, PixelColorBlendingMode.Screen, new Rgba32(0xFFEEE7FF) }, - { Color.MistyRose, Color.MidnightBlue, 1, PixelColorBlendingMode.HardLight, new Rgba32(0xFFC62D32) }, - { Color.MistyRose, Color.MidnightBlue, 1, PixelColorBlendingMode.Overlay, new Rgba32(0xFFDDCEFF) }, - { Color.MistyRose, Color.MidnightBlue, 1, PixelColorBlendingMode.Darken, new Rgba32(0xFF701919) }, - { Color.MistyRose, Color.MidnightBlue, 1, PixelColorBlendingMode.Lighten, new Rgba32(0xFFE1E4FF) }, - { Color.MistyRose, Color.MidnightBlue, 1, PixelColorBlendingMode.Add, new Rgba32(0xFFFFFDFF) }, - { Color.MistyRose, Color.MidnightBlue, 1, PixelColorBlendingMode.Subtract, new Rgba32(0xFF71CBE6) }, - { Color.MistyRose, Color.MidnightBlue, 1, PixelColorBlendingMode.Multiply, new Rgba32(0xFF631619) }, + { Color.MistyRose.ToPixel(), Color.MidnightBlue.ToPixel(), 1, PixelColorBlendingMode.Normal, Color.MidnightBlue.ToPixel() }, + { Color.MistyRose.ToPixel(), Color.MidnightBlue.ToPixel(), 1, PixelColorBlendingMode.Screen, new Rgba32(0xFFEEE7FF) }, + { Color.MistyRose.ToPixel(), Color.MidnightBlue.ToPixel(), 1, PixelColorBlendingMode.HardLight, new Rgba32(0xFFC62D32) }, + { Color.MistyRose.ToPixel(), Color.MidnightBlue.ToPixel(), 1, PixelColorBlendingMode.Overlay, new Rgba32(0xFFDDCEFF) }, + { Color.MistyRose.ToPixel(), Color.MidnightBlue.ToPixel(), 1, PixelColorBlendingMode.Darken, new Rgba32(0xFF701919) }, + { Color.MistyRose.ToPixel(), Color.MidnightBlue.ToPixel(), 1, PixelColorBlendingMode.Lighten, new Rgba32(0xFFE1E4FF) }, + { Color.MistyRose.ToPixel(), Color.MidnightBlue.ToPixel(), 1, PixelColorBlendingMode.Add, new Rgba32(0xFFFFFDFF) }, + { Color.MistyRose.ToPixel(), Color.MidnightBlue.ToPixel(), 1, PixelColorBlendingMode.Subtract, new Rgba32(0xFF71CBE6) }, + { Color.MistyRose.ToPixel(), Color.MidnightBlue.ToPixel(), 1, PixelColorBlendingMode.Multiply, new Rgba32(0xFF631619) }, }; [Theory] @@ -67,18 +67,18 @@ public void TestColorBlendingModes(Rgba32 backdrop, Rgba32 source, float opacity public static TheoryData AlphaCompositionExpectedResults = new() { - { Color.MistyRose, Color.MidnightBlue, 1, PixelAlphaCompositionMode.Clear, new Rgba32(0) }, - { Color.MistyRose, Color.MidnightBlue, 1, PixelAlphaCompositionMode.Xor, new Rgba32(0) }, - { Color.MistyRose, Color.MidnightBlue, 1, PixelAlphaCompositionMode.Dest, Color.MistyRose }, - { Color.MistyRose, Color.MidnightBlue, 1, PixelAlphaCompositionMode.DestAtop, Color.MistyRose }, - { Color.MistyRose, Color.MidnightBlue, 1, PixelAlphaCompositionMode.DestIn, Color.MistyRose }, - { Color.MistyRose, Color.MidnightBlue, 1, PixelAlphaCompositionMode.DestOut, new Rgba32(0) }, - { Color.MistyRose, Color.MidnightBlue, 1, PixelAlphaCompositionMode.DestOver, Color.MistyRose }, - { Color.MistyRose, Color.MidnightBlue, 1, PixelAlphaCompositionMode.Src, Color.MidnightBlue }, - { Color.MistyRose, Color.MidnightBlue, 1, PixelAlphaCompositionMode.SrcAtop, Color.MidnightBlue }, - { Color.MistyRose, Color.MidnightBlue, 1, PixelAlphaCompositionMode.SrcIn, Color.MidnightBlue }, - { Color.MistyRose, Color.MidnightBlue, 1, PixelAlphaCompositionMode.SrcOut, new Rgba32(0) }, - { Color.MistyRose, Color.MidnightBlue, 1, PixelAlphaCompositionMode.SrcOver, Color.MidnightBlue }, + { Color.MistyRose.ToPixel(), Color.MidnightBlue.ToPixel(), 1, PixelAlphaCompositionMode.Clear, new Rgba32(0) }, + { Color.MistyRose.ToPixel(), Color.MidnightBlue.ToPixel(), 1, PixelAlphaCompositionMode.Xor, new Rgba32(0) }, + { Color.MistyRose.ToPixel(), Color.MidnightBlue.ToPixel(), 1, PixelAlphaCompositionMode.Dest, Color.MistyRose.ToPixel() }, + { Color.MistyRose.ToPixel(), Color.MidnightBlue.ToPixel(), 1, PixelAlphaCompositionMode.DestAtop, Color.MistyRose.ToPixel() }, + { Color.MistyRose.ToPixel(), Color.MidnightBlue.ToPixel(), 1, PixelAlphaCompositionMode.DestIn, Color.MistyRose.ToPixel() }, + { Color.MistyRose.ToPixel(), Color.MidnightBlue.ToPixel(), 1, PixelAlphaCompositionMode.DestOut, new Rgba32(0) }, + { Color.MistyRose.ToPixel(), Color.MidnightBlue.ToPixel(), 1, PixelAlphaCompositionMode.DestOver, Color.MistyRose.ToPixel() }, + { Color.MistyRose.ToPixel(), Color.MidnightBlue.ToPixel(), 1, PixelAlphaCompositionMode.Src, Color.MidnightBlue.ToPixel() }, + { Color.MistyRose.ToPixel(), Color.MidnightBlue.ToPixel(), 1, PixelAlphaCompositionMode.SrcAtop, Color.MidnightBlue.ToPixel() }, + { Color.MistyRose.ToPixel(), Color.MidnightBlue.ToPixel(), 1, PixelAlphaCompositionMode.SrcIn, Color.MidnightBlue.ToPixel() }, + { Color.MistyRose.ToPixel(), Color.MidnightBlue.ToPixel(), 1, PixelAlphaCompositionMode.SrcOut, new Rgba32(0) }, + { Color.MistyRose.ToPixel(), Color.MidnightBlue.ToPixel(), 1, PixelAlphaCompositionMode.SrcOver, Color.MidnightBlue.ToPixel() }, }; [Theory] diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelColorTypeTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelColorTypeTests.cs new file mode 100644 index 0000000000..05fd25cca9 --- /dev/null +++ b/tests/ImageSharp.Tests/PixelFormats/PixelColorTypeTests.cs @@ -0,0 +1,333 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.PixelFormats; + +namespace SixLabors.ImageSharp.Tests.PixelFormats; + +public class PixelColorTypeTests +{ + [Fact] + public void PixelColorType_RedFlag_ShouldBeSet() + { + const PixelColorType colorType = PixelColorType.Red; + Assert.True(colorType.HasFlag(PixelColorType.Red)); + } + + [Fact] + public void PixelColorType_GreenFlag_ShouldBeSet() + { + const PixelColorType colorType = PixelColorType.Green; + Assert.True(colorType.HasFlag(PixelColorType.Green)); + } + + [Fact] + public void PixelColorType_BlueFlag_ShouldBeSet() + { + const PixelColorType colorType = PixelColorType.Blue; + Assert.True(colorType.HasFlag(PixelColorType.Blue)); + } + + [Fact] + public void PixelColorType_AlphaFlag_ShouldBeSet() + { + const PixelColorType colorType = PixelColorType.Alpha; + Assert.True(colorType.HasFlag(PixelColorType.Alpha)); + } + + [Fact] + public void PixelColorType_Exponent_ShouldBeSet() + { + const PixelColorType colorType = PixelColorType.Exponent; + Assert.True(colorType.HasFlag(PixelColorType.Exponent)); + } + + [Fact] + public void PixelColorType_LuminanceFlag_ShouldBeSet() + { + const PixelColorType colorType = PixelColorType.Luminance; + Assert.True(colorType.HasFlag(PixelColorType.Luminance)); + } + + [Fact] + public void PixelColorType_Binary_ShouldBeSet() + { + const PixelColorType colorType = PixelColorType.Binary; + Assert.True(colorType.HasFlag(PixelColorType.Binary)); + } + + [Fact] + public void PixelColorType_Indexed_ShouldBeSet() + { + const PixelColorType colorType = PixelColorType.Indexed; + Assert.True(colorType.HasFlag(PixelColorType.Indexed)); + } + + [Fact] + public void PixelColorType_RGBFlags_ShouldBeSet() + { + const PixelColorType colorType = PixelColorType.RGB; + Assert.True(colorType.HasFlag(PixelColorType.Red)); + Assert.True(colorType.HasFlag(PixelColorType.Green)); + Assert.True(colorType.HasFlag(PixelColorType.Blue)); + Assert.False(colorType.HasFlag(PixelColorType.BGR)); + } + + [Fact] + public void PixelColorType_BGRFlags_ShouldBeSet() + { + const PixelColorType colorType = PixelColorType.BGR; + Assert.True(colorType.HasFlag(PixelColorType.Blue)); + Assert.True(colorType.HasFlag(PixelColorType.Green)); + Assert.True(colorType.HasFlag(PixelColorType.Red)); + Assert.False(colorType.HasFlag(PixelColorType.RGB)); + } + + [Fact] + public void PixelColorType_ChrominanceBlueFlag_ShouldBeSet() + { + const PixelColorType colorType = PixelColorType.ChrominanceBlue; + Assert.True(colorType.HasFlag(PixelColorType.ChrominanceBlue)); + } + + [Fact] + public void PixelColorType_ChrominanceRedFlag_ShouldBeSet() + { + const PixelColorType colorType = PixelColorType.ChrominanceRed; + Assert.True(colorType.HasFlag(PixelColorType.ChrominanceRed)); + } + + [Fact] + public void PixelColorType_YCbCrFlags_ShouldBeSet() + { + const PixelColorType colorType = PixelColorType.YCbCr; + Assert.True(colorType.HasFlag(PixelColorType.Luminance)); + Assert.True(colorType.HasFlag(PixelColorType.ChrominanceBlue)); + Assert.True(colorType.HasFlag(PixelColorType.ChrominanceRed)); + } + + [Fact] + public void PixelColorType_CyanFlag_ShouldBeSet() + { + const PixelColorType colorType = PixelColorType.Cyan; + Assert.True(colorType.HasFlag(PixelColorType.Cyan)); + } + + [Fact] + public void PixelColorType_MagentaFlag_ShouldBeSet() + { + const PixelColorType colorType = PixelColorType.Magenta; + Assert.True(colorType.HasFlag(PixelColorType.Magenta)); + } + + [Fact] + public void PixelColorType_YellowFlag_ShouldBeSet() + { + const PixelColorType colorType = PixelColorType.Yellow; + Assert.True(colorType.HasFlag(PixelColorType.Yellow)); + } + + [Fact] + public void PixelColorType_KeyFlag_ShouldBeSet() + { + const PixelColorType colorType = PixelColorType.Key; + Assert.True(colorType.HasFlag(PixelColorType.Key)); + } + + [Fact] + public void PixelColorType_CMYKFlags_ShouldBeSet() + { + const PixelColorType colorType = PixelColorType.CMYK; + Assert.True(colorType.HasFlag(PixelColorType.Cyan)); + Assert.True(colorType.HasFlag(PixelColorType.Magenta)); + Assert.True(colorType.HasFlag(PixelColorType.Yellow)); + Assert.True(colorType.HasFlag(PixelColorType.Key)); + } + + [Fact] + public void PixelColorType_YCCKFlags_ShouldBeSet() + { + const PixelColorType colorType = PixelColorType.YCCK; + Assert.True(colorType.HasFlag(PixelColorType.Luminance)); + Assert.True(colorType.HasFlag(PixelColorType.ChrominanceBlue)); + Assert.True(colorType.HasFlag(PixelColorType.ChrominanceRed)); + Assert.True(colorType.HasFlag(PixelColorType.Key)); + } + + [Fact] + public void PixelColorType_Other_ShouldBeSet() + { + const PixelColorType colorType = PixelColorType.Other; + Assert.True(colorType.HasFlag(PixelColorType.Other)); + } + + [Fact] + public void PixelColorType_None_ShouldBeZero() + { + const PixelColorType colorType = PixelColorType.None; + Assert.Equal(0, (int)colorType); + } + + [Fact] + public void PixelColorType_RGB_ShouldNotContainOtherFlags() + { + const PixelColorType colorType = PixelColorType.RGB; + Assert.False(colorType.HasFlag(PixelColorType.Alpha)); + Assert.False(colorType.HasFlag(PixelColorType.Exponent)); + Assert.False(colorType.HasFlag(PixelColorType.Luminance)); + Assert.False(colorType.HasFlag(PixelColorType.Binary)); + Assert.False(colorType.HasFlag(PixelColorType.Indexed)); + Assert.False(colorType.HasFlag(PixelColorType.ChrominanceBlue)); + Assert.False(colorType.HasFlag(PixelColorType.ChrominanceRed)); + Assert.False(colorType.HasFlag(PixelColorType.Cyan)); + Assert.False(colorType.HasFlag(PixelColorType.Magenta)); + Assert.False(colorType.HasFlag(PixelColorType.Yellow)); + Assert.False(colorType.HasFlag(PixelColorType.Key)); + Assert.False(colorType.HasFlag(PixelColorType.Other)); + } + + [Fact] + public void PixelColorType_BGR_ShouldNotContainOtherFlags() + { + const PixelColorType colorType = PixelColorType.BGR; + Assert.False(colorType.HasFlag(PixelColorType.Alpha)); + Assert.False(colorType.HasFlag(PixelColorType.Exponent)); + Assert.False(colorType.HasFlag(PixelColorType.Luminance)); + Assert.False(colorType.HasFlag(PixelColorType.Binary)); + Assert.False(colorType.HasFlag(PixelColorType.Indexed)); + Assert.False(colorType.HasFlag(PixelColorType.ChrominanceBlue)); + Assert.False(colorType.HasFlag(PixelColorType.ChrominanceRed)); + Assert.False(colorType.HasFlag(PixelColorType.Cyan)); + Assert.False(colorType.HasFlag(PixelColorType.Magenta)); + Assert.False(colorType.HasFlag(PixelColorType.Yellow)); + Assert.False(colorType.HasFlag(PixelColorType.Key)); + Assert.False(colorType.HasFlag(PixelColorType.Other)); + } + + [Fact] + public void PixelColorType_YCbCr_ShouldNotContainOtherFlags() + { + const PixelColorType colorType = PixelColorType.YCbCr; + Assert.False(colorType.HasFlag(PixelColorType.Red)); + Assert.False(colorType.HasFlag(PixelColorType.Green)); + Assert.False(colorType.HasFlag(PixelColorType.Blue)); + Assert.False(colorType.HasFlag(PixelColorType.Alpha)); + Assert.False(colorType.HasFlag(PixelColorType.Exponent)); + Assert.False(colorType.HasFlag(PixelColorType.Binary)); + Assert.False(colorType.HasFlag(PixelColorType.Indexed)); + Assert.False(colorType.HasFlag(PixelColorType.Cyan)); + Assert.False(colorType.HasFlag(PixelColorType.Magenta)); + Assert.False(colorType.HasFlag(PixelColorType.Yellow)); + Assert.False(colorType.HasFlag(PixelColorType.Key)); + Assert.False(colorType.HasFlag(PixelColorType.Other)); + } + + [Fact] + public void PixelColorType_CMYK_ShouldNotContainOtherFlags() + { + const PixelColorType colorType = PixelColorType.CMYK; + Assert.False(colorType.HasFlag(PixelColorType.Red)); + Assert.False(colorType.HasFlag(PixelColorType.Green)); + Assert.False(colorType.HasFlag(PixelColorType.Blue)); + Assert.False(colorType.HasFlag(PixelColorType.Alpha)); + Assert.False(colorType.HasFlag(PixelColorType.Exponent)); + Assert.False(colorType.HasFlag(PixelColorType.Luminance)); + Assert.False(colorType.HasFlag(PixelColorType.Binary)); + Assert.False(colorType.HasFlag(PixelColorType.Indexed)); + Assert.False(colorType.HasFlag(PixelColorType.ChrominanceBlue)); + Assert.False(colorType.HasFlag(PixelColorType.ChrominanceRed)); + Assert.False(colorType.HasFlag(PixelColorType.Other)); + } + + [Fact] + public void PixelColorType_YCCK_ShouldNotContainOtherFlags() + { + const PixelColorType colorType = PixelColorType.YCCK; + Assert.False(colorType.HasFlag(PixelColorType.Red)); + Assert.False(colorType.HasFlag(PixelColorType.Green)); + Assert.False(colorType.HasFlag(PixelColorType.Blue)); + Assert.False(colorType.HasFlag(PixelColorType.Alpha)); + Assert.False(colorType.HasFlag(PixelColorType.Exponent)); + Assert.False(colorType.HasFlag(PixelColorType.Binary)); + Assert.False(colorType.HasFlag(PixelColorType.Indexed)); + Assert.False(colorType.HasFlag(PixelColorType.Cyan)); + Assert.False(colorType.HasFlag(PixelColorType.Magenta)); + Assert.False(colorType.HasFlag(PixelColorType.Yellow)); + Assert.False(colorType.HasFlag(PixelColorType.Other)); + } + + [Fact] + public void PixelColorType_Binary_ShouldNotContainOtherFlags() + { + const PixelColorType colorType = PixelColorType.Binary; + Assert.False(colorType.HasFlag(PixelColorType.Red)); + Assert.False(colorType.HasFlag(PixelColorType.Green)); + Assert.False(colorType.HasFlag(PixelColorType.Blue)); + Assert.False(colorType.HasFlag(PixelColorType.Alpha)); + Assert.False(colorType.HasFlag(PixelColorType.Exponent)); + Assert.False(colorType.HasFlag(PixelColorType.Luminance)); + Assert.False(colorType.HasFlag(PixelColorType.Indexed)); + Assert.False(colorType.HasFlag(PixelColorType.RGB)); + Assert.False(colorType.HasFlag(PixelColorType.BGR)); + Assert.False(colorType.HasFlag(PixelColorType.ChrominanceBlue)); + Assert.False(colorType.HasFlag(PixelColorType.ChrominanceRed)); + Assert.False(colorType.HasFlag(PixelColorType.YCbCr)); + Assert.False(colorType.HasFlag(PixelColorType.Cyan)); + Assert.False(colorType.HasFlag(PixelColorType.Magenta)); + Assert.False(colorType.HasFlag(PixelColorType.Yellow)); + Assert.False(colorType.HasFlag(PixelColorType.Key)); + Assert.False(colorType.HasFlag(PixelColorType.CMYK)); + Assert.False(colorType.HasFlag(PixelColorType.YCCK)); + Assert.False(colorType.HasFlag(PixelColorType.Other)); + } + + [Fact] + public void PixelColorType_Indexed_ShouldNotContainOtherFlags() + { + const PixelColorType colorType = PixelColorType.Indexed; + Assert.False(colorType.HasFlag(PixelColorType.Red)); + Assert.False(colorType.HasFlag(PixelColorType.Green)); + Assert.False(colorType.HasFlag(PixelColorType.Blue)); + Assert.False(colorType.HasFlag(PixelColorType.Alpha)); + Assert.False(colorType.HasFlag(PixelColorType.Exponent)); + Assert.False(colorType.HasFlag(PixelColorType.Luminance)); + Assert.False(colorType.HasFlag(PixelColorType.Binary)); + Assert.False(colorType.HasFlag(PixelColorType.RGB)); + Assert.False(colorType.HasFlag(PixelColorType.BGR)); + Assert.False(colorType.HasFlag(PixelColorType.ChrominanceBlue)); + Assert.False(colorType.HasFlag(PixelColorType.ChrominanceRed)); + Assert.False(colorType.HasFlag(PixelColorType.YCbCr)); + Assert.False(colorType.HasFlag(PixelColorType.Cyan)); + Assert.False(colorType.HasFlag(PixelColorType.Magenta)); + Assert.False(colorType.HasFlag(PixelColorType.Yellow)); + Assert.False(colorType.HasFlag(PixelColorType.Key)); + Assert.False(colorType.HasFlag(PixelColorType.CMYK)); + Assert.False(colorType.HasFlag(PixelColorType.YCCK)); + Assert.False(colorType.HasFlag(PixelColorType.Other)); + } + + [Fact] + public void PixelColorType_Other_ShouldNotContainPreviousFlags() + { + const PixelColorType colorType = PixelColorType.Other; + Assert.False(colorType.HasFlag(PixelColorType.Red)); + Assert.False(colorType.HasFlag(PixelColorType.Green)); + Assert.False(colorType.HasFlag(PixelColorType.Blue)); + Assert.False(colorType.HasFlag(PixelColorType.Alpha)); + Assert.False(colorType.HasFlag(PixelColorType.Exponent)); + Assert.False(colorType.HasFlag(PixelColorType.Luminance)); + Assert.False(colorType.HasFlag(PixelColorType.Binary)); + Assert.False(colorType.HasFlag(PixelColorType.Indexed)); + Assert.False(colorType.HasFlag(PixelColorType.RGB)); + Assert.False(colorType.HasFlag(PixelColorType.BGR)); + Assert.False(colorType.HasFlag(PixelColorType.ChrominanceBlue)); + Assert.False(colorType.HasFlag(PixelColorType.ChrominanceRed)); + Assert.False(colorType.HasFlag(PixelColorType.YCbCr)); + Assert.False(colorType.HasFlag(PixelColorType.Cyan)); + Assert.False(colorType.HasFlag(PixelColorType.Magenta)); + Assert.False(colorType.HasFlag(PixelColorType.Yellow)); + Assert.False(colorType.HasFlag(PixelColorType.Key)); + Assert.False(colorType.HasFlag(PixelColorType.CMYK)); + Assert.False(colorType.HasFlag(PixelColorType.YCCK)); + } +} diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelConverterTests.ReferenceImplementations.cs b/tests/ImageSharp.Tests/PixelFormats/PixelConverterTests.ReferenceImplementations.cs index 006cb9eb61..2a5c5765ab 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelConverterTests.ReferenceImplementations.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelConverterTests.ReferenceImplementations.cs @@ -14,7 +14,7 @@ public static class ReferenceImplementations { public static byte[] MakeRgba32ByteArray(byte r, byte g, byte b, byte a) { - var buffer = new byte[256]; + byte[] buffer = new byte[256]; for (int i = 0; i < buffer.Length; i += 4) { @@ -29,7 +29,7 @@ public static byte[] MakeRgba32ByteArray(byte r, byte g, byte b, byte a) public static byte[] MakeArgb32ByteArray(byte r, byte g, byte b, byte a) { - var buffer = new byte[256]; + byte[] buffer = new byte[256]; for (int i = 0; i < buffer.Length; i += 4) { @@ -44,7 +44,7 @@ public static byte[] MakeArgb32ByteArray(byte r, byte g, byte b, byte a) public static byte[] MakeBgra32ByteArray(byte r, byte g, byte b, byte a) { - var buffer = new byte[256]; + byte[] buffer = new byte[256]; for (int i = 0; i < buffer.Length; i += 4) { @@ -59,7 +59,7 @@ public static byte[] MakeBgra32ByteArray(byte r, byte g, byte b, byte a) public static byte[] MakeAbgr32ByteArray(byte r, byte g, byte b, byte a) { - var buffer = new byte[256]; + byte[] buffer = new byte[256]; for (int i = 0; i < buffer.Length; i += 4) { @@ -87,49 +87,18 @@ internal static void To( if (typeof(TSourcePixel) == typeof(TDestinationPixel)) { - Span uniformDest = - MemoryMarshal.Cast(destinationPixels); + Span uniformDest = MemoryMarshal.Cast(destinationPixels); sourcePixels.CopyTo(uniformDest); return; } - // L8 and L16 are special implementations of IPixel in that they do not conform to the - // standard RGBA colorspace format and must be converted from RGBA using the special ITU BT709 algorithm. - // One of the requirements of FromScaledVector4/ToScaledVector4 is that it unaware of this and - // packs/unpacks the pixel without and conversion so we employ custom methods do do this. - if (typeof(TDestinationPixel) == typeof(L16)) - { - ref L16 l16Ref = ref MemoryMarshal.GetReference(MemoryMarshal.Cast(destinationPixels)); - for (int i = 0; i < count; i++) - { - ref TSourcePixel sp = ref Unsafe.Add(ref sourceRef, i); - ref L16 dp = ref Unsafe.Add(ref l16Ref, i); - dp.ConvertFromRgbaScaledVector4(sp.ToScaledVector4()); - } - - return; - } - - if (typeof(TDestinationPixel) == typeof(L8)) - { - ref L8 l8Ref = ref MemoryMarshal.GetReference(MemoryMarshal.Cast(destinationPixels)); - for (int i = 0; i < count; i++) - { - ref TSourcePixel sp = ref Unsafe.Add(ref sourceRef, i); - ref L8 dp = ref Unsafe.Add(ref l8Ref, i); - dp.ConvertFromRgbaScaledVector4(sp.ToScaledVector4()); - } - - return; - } - // Normal conversion ref TDestinationPixel destRef = ref MemoryMarshal.GetReference(destinationPixels); for (int i = 0; i < count; i++) { ref TSourcePixel sp = ref Unsafe.Add(ref sourceRef, i); ref TDestinationPixel dp = ref Unsafe.Add(ref destRef, i); - dp.FromScaledVector4(sp.ToScaledVector4()); + dp = TDestinationPixel.FromScaledVector4(sp.ToScaledVector4()); } } } diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/Generated/PixelOperationsTests.Specialized.Generated.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/Generated/PixelOperationsTests.Specialized.Generated.cs index 5ba5c1bedf..b372829270 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/Generated/PixelOperationsTests.Specialized.Generated.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/Generated/PixelOperationsTests.Specialized.Generated.cs @@ -1,4 +1,4 @@ -// Copyright (c) Six Labors. +// Copyright (c) Six Labors. // Licensed under the Six Labors Split License. // @@ -12,7 +12,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations; public partial class PixelOperationsTests { - + public partial class A8_OperationsTests : PixelOperationsTests { public A8_OperationsTests(ITestOutputHelper output) @@ -20,19 +20,14 @@ public A8_OperationsTests(ITestOutputHelper output) { } - protected override PixelOperations Operations => A8.PixelOperations.Instance; - - [Fact] - public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); - [Fact] public void PixelTypeInfoHasCorrectAlphaRepresentation() { - var alphaRepresentation = this.Operations.GetPixelTypeInfo().AlphaRepresentation; + var alphaRepresentation = A8.GetPixelTypeInfo().AlphaRepresentation; Assert.Equal(PixelAlphaRepresentation.Unassociated, alphaRepresentation); } } - + public partial class Argb32_OperationsTests : PixelOperationsTests { public Argb32_OperationsTests(ITestOutputHelper output) @@ -40,19 +35,14 @@ public Argb32_OperationsTests(ITestOutputHelper output) { } - protected override PixelOperations Operations => Argb32.PixelOperations.Instance; - - [Fact] - public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); - [Fact] public void PixelTypeInfoHasCorrectAlphaRepresentation() { - var alphaRepresentation = this.Operations.GetPixelTypeInfo().AlphaRepresentation; + var alphaRepresentation = Argb32.GetPixelTypeInfo().AlphaRepresentation; Assert.Equal(PixelAlphaRepresentation.Unassociated, alphaRepresentation); } } - + public partial class Abgr32_OperationsTests : PixelOperationsTests { public Abgr32_OperationsTests(ITestOutputHelper output) @@ -60,19 +50,14 @@ public Abgr32_OperationsTests(ITestOutputHelper output) { } - protected override PixelOperations Operations => Abgr32.PixelOperations.Instance; - - [Fact] - public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); - [Fact] public void PixelTypeInfoHasCorrectAlphaRepresentation() { - var alphaRepresentation = this.Operations.GetPixelTypeInfo().AlphaRepresentation; + var alphaRepresentation = Abgr32.GetPixelTypeInfo().AlphaRepresentation; Assert.Equal(PixelAlphaRepresentation.Unassociated, alphaRepresentation); } } - + public partial class Bgr24_OperationsTests : PixelOperationsTests { public Bgr24_OperationsTests(ITestOutputHelper output) @@ -80,19 +65,14 @@ public Bgr24_OperationsTests(ITestOutputHelper output) { } - protected override PixelOperations Operations => Bgr24.PixelOperations.Instance; - - [Fact] - public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); - [Fact] public void PixelTypeInfoHasCorrectAlphaRepresentation() { - var alphaRepresentation = this.Operations.GetPixelTypeInfo().AlphaRepresentation; + var alphaRepresentation = Bgr24.GetPixelTypeInfo().AlphaRepresentation; Assert.Equal(PixelAlphaRepresentation.None, alphaRepresentation); } } - + public partial class Bgr565_OperationsTests : PixelOperationsTests { public Bgr565_OperationsTests(ITestOutputHelper output) @@ -100,19 +80,14 @@ public Bgr565_OperationsTests(ITestOutputHelper output) { } - protected override PixelOperations Operations => Bgr565.PixelOperations.Instance; - - [Fact] - public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); - [Fact] public void PixelTypeInfoHasCorrectAlphaRepresentation() { - var alphaRepresentation = this.Operations.GetPixelTypeInfo().AlphaRepresentation; + var alphaRepresentation = Bgr565.GetPixelTypeInfo().AlphaRepresentation; Assert.Equal(PixelAlphaRepresentation.None, alphaRepresentation); } } - + public partial class Bgra32_OperationsTests : PixelOperationsTests { public Bgra32_OperationsTests(ITestOutputHelper output) @@ -120,19 +95,14 @@ public Bgra32_OperationsTests(ITestOutputHelper output) { } - protected override PixelOperations Operations => Bgra32.PixelOperations.Instance; - - [Fact] - public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); - [Fact] public void PixelTypeInfoHasCorrectAlphaRepresentation() { - var alphaRepresentation = this.Operations.GetPixelTypeInfo().AlphaRepresentation; + var alphaRepresentation = Bgra32.GetPixelTypeInfo().AlphaRepresentation; Assert.Equal(PixelAlphaRepresentation.Unassociated, alphaRepresentation); } } - + public partial class Bgra4444_OperationsTests : PixelOperationsTests { public Bgra4444_OperationsTests(ITestOutputHelper output) @@ -140,19 +110,14 @@ public Bgra4444_OperationsTests(ITestOutputHelper output) { } - protected override PixelOperations Operations => Bgra4444.PixelOperations.Instance; - - [Fact] - public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); - [Fact] public void PixelTypeInfoHasCorrectAlphaRepresentation() { - var alphaRepresentation = this.Operations.GetPixelTypeInfo().AlphaRepresentation; + var alphaRepresentation = Bgra4444.GetPixelTypeInfo().AlphaRepresentation; Assert.Equal(PixelAlphaRepresentation.Unassociated, alphaRepresentation); } } - + public partial class Bgra5551_OperationsTests : PixelOperationsTests { public Bgra5551_OperationsTests(ITestOutputHelper output) @@ -160,19 +125,14 @@ public Bgra5551_OperationsTests(ITestOutputHelper output) { } - protected override PixelOperations Operations => Bgra5551.PixelOperations.Instance; - - [Fact] - public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); - [Fact] public void PixelTypeInfoHasCorrectAlphaRepresentation() { - var alphaRepresentation = this.Operations.GetPixelTypeInfo().AlphaRepresentation; + var alphaRepresentation = Bgra5551.GetPixelTypeInfo().AlphaRepresentation; Assert.Equal(PixelAlphaRepresentation.Unassociated, alphaRepresentation); } } - + public partial class Byte4_OperationsTests : PixelOperationsTests { public Byte4_OperationsTests(ITestOutputHelper output) @@ -180,19 +140,14 @@ public Byte4_OperationsTests(ITestOutputHelper output) { } - protected override PixelOperations Operations => Byte4.PixelOperations.Instance; - - [Fact] - public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); - [Fact] public void PixelTypeInfoHasCorrectAlphaRepresentation() { - var alphaRepresentation = this.Operations.GetPixelTypeInfo().AlphaRepresentation; + var alphaRepresentation = Byte4.GetPixelTypeInfo().AlphaRepresentation; Assert.Equal(PixelAlphaRepresentation.Unassociated, alphaRepresentation); } } - + public partial class HalfSingle_OperationsTests : PixelOperationsTests { public HalfSingle_OperationsTests(ITestOutputHelper output) @@ -200,19 +155,14 @@ public HalfSingle_OperationsTests(ITestOutputHelper output) { } - protected override PixelOperations Operations => HalfSingle.PixelOperations.Instance; - - [Fact] - public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); - [Fact] public void PixelTypeInfoHasCorrectAlphaRepresentation() { - var alphaRepresentation = this.Operations.GetPixelTypeInfo().AlphaRepresentation; + var alphaRepresentation = HalfSingle.GetPixelTypeInfo().AlphaRepresentation; Assert.Equal(PixelAlphaRepresentation.None, alphaRepresentation); } } - + public partial class HalfVector2_OperationsTests : PixelOperationsTests { public HalfVector2_OperationsTests(ITestOutputHelper output) @@ -220,19 +170,14 @@ public HalfVector2_OperationsTests(ITestOutputHelper output) { } - protected override PixelOperations Operations => HalfVector2.PixelOperations.Instance; - - [Fact] - public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); - [Fact] public void PixelTypeInfoHasCorrectAlphaRepresentation() { - var alphaRepresentation = this.Operations.GetPixelTypeInfo().AlphaRepresentation; + var alphaRepresentation = HalfVector2.GetPixelTypeInfo().AlphaRepresentation; Assert.Equal(PixelAlphaRepresentation.None, alphaRepresentation); } } - + public partial class HalfVector4_OperationsTests : PixelOperationsTests { public HalfVector4_OperationsTests(ITestOutputHelper output) @@ -240,19 +185,14 @@ public HalfVector4_OperationsTests(ITestOutputHelper output) { } - protected override PixelOperations Operations => HalfVector4.PixelOperations.Instance; - - [Fact] - public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); - [Fact] public void PixelTypeInfoHasCorrectAlphaRepresentation() { - var alphaRepresentation = this.Operations.GetPixelTypeInfo().AlphaRepresentation; + var alphaRepresentation = HalfVector4.GetPixelTypeInfo().AlphaRepresentation; Assert.Equal(PixelAlphaRepresentation.Unassociated, alphaRepresentation); } } - + public partial class L16_OperationsTests : PixelOperationsTests { public L16_OperationsTests(ITestOutputHelper output) @@ -260,19 +200,14 @@ public L16_OperationsTests(ITestOutputHelper output) { } - protected override PixelOperations Operations => L16.PixelOperations.Instance; - - [Fact] - public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); - [Fact] public void PixelTypeInfoHasCorrectAlphaRepresentation() { - var alphaRepresentation = this.Operations.GetPixelTypeInfo().AlphaRepresentation; + var alphaRepresentation = L16.GetPixelTypeInfo().AlphaRepresentation; Assert.Equal(PixelAlphaRepresentation.None, alphaRepresentation); } } - + public partial class L8_OperationsTests : PixelOperationsTests { public L8_OperationsTests(ITestOutputHelper output) @@ -280,19 +215,14 @@ public L8_OperationsTests(ITestOutputHelper output) { } - protected override PixelOperations Operations => L8.PixelOperations.Instance; - - [Fact] - public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); - [Fact] public void PixelTypeInfoHasCorrectAlphaRepresentation() { - var alphaRepresentation = this.Operations.GetPixelTypeInfo().AlphaRepresentation; + var alphaRepresentation = L8.GetPixelTypeInfo().AlphaRepresentation; Assert.Equal(PixelAlphaRepresentation.None, alphaRepresentation); } } - + public partial class La16_OperationsTests : PixelOperationsTests { public La16_OperationsTests(ITestOutputHelper output) @@ -300,19 +230,14 @@ public La16_OperationsTests(ITestOutputHelper output) { } - protected override PixelOperations Operations => La16.PixelOperations.Instance; - - [Fact] - public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); - [Fact] public void PixelTypeInfoHasCorrectAlphaRepresentation() { - var alphaRepresentation = this.Operations.GetPixelTypeInfo().AlphaRepresentation; + var alphaRepresentation = La16.GetPixelTypeInfo().AlphaRepresentation; Assert.Equal(PixelAlphaRepresentation.Unassociated, alphaRepresentation); } } - + public partial class La32_OperationsTests : PixelOperationsTests { public La32_OperationsTests(ITestOutputHelper output) @@ -320,19 +245,14 @@ public La32_OperationsTests(ITestOutputHelper output) { } - protected override PixelOperations Operations => La32.PixelOperations.Instance; - - [Fact] - public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); - [Fact] public void PixelTypeInfoHasCorrectAlphaRepresentation() { - var alphaRepresentation = this.Operations.GetPixelTypeInfo().AlphaRepresentation; + var alphaRepresentation = La32.GetPixelTypeInfo().AlphaRepresentation; Assert.Equal(PixelAlphaRepresentation.Unassociated, alphaRepresentation); } } - + public partial class NormalizedByte2_OperationsTests : PixelOperationsTests { public NormalizedByte2_OperationsTests(ITestOutputHelper output) @@ -340,19 +260,14 @@ public NormalizedByte2_OperationsTests(ITestOutputHelper output) { } - protected override PixelOperations Operations => NormalizedByte2.PixelOperations.Instance; - - [Fact] - public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); - [Fact] public void PixelTypeInfoHasCorrectAlphaRepresentation() { - var alphaRepresentation = this.Operations.GetPixelTypeInfo().AlphaRepresentation; + var alphaRepresentation = NormalizedByte2.GetPixelTypeInfo().AlphaRepresentation; Assert.Equal(PixelAlphaRepresentation.None, alphaRepresentation); } } - + public partial class NormalizedByte4_OperationsTests : PixelOperationsTests { public NormalizedByte4_OperationsTests(ITestOutputHelper output) @@ -360,19 +275,14 @@ public NormalizedByte4_OperationsTests(ITestOutputHelper output) { } - protected override PixelOperations Operations => NormalizedByte4.PixelOperations.Instance; - - [Fact] - public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); - [Fact] public void PixelTypeInfoHasCorrectAlphaRepresentation() { - var alphaRepresentation = this.Operations.GetPixelTypeInfo().AlphaRepresentation; + var alphaRepresentation = NormalizedByte4.GetPixelTypeInfo().AlphaRepresentation; Assert.Equal(PixelAlphaRepresentation.Unassociated, alphaRepresentation); } } - + public partial class NormalizedShort2_OperationsTests : PixelOperationsTests { public NormalizedShort2_OperationsTests(ITestOutputHelper output) @@ -380,19 +290,14 @@ public NormalizedShort2_OperationsTests(ITestOutputHelper output) { } - protected override PixelOperations Operations => NormalizedShort2.PixelOperations.Instance; - - [Fact] - public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); - [Fact] public void PixelTypeInfoHasCorrectAlphaRepresentation() { - var alphaRepresentation = this.Operations.GetPixelTypeInfo().AlphaRepresentation; + var alphaRepresentation = NormalizedShort2.GetPixelTypeInfo().AlphaRepresentation; Assert.Equal(PixelAlphaRepresentation.None, alphaRepresentation); } } - + public partial class NormalizedShort4_OperationsTests : PixelOperationsTests { public NormalizedShort4_OperationsTests(ITestOutputHelper output) @@ -400,19 +305,14 @@ public NormalizedShort4_OperationsTests(ITestOutputHelper output) { } - protected override PixelOperations Operations => NormalizedShort4.PixelOperations.Instance; - - [Fact] - public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); - [Fact] public void PixelTypeInfoHasCorrectAlphaRepresentation() { - var alphaRepresentation = this.Operations.GetPixelTypeInfo().AlphaRepresentation; + var alphaRepresentation = NormalizedShort4.GetPixelTypeInfo().AlphaRepresentation; Assert.Equal(PixelAlphaRepresentation.Unassociated, alphaRepresentation); } } - + public partial class Rg32_OperationsTests : PixelOperationsTests { public Rg32_OperationsTests(ITestOutputHelper output) @@ -420,19 +320,14 @@ public Rg32_OperationsTests(ITestOutputHelper output) { } - protected override PixelOperations Operations => Rg32.PixelOperations.Instance; - - [Fact] - public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); - [Fact] public void PixelTypeInfoHasCorrectAlphaRepresentation() { - var alphaRepresentation = this.Operations.GetPixelTypeInfo().AlphaRepresentation; + var alphaRepresentation = Rg32.GetPixelTypeInfo().AlphaRepresentation; Assert.Equal(PixelAlphaRepresentation.None, alphaRepresentation); } } - + public partial class Rgb24_OperationsTests : PixelOperationsTests { public Rgb24_OperationsTests(ITestOutputHelper output) @@ -440,19 +335,14 @@ public Rgb24_OperationsTests(ITestOutputHelper output) { } - protected override PixelOperations Operations => Rgb24.PixelOperations.Instance; - - [Fact] - public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); - [Fact] public void PixelTypeInfoHasCorrectAlphaRepresentation() { - var alphaRepresentation = this.Operations.GetPixelTypeInfo().AlphaRepresentation; + var alphaRepresentation = Rgb24.GetPixelTypeInfo().AlphaRepresentation; Assert.Equal(PixelAlphaRepresentation.None, alphaRepresentation); } } - + public partial class Rgb48_OperationsTests : PixelOperationsTests { public Rgb48_OperationsTests(ITestOutputHelper output) @@ -460,19 +350,14 @@ public Rgb48_OperationsTests(ITestOutputHelper output) { } - protected override PixelOperations Operations => Rgb48.PixelOperations.Instance; - - [Fact] - public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); - [Fact] public void PixelTypeInfoHasCorrectAlphaRepresentation() { - var alphaRepresentation = this.Operations.GetPixelTypeInfo().AlphaRepresentation; + var alphaRepresentation = Rgb48.GetPixelTypeInfo().AlphaRepresentation; Assert.Equal(PixelAlphaRepresentation.None, alphaRepresentation); } } - + public partial class Rgba1010102_OperationsTests : PixelOperationsTests { public Rgba1010102_OperationsTests(ITestOutputHelper output) @@ -480,19 +365,14 @@ public Rgba1010102_OperationsTests(ITestOutputHelper output) { } - protected override PixelOperations Operations => Rgba1010102.PixelOperations.Instance; - - [Fact] - public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); - [Fact] public void PixelTypeInfoHasCorrectAlphaRepresentation() { - var alphaRepresentation = this.Operations.GetPixelTypeInfo().AlphaRepresentation; + var alphaRepresentation = Rgba1010102.GetPixelTypeInfo().AlphaRepresentation; Assert.Equal(PixelAlphaRepresentation.Unassociated, alphaRepresentation); } } - + public partial class Rgba32_OperationsTests : PixelOperationsTests { public Rgba32_OperationsTests(ITestOutputHelper output) @@ -500,19 +380,14 @@ public Rgba32_OperationsTests(ITestOutputHelper output) { } - protected override PixelOperations Operations => Rgba32.PixelOperations.Instance; - - [Fact] - public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); - [Fact] public void PixelTypeInfoHasCorrectAlphaRepresentation() { - var alphaRepresentation = this.Operations.GetPixelTypeInfo().AlphaRepresentation; + var alphaRepresentation = Rgba32.GetPixelTypeInfo().AlphaRepresentation; Assert.Equal(PixelAlphaRepresentation.Unassociated, alphaRepresentation); } } - + public partial class Rgba64_OperationsTests : PixelOperationsTests { public Rgba64_OperationsTests(ITestOutputHelper output) @@ -520,19 +395,14 @@ public Rgba64_OperationsTests(ITestOutputHelper output) { } - protected override PixelOperations Operations => Rgba64.PixelOperations.Instance; - - [Fact] - public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); - [Fact] public void PixelTypeInfoHasCorrectAlphaRepresentation() { - var alphaRepresentation = this.Operations.GetPixelTypeInfo().AlphaRepresentation; + var alphaRepresentation = Rgba64.GetPixelTypeInfo().AlphaRepresentation; Assert.Equal(PixelAlphaRepresentation.Unassociated, alphaRepresentation); } } - + public partial class RgbaVector_OperationsTests : PixelOperationsTests { public RgbaVector_OperationsTests(ITestOutputHelper output) @@ -540,19 +410,14 @@ public RgbaVector_OperationsTests(ITestOutputHelper output) { } - protected override PixelOperations Operations => RgbaVector.PixelOperations.Instance; - - [Fact] - public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); - [Fact] public void PixelTypeInfoHasCorrectAlphaRepresentation() { - var alphaRepresentation = this.Operations.GetPixelTypeInfo().AlphaRepresentation; + var alphaRepresentation = RgbaVector.GetPixelTypeInfo().AlphaRepresentation; Assert.Equal(PixelAlphaRepresentation.Unassociated, alphaRepresentation); } } - + public partial class Short2_OperationsTests : PixelOperationsTests { public Short2_OperationsTests(ITestOutputHelper output) @@ -560,19 +425,14 @@ public Short2_OperationsTests(ITestOutputHelper output) { } - protected override PixelOperations Operations => Short2.PixelOperations.Instance; - - [Fact] - public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); - [Fact] public void PixelTypeInfoHasCorrectAlphaRepresentation() { - var alphaRepresentation = this.Operations.GetPixelTypeInfo().AlphaRepresentation; + var alphaRepresentation = Short2.GetPixelTypeInfo().AlphaRepresentation; Assert.Equal(PixelAlphaRepresentation.None, alphaRepresentation); } } - + public partial class Short4_OperationsTests : PixelOperationsTests { public Short4_OperationsTests(ITestOutputHelper output) @@ -580,15 +440,10 @@ public Short4_OperationsTests(ITestOutputHelper output) { } - protected override PixelOperations Operations => Short4.PixelOperations.Instance; - - [Fact] - public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); - [Fact] public void PixelTypeInfoHasCorrectAlphaRepresentation() { - var alphaRepresentation = this.Operations.GetPixelTypeInfo().AlphaRepresentation; + var alphaRepresentation = Short4.GetPixelTypeInfo().AlphaRepresentation; Assert.Equal(PixelAlphaRepresentation.Unassociated, alphaRepresentation); } } diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/Generated/_Common.ttinclude b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/Generated/_Common.ttinclude index 0e7b1f3354..90cb3a8665 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/Generated/_Common.ttinclude +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/Generated/_Common.ttinclude @@ -70,7 +70,7 @@ using Xunit.Abstractions; void GenerateSpecializedClass(string pixelType, string alpha) {#> - + public partial class <#=pixelType#>_OperationsTests : PixelOperationsTests<<#=pixelType#>> { public <#=pixelType#>_OperationsTests(ITestOutputHelper output) @@ -78,15 +78,10 @@ using Xunit.Abstractions; { } - protected override PixelOperations<<#=pixelType#>> Operations => <#=pixelType#>.PixelOperations.Instance; - - [Fact] - public void IsSpecialImplementation() => Assert.IsType<<#=pixelType#>.PixelOperations>(PixelOperations<<#=pixelType#>>.Instance); - [Fact] public void PixelTypeInfoHasCorrectAlphaRepresentation() { - var alphaRepresentation = this.Operations.GetPixelTypeInfo().AlphaRepresentation; + var alphaRepresentation = <#=pixelType#>.GetPixelTypeInfo().AlphaRepresentation; Assert.Equal(<#=alpha#>, alphaRepresentation); } } diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.cs index a9b3ee9a42..32b62fc03d 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.cs @@ -5,7 +5,7 @@ using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using SixLabors.ImageSharp.ColorSpaces.Companding; +using SixLabors.ImageSharp.ColorProfiles.Companding; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Tests.Common; @@ -39,49 +39,49 @@ protected PixelOperationsTests(ITestOutputHelper output) } public static TheoryData ArraySizesData => - new TheoryData - { - 0, - 1, - 2, - 7, - 16, - 512, - 513, - 514, - 515, - 516, - 517, - 518, - 519, - 520, - 521, - 522, - 523, - 524, - 525, - 526, - 527, - 528, - 1111 - }; + new() + { + 0, + 1, + 2, + 7, + 16, + 512, + 513, + 514, + 515, + 516, + 517, + 518, + 519, + 520, + 521, + 522, + 523, + 524, + 525, + 526, + 527, + 528, + 1111 + }; protected Configuration Configuration => Configuration.Default; protected virtual PixelOperations Operations { get; } = PixelOperations.Instance; - protected bool HasUnassociatedAlpha => this.Operations.GetPixelTypeInfo().AlphaRepresentation == PixelAlphaRepresentation.Unassociated; + protected bool HasUnassociatedAlpha => TPixel.GetPixelTypeInfo().AlphaRepresentation == PixelAlphaRepresentation.Unassociated; internal static TPixel[] CreateExpectedPixelData(Vector4[] source, RefAction vectorModifier = null) { - var expected = new TPixel[source.Length]; + TPixel[] expected = new TPixel[source.Length]; for (int i = 0; i < expected.Length; i++) { Vector4 v = source[i]; vectorModifier?.Invoke(ref v); - expected[i].FromVector4(v); + expected[i] = TPixel.FromVector4(v); } return expected; @@ -89,14 +89,14 @@ internal static TPixel[] CreateExpectedPixelData(Vector4[] source, RefAction vectorModifier = null) { - var expected = new TPixel[source.Length]; + TPixel[] expected = new TPixel[source.Length]; for (int i = 0; i < expected.Length; i++) { Vector4 v = source[i]; vectorModifier?.Invoke(ref v); - expected[i].FromScaledVector4(v); + expected[i] = TPixel.FromScaledVector4(v); } return expected; @@ -105,7 +105,7 @@ internal static TPixel[] CreateScaledExpectedPixelData(Vector4[] source, RefActi [Fact] public void PixelTypeInfoHasCorrectBitsPerPixel() { - int bits = this.Operations.GetPixelTypeInfo().BitsPerPixel; + int bits = TPixel.GetPixelTypeInfo().BitsPerPixel; Assert.Equal(Unsafe.SizeOf() * 8, bits); } @@ -114,18 +114,16 @@ public void PixelAlphaRepresentation_DefinesPresenceOfAlphaChannel() { // We use 0 - 255 as we have pixel formats that store // the alpha component in less than 8 bits. - const byte Alpha = byte.MinValue; - const byte NoAlpha = byte.MaxValue; + const byte alpha = byte.MinValue; + const byte noAlpha = byte.MaxValue; - TPixel pixel = default; - pixel.FromRgba32(new Rgba32(0, 0, 0, Alpha)); + TPixel pixel = TPixel.FromRgba32(new Rgba32(0, 0, 0, alpha)); - Rgba32 dest = default; - pixel.ToRgba32(ref dest); + Rgba32 dest = pixel.ToRgba32(); - bool hasAlpha = this.Operations.GetPixelTypeInfo().AlphaRepresentation != PixelAlphaRepresentation.None; + bool hasAlpha = TPixel.GetPixelTypeInfo().AlphaRepresentation != PixelAlphaRepresentation.None; - byte expectedAlpha = hasAlpha ? Alpha : NoAlpha; + byte expectedAlpha = hasAlpha ? alpha : noAlpha; Assert.Equal(expectedAlpha, dest.A); } @@ -163,12 +161,12 @@ public void FromScaledVector4(int count) [MemberData(nameof(ArraySizesData))] public void FromCompandedScaledVector4(int count) { - void SourceAction(ref Vector4 v) => SRgbCompanding.Expand(ref v); + void SourceAction(ref Vector4 v) => v = SRgbCompanding.Expand(v); - void ExpectedAction(ref Vector4 v) => SRgbCompanding.Compress(ref v); + void ExpectedAction(ref Vector4 v) => v = SRgbCompanding.Compress(v); - Vector4[] source = CreateVector4TestData(count, (ref Vector4 v) => SourceAction(ref v)); - TPixel[] expected = CreateScaledExpectedPixelData(source, (ref Vector4 v) => ExpectedAction(ref v)); + Vector4[] source = CreateVector4TestData(count, SourceAction); + TPixel[] expected = CreateScaledExpectedPixelData(source, ExpectedAction); TestOperation( source, @@ -263,7 +261,7 @@ public void FromCompandedPremultipliedScaledVector4(int count) { void SourceAction(ref Vector4 v) { - SRgbCompanding.Expand(ref v); + v = SRgbCompanding.Expand(v); if (this.HasUnassociatedAlpha) { @@ -278,11 +276,11 @@ void ExpectedAction(ref Vector4 v) Numerics.UnPremultiply(ref v); } - SRgbCompanding.Compress(ref v); + v = SRgbCompanding.Compress(v); } - Vector4[] source = CreateVector4TestData(count, (ref Vector4 v) => SourceAction(ref v)); - TPixel[] expected = CreateScaledExpectedPixelData(source, (ref Vector4 v) => ExpectedAction(ref v)); + Vector4[] source = CreateVector4TestData(count, SourceAction); + TPixel[] expected = CreateScaledExpectedPixelData(source, ExpectedAction); TestOperation( source, @@ -355,7 +353,7 @@ public void Generic_To(TestPixel _) { const int count = 2134; TPixel[] source = CreatePixelTestData(count); - var expected = new TDestPixel[count]; + TDestPixel[] expected = new TDestPixel[count]; PixelConverterTests.ReferenceImplementations.To(this.Configuration, source, expected); @@ -387,10 +385,10 @@ void SourceAction(ref Vector4 v) { } - void ExpectedAction(ref Vector4 v) => SRgbCompanding.Expand(ref v); + void ExpectedAction(ref Vector4 v) => v = SRgbCompanding.Expand(v); - TPixel[] source = CreateScaledPixelTestData(count, (ref Vector4 v) => SourceAction(ref v)); - Vector4[] expected = CreateExpectedScaledVector4Data(source, (ref Vector4 v) => ExpectedAction(ref v)); + TPixel[] source = CreateScaledPixelTestData(count, SourceAction); + Vector4[] expected = CreateExpectedScaledVector4Data(source, ExpectedAction); TestOperation( source, @@ -412,8 +410,8 @@ void SourceAction(ref Vector4 v) void ExpectedAction(ref Vector4 v) => Numerics.Premultiply(ref v); - TPixel[] source = CreatePixelTestData(count, (ref Vector4 v) => SourceAction(ref v)); - Vector4[] expected = CreateExpectedVector4Data(source, (ref Vector4 v) => ExpectedAction(ref v)); + TPixel[] source = CreatePixelTestData(count, SourceAction); + Vector4[] expected = CreateExpectedVector4Data(source, ExpectedAction); TestOperation( source, @@ -431,7 +429,7 @@ void SourceAction(ref Vector4 v) void ExpectedAction(ref Vector4 v) => Numerics.Premultiply(ref v); - TPixel[] source = CreateScaledPixelTestData(count, (ref Vector4 v) => SourceAction(ref v)); + TPixel[] source = CreateScaledPixelTestData(count, SourceAction); Vector4[] expected = CreateExpectedScaledVector4Data(source, (ref Vector4 v) => ExpectedAction(ref v)); TestOperation( @@ -454,12 +452,12 @@ void SourceAction(ref Vector4 v) void ExpectedAction(ref Vector4 v) { - SRgbCompanding.Expand(ref v); + v = SRgbCompanding.Expand(v); Numerics.Premultiply(ref v); } - TPixel[] source = CreateScaledPixelTestData(count, (ref Vector4 v) => SourceAction(ref v)); - Vector4[] expected = CreateExpectedScaledVector4Data(source, (ref Vector4 v) => ExpectedAction(ref v)); + TPixel[] source = CreateScaledPixelTestData(count, SourceAction); + Vector4[] expected = CreateExpectedScaledVector4Data(source, ExpectedAction); TestOperation( source, @@ -476,13 +474,13 @@ void ExpectedAction(ref Vector4 v) public void FromArgb32Bytes(int count) { byte[] source = CreateByteTestData(count * 4); - var expected = new TPixel[count]; + TPixel[] expected = new TPixel[count]; for (int i = 0; i < count; i++) { int i4 = i * 4; - expected[i].FromArgb32(new Argb32(source[i4 + 1], source[i4 + 2], source[i4 + 3], source[i4 + 0])); + expected[i] = TPixel.FromArgb32(new Argb32(source[i4 + 1], source[i4 + 2], source[i4 + 3], source[i4 + 0])); } TestOperation( @@ -497,12 +495,11 @@ public void ToArgb32Bytes(int count) { TPixel[] source = CreatePixelTestData(count); byte[] expected = new byte[count * 4]; - var argb = default(Argb32); for (int i = 0; i < count; i++) { int i4 = i * 4; - argb.FromScaledVector4(source[i].ToScaledVector4()); + Argb32 argb = Argb32.FromScaledVector4(source[i].ToScaledVector4()); expected[i4] = argb.A; expected[i4 + 1] = argb.R; @@ -521,13 +518,13 @@ public void ToArgb32Bytes(int count) public void FromBgr24Bytes(int count) { byte[] source = CreateByteTestData(count * 3); - var expected = new TPixel[count]; + TPixel[] expected = new TPixel[count]; for (int i = 0; i < count; i++) { int i3 = i * 3; - expected[i].FromBgr24(new Bgr24(source[i3 + 2], source[i3 + 1], source[i3])); + expected[i] = TPixel.FromBgr24(new Bgr24(source[i3 + 2], source[i3 + 1], source[i3])); } TestOperation( @@ -542,12 +539,11 @@ public void ToBgr24Bytes(int count) { TPixel[] source = CreatePixelTestData(count); byte[] expected = new byte[count * 3]; - var bgr = default(Bgr24); for (int i = 0; i < count; i++) { int i3 = i * 3; - bgr.FromScaledVector4(source[i].ToScaledVector4()); + Bgr24 bgr = Bgr24.FromScaledVector4(source[i].ToScaledVector4()); expected[i3] = bgr.B; expected[i3 + 1] = bgr.G; expected[i3 + 2] = bgr.R; @@ -564,13 +560,13 @@ public void ToBgr24Bytes(int count) public void FromBgra32Bytes(int count) { byte[] source = CreateByteTestData(count * 4); - var expected = new TPixel[count]; + TPixel[] expected = new TPixel[count]; for (int i = 0; i < count; i++) { int i4 = i * 4; - expected[i].FromBgra32(new Bgra32(source[i4 + 2], source[i4 + 1], source[i4 + 0], source[i4 + 3])); + expected[i] = TPixel.FromBgra32(new Bgra32(source[i4 + 2], source[i4 + 1], source[i4 + 0], source[i4 + 3])); } TestOperation( @@ -585,12 +581,11 @@ public void ToBgra32Bytes(int count) { TPixel[] source = CreatePixelTestData(count); byte[] expected = new byte[count * 4]; - var bgra = default(Bgra32); for (int i = 0; i < count; i++) { int i4 = i * 4; - bgra.FromScaledVector4(source[i].ToScaledVector4()); + Bgra32 bgra = Bgra32.FromScaledVector4(source[i].ToScaledVector4()); expected[i4] = bgra.B; expected[i4 + 1] = bgra.G; expected[i4 + 2] = bgra.R; @@ -608,13 +603,13 @@ public void ToBgra32Bytes(int count) public void FromAbgr32Bytes(int count) { byte[] source = CreateByteTestData(count * 4); - var expected = new TPixel[count]; + TPixel[] expected = new TPixel[count]; for (int i = 0; i < count; i++) { int i4 = i * 4; - expected[i].FromAbgr32(new Abgr32(source[i4 + 3], source[i4 + 2], source[i4 + 1], source[i4 + 0])); + expected[i] = TPixel.FromAbgr32(new Abgr32(source[i4 + 3], source[i4 + 2], source[i4 + 1], source[i4 + 0])); } TestOperation( @@ -629,12 +624,11 @@ public void ToAbgr32Bytes(int count) { TPixel[] source = CreatePixelTestData(count); byte[] expected = new byte[count * 4]; - var abgr = default(Abgr32); for (int i = 0; i < count; i++) { int i4 = i * 4; - abgr.FromScaledVector4(source[i].ToScaledVector4()); + Abgr32 abgr = Abgr32.FromScaledVector4(source[i].ToScaledVector4()); expected[i4] = abgr.A; expected[i4 + 1] = abgr.B; expected[i4 + 2] = abgr.G; @@ -653,14 +647,14 @@ public void FromBgra5551Bytes(int count) { int size = Unsafe.SizeOf(); byte[] source = CreateByteTestData(count * size); - var expected = new TPixel[count]; + TPixel[] expected = new TPixel[count]; for (int i = 0; i < count; i++) { int offset = i * size; Bgra5551 bgra = MemoryMarshal.Cast(source.AsSpan().Slice(offset, size))[0]; - expected[i].FromBgra5551(bgra); + expected[i] = TPixel.FromBgra5551(bgra); } TestOperation( @@ -676,12 +670,11 @@ public void ToBgra5551Bytes(int count) int size = Unsafe.SizeOf(); TPixel[] source = CreatePixelTestData(count); byte[] expected = new byte[count * size]; - Bgra5551 bgra = default; for (int i = 0; i < count; i++) { int offset = i * size; - bgra.FromScaledVector4(source[i].ToScaledVector4()); + Bgra5551 bgra = Bgra5551.FromScaledVector4(source[i].ToScaledVector4()); OctetBytes bytes = Unsafe.As(ref bgra); expected[offset] = bytes[0]; expected[offset + 1] = bytes[1]; @@ -699,11 +692,11 @@ public void FromL8(int count) { byte[] sourceBytes = CreateByteTestData(count); L8[] source = sourceBytes.Select(b => new L8(b)).ToArray(); - var expected = new TPixel[count]; + TPixel[] expected = new TPixel[count]; for (int i = 0; i < count; i++) { - expected[i].FromL8(source[i]); + expected[i] = TPixel.FromL8(source[i]); } TestOperation( @@ -717,11 +710,11 @@ public void FromL8(int count) public void ToL8(int count) { TPixel[] source = CreatePixelTestData(count); - var expected = new L8[count]; + L8[] expected = new L8[count]; for (int i = 0; i < count; i++) { - expected[i].FromScaledVector4(source[i].ToScaledVector4()); + expected[i] = L8.FromScaledVector4(source[i].ToScaledVector4()); } TestOperation( @@ -734,18 +727,13 @@ public void ToL8(int count) [MemberData(nameof(ArraySizesData))] public void FromL16(int count) { - L16[] source = CreateVector4TestData(count).Select(v => - { - L16 g = default; - g.FromVector4(v); - return g; - }).ToArray(); + L16[] source = CreateVector4TestData(count).Select(L16.FromVector4).ToArray(); - var expected = new TPixel[count]; + TPixel[] expected = new TPixel[count]; for (int i = 0; i < count; i++) { - expected[i].FromL16(source[i]); + expected[i] = TPixel.FromL16(source[i]); } TestOperation( @@ -759,11 +747,11 @@ public void FromL16(int count) public void ToL16(int count) { TPixel[] source = CreatePixelTestData(count); - var expected = new L16[count]; + L16[] expected = new L16[count]; for (int i = 0; i < count; i++) { - expected[i].FromScaledVector4(source[i].ToScaledVector4()); + expected[i] = L16.FromScaledVector4(source[i].ToScaledVector4()); } TestOperation( @@ -778,14 +766,14 @@ public void FromLa16Bytes(int count) { int size = Unsafe.SizeOf(); byte[] source = CreateByteTestData(count * size); - var expected = new TPixel[count]; + TPixel[] expected = new TPixel[count]; for (int i = 0; i < count; i++) { int offset = i * size; La16 la = MemoryMarshal.Cast(source.AsSpan().Slice(offset, size))[0]; - expected[i].FromLa16(la); + expected[i] = TPixel.FromLa16(la); } TestOperation( @@ -801,12 +789,11 @@ public void ToLa16Bytes(int count) int size = Unsafe.SizeOf(); TPixel[] source = CreatePixelTestData(count); byte[] expected = new byte[count * size]; - La16 la = default; for (int i = 0; i < count; i++) { int offset = i * size; - la.FromScaledVector4(source[i].ToScaledVector4()); + La16 la = La16.FromScaledVector4(source[i].ToScaledVector4()); OctetBytes bytes = Unsafe.As(ref la); expected[offset] = bytes[0]; expected[offset + 1] = bytes[1]; @@ -824,14 +811,14 @@ public void FromLa32Bytes(int count) { int size = Unsafe.SizeOf(); byte[] source = CreateByteTestData(count * size); - var expected = new TPixel[count]; + TPixel[] expected = new TPixel[count]; for (int i = 0; i < count; i++) { int offset = i * size; La32 la = MemoryMarshal.Cast(source.AsSpan().Slice(offset, size))[0]; - expected[i].FromLa32(la); + expected[i] = TPixel.FromLa32(la); } TestOperation( @@ -847,12 +834,11 @@ public void ToLa32Bytes(int count) int size = Unsafe.SizeOf(); TPixel[] source = CreatePixelTestData(count); byte[] expected = new byte[count * size]; - La32 la = default; for (int i = 0; i < count; i++) { int offset = i * size; - la.FromScaledVector4(source[i].ToScaledVector4()); + La32 la = La32.FromScaledVector4(source[i].ToScaledVector4()); OctetBytes bytes = Unsafe.As(ref la); expected[offset] = bytes[0]; expected[offset + 1] = bytes[1]; @@ -871,13 +857,13 @@ public void ToLa32Bytes(int count) public void FromRgb24Bytes(int count) { byte[] source = CreateByteTestData(count * 3); - var expected = new TPixel[count]; + TPixel[] expected = new TPixel[count]; for (int i = 0; i < count; i++) { int i3 = i * 3; - expected[i].FromRgb24(new Rgb24(source[i3 + 0], source[i3 + 1], source[i3 + 2])); + expected[i] = TPixel.FromRgb24(new Rgb24(source[i3 + 0], source[i3 + 1], source[i3 + 2])); } TestOperation( @@ -892,12 +878,11 @@ public void ToRgb24Bytes(int count) { TPixel[] source = CreatePixelTestData(count); byte[] expected = new byte[count * 3]; - var rgb = default(Rgb24); for (int i = 0; i < count; i++) { int i3 = i * 3; - rgb.FromScaledVector4(source[i].ToScaledVector4()); + Rgb24 rgb = Rgb24.FromScaledVector4(source[i].ToScaledVector4()); expected[i3] = rgb.R; expected[i3 + 1] = rgb.G; expected[i3 + 2] = rgb.B; @@ -914,13 +899,13 @@ public void ToRgb24Bytes(int count) public void FromRgba32Bytes(int count) { byte[] source = CreateByteTestData(count * 4); - var expected = new TPixel[count]; + TPixel[] expected = new TPixel[count]; for (int i = 0; i < count; i++) { int i4 = i * 4; - expected[i].FromRgba32(new Rgba32(source[i4 + 0], source[i4 + 1], source[i4 + 2], source[i4 + 3])); + expected[i] = TPixel.FromRgba32(new Rgba32(source[i4 + 0], source[i4 + 1], source[i4 + 2], source[i4 + 3])); } TestOperation( @@ -935,12 +920,11 @@ public void ToRgba32Bytes(int count) { TPixel[] source = CreatePixelTestData(count); byte[] expected = new byte[count * 4]; - var rgba = default(Rgba32); for (int i = 0; i < count; i++) { int i4 = i * 4; - rgba.FromScaledVector4(source[i].ToScaledVector4()); + Rgba32 rgba = Rgba32.FromScaledVector4(source[i].ToScaledVector4()); expected[i4] = rgba.R; expected[i4 + 1] = rgba.G; expected[i4 + 2] = rgba.B; @@ -959,12 +943,12 @@ public void FromRgb48Bytes(int count) { byte[] source = CreateByteTestData(count * 6); Span sourceSpan = source.AsSpan(); - var expected = new TPixel[count]; + TPixel[] expected = new TPixel[count]; for (int i = 0; i < count; i++) { int i6 = i * 6; - expected[i].FromRgb48(MemoryMarshal.Cast(sourceSpan.Slice(i6, 6))[0]); + expected[i] = TPixel.FromRgb48(MemoryMarshal.Cast(sourceSpan.Slice(i6, 6))[0]); } TestOperation( @@ -979,12 +963,11 @@ public void ToRgb48Bytes(int count) { TPixel[] source = CreatePixelTestData(count); byte[] expected = new byte[count * 6]; - Rgb48 rgb = default; for (int i = 0; i < count; i++) { int i6 = i * 6; - rgb.FromScaledVector4(source[i].ToScaledVector4()); + Rgb48 rgb = Rgb48.FromScaledVector4(source[i].ToScaledVector4()); OctetBytes rgb48Bytes = Unsafe.As(ref rgb); expected[i6] = rgb48Bytes[0]; expected[i6 + 1] = rgb48Bytes[1]; @@ -1006,12 +989,12 @@ public void FromRgba64Bytes(int count) { byte[] source = CreateByteTestData(count * 8); Span sourceSpan = source.AsSpan(); - var expected = new TPixel[count]; + TPixel[] expected = new TPixel[count]; for (int i = 0; i < count; i++) { int i8 = i * 8; - expected[i].FromRgba64(MemoryMarshal.Cast(sourceSpan.Slice(i8, 8))[0]); + expected[i] = TPixel.FromRgba64(MemoryMarshal.Cast(sourceSpan.Slice(i8, 8))[0]); } TestOperation( @@ -1026,12 +1009,11 @@ public void ToRgba64Bytes(int count) { TPixel[] source = CreatePixelTestData(count); byte[] expected = new byte[count * 8]; - Rgba64 rgba = default; for (int i = 0; i < count; i++) { int i8 = i * 8; - rgba.FromScaledVector4(source[i].ToScaledVector4()); + Rgba64 rgba = Rgba64.FromScaledVector4(source[i].ToScaledVector4()); OctetBytes rgba64Bytes = Unsafe.As(ref rgba); expected[i8] = rgba64Bytes[0]; expected[i8 + 1] = rgba64Bytes[1]; @@ -1060,11 +1042,11 @@ public void PackFromRgbPlanes(int count) internal static Vector4[] CreateExpectedVector4Data(TPixel[] source, RefAction vectorModifier = null) { - var expected = new Vector4[source.Length]; + Vector4[] expected = new Vector4[source.Length]; for (int i = 0; i < expected.Length; i++) { - var v = source[i].ToVector4(); + Vector4 v = source[i].ToVector4(); vectorModifier?.Invoke(ref v); @@ -1076,7 +1058,7 @@ internal static Vector4[] CreateExpectedVector4Data(TPixel[] source, RefAction vectorModifier = null) { - var expected = new Vector4[source.Length]; + Vector4[] expected = new Vector4[source.Length]; for (int i = 0; i < expected.Length; i++) { @@ -1098,7 +1080,7 @@ internal static void TestOperation( where TSource : struct where TDest : struct { - using (var buffers = new TestBuffers(source, expected, preferExactComparison)) + using (TestBuffers buffers = new(source, expected, preferExactComparison)) { action(buffers.SourceBuffer, buffers.ActualDestBuffer); buffers.Verify(); @@ -1107,8 +1089,8 @@ internal static void TestOperation( internal static Vector4[] CreateVector4TestData(int length, RefAction vectorModifier = null) { - var result = new Vector4[length]; - var rnd = new Random(42); // Deterministic random values + Vector4[] result = new Vector4[length]; + Random rnd = new(42); // Deterministic random values for (int i = 0; i < result.Length; i++) { @@ -1123,9 +1105,9 @@ internal static Vector4[] CreateVector4TestData(int length, RefAction v internal static TPixel[] CreatePixelTestData(int length, RefAction vectorModifier = null) { - var result = new TPixel[length]; + TPixel[] result = new TPixel[length]; - var rnd = new Random(42); // Deterministic random values + Random rnd = new(42); // Deterministic random values for (int i = 0; i < result.Length; i++) { @@ -1133,7 +1115,7 @@ internal static TPixel[] CreatePixelTestData(int length, RefAction vect vectorModifier?.Invoke(ref v); - result[i].FromVector4(v); + result[i] = TPixel.FromVector4(v); } return result; @@ -1141,9 +1123,9 @@ internal static TPixel[] CreatePixelTestData(int length, RefAction vect internal static TPixel[] CreateScaledPixelTestData(int length, RefAction vectorModifier = null) { - var result = new TPixel[length]; + TPixel[] result = new TPixel[length]; - var rnd = new Random(42); // Deterministic random values + Random rnd = new(42); // Deterministic random values for (int i = 0; i < result.Length; i++) { @@ -1151,7 +1133,7 @@ internal static TPixel[] CreateScaledPixelTestData(int length, RefAction new Vector4((float)rnd.NextDouble(), (float)rnd.NextDouble(), (float)rnd.NextDouble(), (float)rnd.NextDouble()); + => new((float)rnd.NextDouble(), (float)rnd.NextDouble(), (float)rnd.NextDouble(), (float)rnd.NextDouble()); [StructLayout(LayoutKind.Sequential)] internal unsafe struct OctetBytes @@ -1219,7 +1201,7 @@ public void Verify() { Span expected = MemoryMarshal.Cast(this.ExpectedDestBuffer.AsSpan()); Span actual = MemoryMarshal.Cast(this.ActualDestBuffer.GetSpan()); - var comparer = new ApproximateFloatComparer(TestEnvironment.Is64BitProcess ? 0.0001F : 0.001F); + ApproximateFloatComparer comparer = new(TestEnvironment.Is64BitProcess ? 0.0001F : 0.001F); for (int i = 0; i < count; i++) { @@ -1230,11 +1212,11 @@ public void Verify() { Span expected = this.ExpectedDestBuffer.AsSpan(); Span actual = this.ActualDestBuffer.GetSpan(); - var comparer = new ApproximateFloatComparer(TestEnvironment.Is64BitProcess ? 0.0001F : 0.001F); + ApproximateFloatComparer comparer = new(TestEnvironment.Is64BitProcess ? 0.0001F : 0.001F); for (int i = 0; i < count; i++) { - Assert.Equal((IPixel)expected[i], (IPixel)actual[i], comparer); + Assert.Equal(((IPixel)expected[i]).ToScaledVector4(), ((IPixel)actual[i]).ToScaledVector4(), comparer); } } else @@ -1249,7 +1231,7 @@ public void Verify() } } - // TODO: We really need a PixelTypeInfo.BitsPerComponent property!! + // TODO: Figure out a means to use PixelTypeInfo here. private static bool IsComplexPixel() => default(TDest) switch { HalfSingle or HalfVector2 or L16 or La32 or NormalizedShort2 or Rg32 or Short2 => true, diff --git a/tests/ImageSharp.Tests/PixelFormats/Rg32Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rg32Tests.cs index 2900b0d292..b2790469a1 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rg32Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rg32Tests.cs @@ -2,6 +2,7 @@ // Licensed under the Six Labors Split License. using System.Numerics; +using System.Runtime.CompilerServices; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Tests.PixelFormats; @@ -12,8 +13,8 @@ public class Rg32Tests [Fact] public void Rg32_PackedValues() { - float x = 0xb6dc; - float y = 0xA59f; + const float x = 0xb6dc; + const float y = 0xA59f; Assert.Equal(0xa59fb6dc, new Rg32(x / 0xffff, y / 0xffff).PackedValue); Assert.Equal(6554U, new Rg32(0.1f, -0.3f).PackedValue); @@ -33,7 +34,7 @@ public void Rg32_ToVector2() public void Rg32_ToScaledVector4() { // arrange - var rg32 = new Rg32(Vector2.One); + Rg32 rg32 = new(Vector2.One); // act Vector4 actual = rg32.ToScaledVector4(); @@ -49,13 +50,12 @@ public void Rg32_ToScaledVector4() public void Rg32_FromScaledVector4() { // arrange - var rg32 = new Rg32(Vector2.One); - var pixel = default(Rg32); - uint expected = 0xFFFFFFFF; + Rg32 rg32 = new(Vector2.One); + const uint expected = 0xFFFFFFFF; // act Vector4 scaled = rg32.ToScaledVector4(); - pixel.FromScaledVector4(scaled); + Rg32 pixel = Rg32.FromScaledVector4(scaled); uint actual = pixel.PackedValue; // assert @@ -66,11 +66,10 @@ public void Rg32_FromScaledVector4() public void Rg32_FromBgra5551() { // arrange - var rg32 = new Rg32(Vector2.One); - uint expected = 0xFFFFFFFF; + const uint expected = 0xFFFFFFFF; // act - rg32.FromBgra5551(new Bgra5551(1.0f, 1.0f, 1.0f, 1.0f)); + Rg32 rg32 = Rg32.FromBgra5551(new Bgra5551(1f, 1f, 1f, 1f)); // assert Assert.Equal(expected, rg32.PackedValue); @@ -82,4 +81,20 @@ public void Rg32_Clamping() Assert.Equal(Vector2.Zero, new Rg32(Vector2.One * -1234.0f).ToVector2()); Assert.Equal(Vector2.One, new Rg32(Vector2.One * 1234.0f).ToVector2()); } + + [Fact] + public void Rg32_PixelInformation() + { + PixelTypeInfo info = Rg32.GetPixelTypeInfo(); + Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); + Assert.Equal(PixelAlphaRepresentation.None, info.AlphaRepresentation); + Assert.Equal(PixelColorType.Red | PixelColorType.Green, info.ColorType); + + PixelComponentInfo componentInfo = info.ComponentInfo.Value; + Assert.Equal(2, componentInfo.ComponentCount); + Assert.Equal(0, componentInfo.Padding); + Assert.Equal(16, componentInfo.GetComponentPrecision(0)); + Assert.Equal(16, componentInfo.GetComponentPrecision(1)); + Assert.Equal(16, componentInfo.GetMaximumComponentPrecision()); + } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgb24Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgb24Tests.cs index 2d1be8ab44..6364378c15 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgb24Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgb24Tests.cs @@ -2,6 +2,7 @@ // Licensed under the Six Labors Split License. using System.Numerics; +using System.Runtime.CompilerServices; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Tests.PixelFormats; @@ -21,7 +22,7 @@ public class Rgb24Tests [MemberData(nameof(ColorData))] public void Constructor(byte r, byte g, byte b) { - var p = new Rgb24(r, g, b); + Rgb24 p = new(r, g, b); Assert.Equal(r, p.R); Assert.Equal(g, p.G); @@ -31,7 +32,7 @@ public void Constructor(byte r, byte g, byte b) [Fact] public unsafe void ByteLayoutIsSequentialRgb() { - var color = new Rgb24(1, 2, 3); + Rgb24 color = new(1, 2, 3); byte* ptr = (byte*)&color; Assert.Equal(1, ptr[0]); @@ -43,8 +44,8 @@ public unsafe void ByteLayoutIsSequentialRgb() [MemberData(nameof(ColorData))] public void Equals_WhenTrue(byte r, byte g, byte b) { - var x = new Rgb24(r, g, b); - var y = new Rgb24(r, g, b); + Rgb24 x = new(r, g, b); + Rgb24 y = new(r, g, b); Assert.True(x.Equals(y)); Assert.True(x.Equals((object)y)); @@ -57,8 +58,8 @@ public void Equals_WhenTrue(byte r, byte g, byte b) [InlineData(1, 255, 0, 0, 255, 0)] public void Equals_WhenFalse(byte r1, byte g1, byte b1, byte r2, byte g2, byte b2) { - var a = new Rgb24(r1, g1, b1); - var b = new Rgb24(r2, g2, b2); + Rgb24 a = new(r1, g1, b1); + Rgb24 b = new(r2, g2, b2); Assert.False(a.Equals(b)); Assert.False(a.Equals((object)b)); @@ -67,8 +68,7 @@ public void Equals_WhenFalse(byte r1, byte g1, byte b1, byte r2, byte g2, byte b [Fact] public void FromRgba32() { - var rgb = default(Rgb24); - rgb.FromRgba32(new Rgba32(1, 2, 3, 4)); + Rgb24 rgb = Rgb24.FromRgba32(new Rgba32(1, 2, 3, 4)); Assert.Equal(1, rgb.R); Assert.Equal(2, rgb.G); @@ -84,8 +84,7 @@ public void FromRgba32() [Fact] public void FromVector4() { - var rgb = default(Rgb24); - rgb.FromVector4(Vec(1, 2, 3, 4)); + Rgb24 rgb = Rgb24.FromVector4(Vec(1, 2, 3, 4)); Assert.Equal(1, rgb.R); Assert.Equal(2, rgb.G); @@ -95,7 +94,7 @@ public void FromVector4() [Fact] public void ToVector4() { - var rgb = new Rgb24(1, 2, 3); + Rgb24 rgb = new(1, 2, 3); Assert.Equal(Vec(1, 2, 3), rgb.ToVector4()); } @@ -104,12 +103,11 @@ public void ToVector4() public void ToRgba32() { // arrange - var rgb = new Rgb24(1, 2, 3); - Rgba32 rgba = default; - var expected = new Rgba32(1, 2, 3, 255); + Rgb24 rgb = new(1, 2, 3); + Rgba32 expected = new(1, 2, 3, 255); // act - rgb.ToRgba32(ref rgba); + Rgba32 rgba = rgb.ToRgba32(); // assert Assert.Equal(expected, rgba); @@ -118,15 +116,29 @@ public void ToRgba32() [Fact] public void Rgb24_FromBgra5551() { - // arrange - var rgb = new Rgb24(255, 255, 255); - // act - rgb.FromBgra5551(new Bgra5551(1.0f, 1.0f, 1.0f, 1.0f)); + Rgb24 rgb = Rgb24.FromBgra5551(new Bgra5551(1.0f, 1.0f, 1.0f, 1.0f)); // assert Assert.Equal(255, rgb.R); Assert.Equal(255, rgb.G); Assert.Equal(255, rgb.B); } + + [Fact] + public void Rgb24_PixelInformation() + { + PixelTypeInfo info = Rgb24.GetPixelTypeInfo(); + Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); + Assert.Equal(PixelAlphaRepresentation.None, info.AlphaRepresentation); + Assert.Equal(PixelColorType.RGB, info.ColorType); + + PixelComponentInfo componentInfo = info.ComponentInfo.Value; + Assert.Equal(3, componentInfo.ComponentCount); + Assert.Equal(0, componentInfo.Padding); + Assert.Equal(8, componentInfo.GetComponentPrecision(0)); + Assert.Equal(8, componentInfo.GetComponentPrecision(1)); + Assert.Equal(8, componentInfo.GetComponentPrecision(2)); + Assert.Equal(8, componentInfo.GetMaximumComponentPrecision()); + } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs index d8a61940b2..764627ee34 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs @@ -2,6 +2,7 @@ // Licensed under the Six Labors Split License. using System.Numerics; +using System.Runtime.CompilerServices; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Tests.PixelFormats; @@ -12,7 +13,7 @@ public class Rgb48Tests [Fact] public void Rgb48_Values() { - var rgb = new Rgba64(5243, 9830, 19660, 29491); + Rgba64 rgb = new(5243, 9830, 19660, 29491); Assert.Equal(5243, rgb.R); Assert.Equal(9830, rgb.G); @@ -32,13 +33,12 @@ public void Rgb48_ToScaledVector4() public void Rgb48_FromScaledVector4() { // arrange - var pixel = default(Rgb48); - var short3 = new Rgb48(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue); - var expected = new Rgb48(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue); + Rgb48 short3 = new(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue); + Rgb48 expected = new(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue); // act Vector4 scaled = short3.ToScaledVector4(); - pixel.FromScaledVector4(scaled); + Rgb48 pixel = Rgb48.FromScaledVector4(scaled); // assert Assert.Equal(expected, pixel); @@ -48,12 +48,11 @@ public void Rgb48_FromScaledVector4() public void Rgb48_ToRgba32() { // arrange - var rgba48 = new Rgb48(5140, 9766, 19532); - var expected = new Rgba32(20, 38, 76, 255); + Rgb48 rgba48 = new(5140, 9766, 19532); + Rgba32 expected = new(20, 38, 76, 255); // act - Rgba32 actual = default; - rgba48.ToRgba32(ref actual); + Rgba32 actual = rgba48.ToRgba32(); // assert Assert.Equal(expected, actual); @@ -63,15 +62,31 @@ public void Rgb48_ToRgba32() public void Rgb48_FromBgra5551() { // arrange - var rgb = default(Rgb48); - ushort expected = ushort.MaxValue; + const ushort expected = ushort.MaxValue; // act - rgb.FromBgra5551(new Bgra5551(1.0f, 1.0f, 1.0f, 1.0f)); + Rgb48 rgb = Rgb48.FromBgra5551(new Bgra5551(1f, 1f, 1f, 1f)); // assert Assert.Equal(expected, rgb.R); Assert.Equal(expected, rgb.G); Assert.Equal(expected, rgb.B); } + + [Fact] + public void Rgb48_PixelInformation() + { + PixelTypeInfo info = Rgb48.GetPixelTypeInfo(); + Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); + Assert.Equal(PixelAlphaRepresentation.None, info.AlphaRepresentation); + Assert.Equal(PixelColorType.RGB, info.ColorType); + + PixelComponentInfo componentInfo = info.ComponentInfo.Value; + Assert.Equal(3, componentInfo.ComponentCount); + Assert.Equal(0, componentInfo.Padding); + Assert.Equal(16, componentInfo.GetComponentPrecision(0)); + Assert.Equal(16, componentInfo.GetComponentPrecision(1)); + Assert.Equal(16, componentInfo.GetComponentPrecision(2)); + Assert.Equal(16, componentInfo.GetMaximumComponentPrecision()); + } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgba1010102Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgba1010102Tests.cs index 0c28b35c69..79a1aefc9c 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgba1010102Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgba1010102Tests.cs @@ -2,6 +2,7 @@ // Licensed under the Six Labors Split License. using System.Numerics; +using System.Runtime.CompilerServices; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Tests.PixelFormats; @@ -15,10 +16,10 @@ public class Rgba1010102Tests [Fact] public void AreEqual() { - var color1 = new Rgba1010102(0.0f, 0.0f, 0.0f, 0.0f); - var color2 = new Rgba1010102(new Vector4(0.0f)); - var color3 = new Rgba1010102(new Vector4(1.0f, 0.0f, 1.0f, 1.0f)); - var color4 = new Rgba1010102(1.0f, 0.0f, 1.0f, 1.0f); + Rgba1010102 color1 = new(0.0f, 0.0f, 0.0f, 0.0f); + Rgba1010102 color2 = new(new Vector4(0.0f)); + Rgba1010102 color3 = new(new Vector4(1f, 0.0f, 1f, 1f)); + Rgba1010102 color4 = new(1f, 0.0f, 1f, 1f); Assert.Equal(color1, color2); Assert.Equal(color3, color4); @@ -30,10 +31,10 @@ public void AreEqual() [Fact] public void AreNotEqual() { - var color1 = new Rgba1010102(0.0f, 0.0f, 0.0f, 0.0f); - var color2 = new Rgba1010102(new Vector4(1.0f)); - var color3 = new Rgba1010102(new Vector4(1.0f, 0.0f, 0.0f, 1.0f)); - var color4 = new Rgba1010102(1.0f, 1.0f, 0.0f, 1.0f); + Rgba1010102 color1 = new(0.0f, 0.0f, 0.0f, 0.0f); + Rgba1010102 color2 = new(new Vector4(1f)); + Rgba1010102 color3 = new(new Vector4(1f, 0.0f, 0.0f, 1f)); + Rgba1010102 color4 = new(1f, 1f, 0.0f, 1f); Assert.NotEqual(color1, color2); Assert.NotEqual(color3, color4); @@ -42,10 +43,10 @@ public void AreNotEqual() [Fact] public void Rgba1010102_PackedValue() { - float x = 0x2db; - float y = 0x36d; - float z = 0x3b7; - float w = 0x1; + const float x = 0x2db; + const float y = 0x36d; + const float z = 0x3b7; + const float w = 0x1; Assert.Equal(0x7B7DB6DBU, new Rgba1010102(x / 0x3ff, y / 0x3ff, z / 0x3ff, w / 3).PackedValue); Assert.Equal(536871014U, new Rgba1010102(0.1f, -0.3f, 0.5f, -0.7f).PackedValue); @@ -66,7 +67,7 @@ public void Rgba1010102_ToVector4() public void Rgba1010102_ToScaledVector4() { // arrange - var rgba = new Rgba1010102(Vector4.One); + Rgba1010102 rgba = new(Vector4.One); // act Vector4 actual = rgba.ToScaledVector4(); @@ -82,13 +83,12 @@ public void Rgba1010102_ToScaledVector4() public void Rgba1010102_FromScaledVector4() { // arrange - var rgba = new Rgba1010102(Vector4.One); - var actual = default(Rgba1010102); - uint expected = 0xFFFFFFFF; + Rgba1010102 rgba = new(Vector4.One); + const uint expected = 0xFFFFFFFF; // act Vector4 scaled = rgba.ToScaledVector4(); - actual.FromScaledVector4(scaled); + Rgba1010102 actual = Rgba1010102.FromScaledVector4(scaled); // assert Assert.Equal(expected, actual.PackedValue); @@ -98,11 +98,10 @@ public void Rgba1010102_FromScaledVector4() public void Rgba1010102_FromBgra5551() { // arrange - var rgba = new Rgba1010102(Vector4.One); - uint expected = 0xFFFFFFFF; + const uint expected = 0xFFFFFFFF; // act - rgba.FromBgra5551(new Bgra5551(1.0f, 1.0f, 1.0f, 1.0f)); + Rgba1010102 rgba = Rgba1010102.FromBgra5551(new Bgra5551(1f, 1f, 1f, 1f)); // assert Assert.Equal(expected, rgba.PackedValue); @@ -112,11 +111,10 @@ public void Rgba1010102_FromBgra5551() public void Rgba1010102_FromArgb32() { // arrange - var rgba = default(Rgba1010102); - uint expectedPackedValue = uint.MaxValue; + const uint expectedPackedValue = uint.MaxValue; // act - rgba.FromArgb32(new Argb32(255, 255, 255, 255)); + Rgba1010102 rgba = Rgba1010102.FromArgb32(new Argb32(255, 255, 255, 255)); // assert Assert.Equal(expectedPackedValue, rgba.PackedValue); @@ -126,14 +124,12 @@ public void Rgba1010102_FromArgb32() public void Rgba1010102_FromRgba32() { // arrange - var rgba1 = default(Rgba1010102); - var rgba2 = default(Rgba1010102); - uint expectedPackedValue1 = uint.MaxValue; - uint expectedPackedValue2 = 0xFFF003FF; + const uint expectedPackedValue1 = uint.MaxValue; + const uint expectedPackedValue2 = 0xFFF003FF; // act - rgba1.FromRgba32(new Rgba32(255, 255, 255, 255)); - rgba2.FromRgba32(new Rgba32(255, 0, 255, 255)); + Rgba1010102 rgba1 = Rgba1010102.FromRgba32(new Rgba32(255, 255, 255, 255)); + Rgba1010102 rgba2 = Rgba1010102.FromRgba32(new Rgba32(255, 0, 255, 255)); // assert Assert.Equal(expectedPackedValue1, rgba1.PackedValue); @@ -144,11 +140,10 @@ public void Rgba1010102_FromRgba32() public void Rgba1010102_FromBgr24() { // arrange - var rgba = default(Rgba1010102); - uint expectedPackedValue = uint.MaxValue; + const uint expectedPackedValue = uint.MaxValue; // act - rgba.FromBgr24(new Bgr24(byte.MaxValue, byte.MaxValue, byte.MaxValue)); + Rgba1010102 rgba = Rgba1010102.FromBgr24(new Bgr24(byte.MaxValue, byte.MaxValue, byte.MaxValue)); // assert Assert.Equal(expectedPackedValue, rgba.PackedValue); @@ -158,11 +153,10 @@ public void Rgba1010102_FromBgr24() public void Rgba1010102_FromGrey8() { // arrange - var rgba = default(Rgba1010102); - uint expectedPackedValue = uint.MaxValue; + const uint expectedPackedValue = uint.MaxValue; // act - rgba.FromL8(new L8(byte.MaxValue)); + Rgba1010102 rgba = Rgba1010102.FromL8(new L8(byte.MaxValue)); // assert Assert.Equal(expectedPackedValue, rgba.PackedValue); @@ -172,11 +166,10 @@ public void Rgba1010102_FromGrey8() public void Rgba1010102_FromGrey16() { // arrange - var rgba = default(Rgba1010102); - uint expectedPackedValue = uint.MaxValue; + const uint expectedPackedValue = uint.MaxValue; // act - rgba.FromL16(new L16(ushort.MaxValue)); + Rgba1010102 rgba = Rgba1010102.FromL16(new L16(ushort.MaxValue)); // assert Assert.Equal(expectedPackedValue, rgba.PackedValue); @@ -186,11 +179,10 @@ public void Rgba1010102_FromGrey16() public void Rgba1010102_FromRgb24() { // arrange - var rgba = default(Rgba1010102); - uint expectedPackedValue = uint.MaxValue; + const uint expectedPackedValue = uint.MaxValue; // act - rgba.FromRgb24(new Rgb24(byte.MaxValue, byte.MaxValue, byte.MaxValue)); + Rgba1010102 rgba = Rgba1010102.FromRgb24(new Rgb24(byte.MaxValue, byte.MaxValue, byte.MaxValue)); // assert Assert.Equal(expectedPackedValue, rgba.PackedValue); @@ -200,11 +192,10 @@ public void Rgba1010102_FromRgb24() public void Rgba1010102_FromRgb48() { // arrange - var rgba = default(Rgba1010102); - uint expectedPackedValue = uint.MaxValue; + const uint expectedPackedValue = uint.MaxValue; // act - rgba.FromRgb48(new Rgb48(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue)); + Rgba1010102 rgba = Rgba1010102.FromRgb48(new Rgb48(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue)); // assert Assert.Equal(expectedPackedValue, rgba.PackedValue); @@ -214,11 +205,10 @@ public void Rgba1010102_FromRgb48() public void Rgba1010102_FromRgba64() { // arrange - var rgba = default(Rgba1010102); - uint expectedPackedValue = uint.MaxValue; + const uint expectedPackedValue = uint.MaxValue; // act - rgba.FromRgba64(new Rgba64(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue, ushort.MaxValue)); + Rgba1010102 rgba = Rgba1010102.FromRgba64(new Rgba64(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue, ushort.MaxValue)); // assert Assert.Equal(expectedPackedValue, rgba.PackedValue); @@ -235,14 +225,31 @@ public void Rgba1010102_Clamping() public void Rgba1010102_ToRgba32() { // arrange - var rgba = new Rgba1010102(0.1f, -0.3f, 0.5f, -0.7f); - var expected = new Rgba32(25, 0, 128, 0); + Rgba1010102 rgba = new(0.1f, -0.3f, 0.5f, -0.7f); + Rgba32 expected = new(25, 0, 128, 0); // act - Rgba32 actual = default; - rgba.ToRgba32(ref actual); + Rgba32 actual = rgba.ToRgba32(); // assert Assert.Equal(expected, actual); } + + [Fact] + public void Rgba1010102_PixelInformation() + { + PixelTypeInfo info = Rgba1010102.GetPixelTypeInfo(); + Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); + Assert.Equal(PixelAlphaRepresentation.Unassociated, info.AlphaRepresentation); + Assert.Equal(PixelColorType.RGB | PixelColorType.Alpha, info.ColorType); + + PixelComponentInfo componentInfo = info.ComponentInfo.Value; + Assert.Equal(4, componentInfo.ComponentCount); + Assert.Equal(0, componentInfo.Padding); + Assert.Equal(10, componentInfo.GetComponentPrecision(0)); + Assert.Equal(10, componentInfo.GetComponentPrecision(1)); + Assert.Equal(10, componentInfo.GetComponentPrecision(2)); + Assert.Equal(2, componentInfo.GetComponentPrecision(3)); + Assert.Equal(10, componentInfo.GetMaximumComponentPrecision()); + } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgba32Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgba32Tests.cs index 64903f65bb..6d56185ecf 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgba32Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgba32Tests.cs @@ -2,6 +2,7 @@ // Licensed under the Six Labors Split License. using System.Numerics; +using System.Runtime.CompilerServices; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Tests.PixelFormats; @@ -18,12 +19,12 @@ public class Rgba32Tests [Fact] public void AreEqual() { - var color1 = new Rgba32(0, 0, 0); - var color2 = new Rgba32(0, 0, 0, 1F); - var color3 = Rgba32.ParseHex("#000"); - var color4 = Rgba32.ParseHex("#000F"); - var color5 = Rgba32.ParseHex("#000000"); - var color6 = Rgba32.ParseHex("#000000FF"); + Rgba32 color1 = new(0, 0, 0); + Rgba32 color2 = new(0, 0, 0, 1F); + Rgba32 color3 = Rgba32.ParseHex("#000"); + Rgba32 color4 = Rgba32.ParseHex("#000F"); + Rgba32 color5 = Rgba32.ParseHex("#000000"); + Rgba32 color6 = Rgba32.ParseHex("#000000FF"); Assert.Equal(color1, color2); Assert.Equal(color1, color3); @@ -38,11 +39,11 @@ public void AreEqual() [Fact] public void AreNotEqual() { - var color1 = new Rgba32(255, 0, 0, 255); - var color2 = new Rgba32(0, 0, 0, 255); - var color3 = Rgba32.ParseHex("#000"); - var color4 = Rgba32.ParseHex("#000000"); - var color5 = Rgba32.ParseHex("#FF000000"); + Rgba32 color1 = new(255, 0, 0, 255); + Rgba32 color2 = new(0, 0, 0, 255); + Rgba32 color3 = Rgba32.ParseHex("#000"); + Rgba32 color4 = Rgba32.ParseHex("#000000"); + Rgba32 color5 = Rgba32.ParseHex("#FF000000"); Assert.NotEqual(color1, color2); Assert.NotEqual(color1, color3); @@ -56,25 +57,25 @@ public void AreNotEqual() [Fact] public void ConstructorAssignsProperties() { - var color1 = new Rgba32(1, .1f, .133f, .864f); + Rgba32 color1 = new(1, .1f, .133f, .864f); Assert.Equal(255, color1.R); Assert.Equal((byte)Math.Round(.1f * 255), color1.G); Assert.Equal((byte)Math.Round(.133f * 255), color1.B); Assert.Equal((byte)Math.Round(.864f * 255), color1.A); - var color2 = new Rgba32(1, .1f, .133f); + Rgba32 color2 = new(1, .1f, .133f); Assert.Equal(255, color2.R); Assert.Equal(Math.Round(.1f * 255), color2.G); Assert.Equal(Math.Round(.133f * 255), color2.B); Assert.Equal(255, color2.A); - var color4 = new Rgba32(new Vector3(1, .1f, .133f)); + Rgba32 color4 = new(new Vector3(1, .1f, .133f)); Assert.Equal(255, color4.R); Assert.Equal(Math.Round(.1f * 255), color4.G); Assert.Equal(Math.Round(.133f * 255), color4.B); Assert.Equal(255, color4.A); - var color5 = new Rgba32(new Vector4(1, .1f, .133f, .5f)); + Rgba32 color5 = new(new Vector4(1, .1f, .133f, .5f)); Assert.Equal(255, color5.R); Assert.Equal(Math.Round(.1f * 255), color5.G); Assert.Equal(Math.Round(.133f * 255), color5.B); @@ -88,7 +89,7 @@ public void ConstructorAssignsProperties() public void FromAndToHex() { // 8 digit hex matches css4 spec. RRGGBBAA - var color = Rgba32.ParseHex("#AABBCCDD"); // 170, 187, 204, 221 + Rgba32 color = Rgba32.ParseHex("#AABBCCDD"); // 170, 187, 204, 221 Assert.Equal(170, color.R); Assert.Equal(187, color.G); Assert.Equal(204, color.B); @@ -111,7 +112,7 @@ public void FromAndToHex() [Fact] public unsafe void ByteLayout() { - var color = new Rgba32(1, 2, 3, 4); + Rgba32 color = new(1, 2, 3, 4); byte* colorBase = (byte*)&color; Assert.Equal(1, colorBase[0]); Assert.Equal(2, colorBase[1]); @@ -146,7 +147,7 @@ public void Rgba32_ToVector4() public void Rgba32_ToScaledVector4() { // arrange - var rgba = new Rgba32(Vector4.One); + Rgba32 rgba = new(Vector4.One); // act Vector4 actual = rgba.ToScaledVector4(); @@ -162,13 +163,12 @@ public void Rgba32_ToScaledVector4() public void Rgba32_FromScaledVector4() { // arrange - var rgba = new Rgba32(Vector4.One); - var actual = default(Rgba32); - uint expected = 0xFFFFFFFF; + Rgba32 rgba = new(Vector4.One); + const uint expected = 0xFFFFFFFF; // act Vector4 scaled = rgba.ToScaledVector4(); - actual.FromScaledVector4(scaled); + Rgba32 actual = Rgba32.FromScaledVector4(scaled); // assert Assert.Equal(expected, actual.PackedValue); @@ -185,12 +185,11 @@ public void Rgba32_Clamping() public void Rgba32_ToRgba32() { // arrange - var rgba = new Rgba32(+0.1f, -0.3f, +0.5f, -0.7f); - var actual = default(Rgba32); - var expected = new Rgba32(0x1a, 0, 0x80, 0); + Rgba32 rgba = new(+0.1f, -0.3f, +0.5f, -0.7f); + Rgba32 expected = new(0x1a, 0, 0x80, 0); // act - actual.FromRgba32(rgba); + Rgba32 actual = Rgba32.FromRgba32(rgba); // assert Assert.Equal(expected, actual); @@ -200,13 +199,11 @@ public void Rgba32_ToRgba32() public void Rgba32_FromRgba32_ToRgba32() { // arrange - var rgba = default(Rgba32); - var actual = default(Rgba32); - var expected = new Rgba32(0x1a, 0, 0x80, 0); + Rgba32 expected = new(0x1a, 0, 0x80, 0); // act - rgba.FromRgba32(expected); - actual.FromRgba32(rgba); + Rgba32 rgba = Rgba32.FromRgba32(expected); + Rgba32 actual = Rgba32.FromRgba32(rgba); // assert Assert.Equal(expected, actual); @@ -216,13 +213,11 @@ public void Rgba32_FromRgba32_ToRgba32() public void Rgba32_FromBgra32_ToRgba32() { // arrange - var rgba = default(Rgba32); - var actual = default(Bgra32); - var expected = new Bgra32(0x1a, 0, 0x80, 0); + Bgra32 expected = new(0x1a, 0, 0x80, 0); // act - rgba.FromBgra32(expected); - actual.FromRgba32(rgba); + Rgba32 rgba = Rgba32.FromBgra32(expected); + Bgra32 actual = Bgra32.FromRgba32(rgba); // assert Assert.Equal(expected, actual); @@ -232,13 +227,11 @@ public void Rgba32_FromBgra32_ToRgba32() public void Rgba32_FromAbgr32_ToRgba32() { // arrange - var rgba = default(Rgba32); - var actual = default(Abgr32); - var expected = new Abgr32(0x1a, 0, 0x80, 0); + Abgr32 expected = new(0x1a, 0, 0x80, 0); // act - rgba.FromAbgr32(expected); - actual.FromRgba32(rgba); + Rgba32 rgba = Rgba32.FromAbgr32(expected); + Abgr32 actual = Abgr32.FromRgba32(rgba); // assert Assert.Equal(expected, actual); @@ -248,13 +241,11 @@ public void Rgba32_FromAbgr32_ToRgba32() public void Rgba32_FromArgb32_ToArgb32() { // arrange - var rgba = default(Rgba32); - var actual = default(Argb32); - var expected = new Argb32(0x1a, 0, 0x80, 0); + Argb32 expected = new(0x1a, 0, 0x80, 0); // act - rgba.FromArgb32(expected); - actual.FromRgba32(rgba); + Rgba32 rgba = Rgba32.FromArgb32(expected); + Argb32 actual = Argb32.FromRgba32(rgba); // assert Assert.Equal(expected, actual); @@ -264,13 +255,11 @@ public void Rgba32_FromArgb32_ToArgb32() public void Rgba32_FromRgb48() { // arrange - var input = default(Rgba32); - var actual = default(Rgb48); - var expected = new Rgb48(65535, 0, 65535); + Rgb48 expected = new(65535, 0, 65535); // act - input.FromRgb48(expected); - actual.FromScaledVector4(input.ToScaledVector4()); + Rgba32 input = Rgba32.FromRgb48(expected); + Rgb48 actual = Rgb48.FromScaledVector4(input.ToScaledVector4()); // assert Assert.Equal(expected, actual); @@ -280,13 +269,11 @@ public void Rgba32_FromRgb48() public void Rgba32_FromRgba64() { // arrange - var input = default(Rgba32); - var actual = default(Rgba64); - var expected = new Rgba64(65535, 0, 65535, 0); + Rgba64 expected = new(65535, 0, 65535, 0); // act - input.FromRgba64(expected); - actual.FromScaledVector4(input.ToScaledVector4()); + Rgba32 input = Rgba32.FromRgba64(expected); + Rgba64 actual = Rgba64.FromScaledVector4(input.ToScaledVector4()); // assert Assert.Equal(expected, actual); @@ -296,13 +283,30 @@ public void Rgba32_FromRgba64() public void Rgba32_FromBgra5551() { // arrange - var rgb = default(Rgba32); - uint expected = 0xFFFFFFFF; + const uint expected = 0xFFFFFFFF; // act - rgb.FromBgra5551(new Bgra5551(1.0f, 1.0f, 1.0f, 1.0f)); + Rgba32 rgb = Rgba32.FromBgra5551(new Bgra5551(1f, 1f, 1f, 1f)); // assert Assert.Equal(expected, rgb.PackedValue); } + + [Fact] + public void Rgba32_PixelInformation() + { + PixelTypeInfo info = Rgba32.GetPixelTypeInfo(); + Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); + Assert.Equal(PixelAlphaRepresentation.Unassociated, info.AlphaRepresentation); + Assert.Equal(PixelColorType.RGB | PixelColorType.Alpha, info.ColorType); + + PixelComponentInfo componentInfo = info.ComponentInfo.Value; + Assert.Equal(4, componentInfo.ComponentCount); + Assert.Equal(0, componentInfo.Padding); + Assert.Equal(8, componentInfo.GetComponentPrecision(0)); + Assert.Equal(8, componentInfo.GetComponentPrecision(1)); + Assert.Equal(8, componentInfo.GetComponentPrecision(2)); + Assert.Equal(8, componentInfo.GetComponentPrecision(3)); + Assert.Equal(8, componentInfo.GetMaximumComponentPrecision()); + } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs index f60ed8a529..694d0ace10 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs @@ -2,6 +2,7 @@ // Licensed under the Six Labors Split License. using System.Numerics; +using System.Runtime.CompilerServices; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Tests.PixelFormats; @@ -38,7 +39,7 @@ public void Rgba64_ToVector4() public void Rgba64_ToScaledVector4(ushort r, ushort g, ushort b, ushort a) { // arrange - var short2 = new Rgba64(r, g, b, a); + Rgba64 short2 = new(r, g, b, a); float max = ushort.MaxValue; float rr = r / max; @@ -63,13 +64,12 @@ public void Rgba64_ToScaledVector4(ushort r, ushort g, ushort b, ushort a) public void Rgba64_FromScaledVector4(ushort r, ushort g, ushort b, ushort a) { // arrange - var source = new Rgba64(r, g, b, a); + Rgba64 source = new(r, g, b, a); // act Vector4 scaled = source.ToScaledVector4(); - Rgba64 actual = default; - actual.FromScaledVector4(scaled); + Rgba64 actual = Rgba64.FromScaledVector4(scaled); // assert Assert.Equal(source, actual); @@ -78,10 +78,9 @@ public void Rgba64_FromScaledVector4(ushort r, ushort g, ushort b, ushort a) [Fact] public void Rgba64_Clamping() { - var zero = default(Rgba64); - var one = default(Rgba64); - zero.FromVector4(Vector4.One * -1234.0f); - one.FromVector4(Vector4.One * 1234.0f); + Rgba64 zero = Rgba64.FromVector4(Vector4.One * -1234.0f); + Rgba64 one = Rgba64.FromVector4(Vector4.One * 1234.0f); + Assert.Equal(Vector4.Zero, zero.ToVector4()); Assert.Equal(Vector4.One, one.ToVector4()); } @@ -90,12 +89,11 @@ public void Rgba64_Clamping() public void Rgba64_ToRgba32() { // arrange - var rgba64 = new Rgba64(5140, 9766, 19532, 29555); - var actual = default(Rgba32); - var expected = new Rgba32(20, 38, 76, 115); + Rgba64 rgba64 = new(5140, 9766, 19532, 29555); + Rgba32 expected = new(20, 38, 76, 115); // act - rgba64.ToRgba32(ref actual); + Rgba32 actual = rgba64.ToRgba32(); // assert Assert.Equal(expected, actual); @@ -105,11 +103,10 @@ public void Rgba64_ToRgba32() public void Rgba64_FromBgra5551() { // arrange - var rgba = default(Rgba64); - ushort expected = ushort.MaxValue; + const ushort expected = ushort.MaxValue; // act - rgba.FromBgra5551(new Bgra5551(1.0f, 1.0f, 1.0f, 1.0f)); + Rgba64 rgba = Rgba64.FromBgra5551(new Bgra5551(1.0f, 1.0f, 1.0f, 1.0f)); // assert Assert.Equal(expected, rgba.R); @@ -121,8 +118,8 @@ public void Rgba64_FromBgra5551() [Fact] public void Equality_WhenTrue() { - var c1 = new Rgba64(100, 2000, 3000, 40000); - var c2 = new Rgba64(100, 2000, 3000, 40000); + Rgba64 c1 = new(100, 2000, 3000, 40000); + Rgba64 c2 = new(100, 2000, 3000, 40000); Assert.True(c1.Equals(c2)); Assert.True(c1.GetHashCode() == c2.GetHashCode()); @@ -131,9 +128,9 @@ public void Equality_WhenTrue() [Fact] public void Equality_WhenFalse() { - var c1 = new Rgba64(100, 2000, 3000, 40000); - var c2 = new Rgba64(101, 2000, 3000, 40000); - var c3 = new Rgba64(100, 2000, 3000, 40001); + Rgba64 c1 = new(100, 2000, 3000, 40000); + Rgba64 c2 = new(101, 2000, 3000, 40000); + Rgba64 c3 = new(100, 2000, 3000, 40001); Assert.False(c1.Equals(c2)); Assert.False(c2.Equals(c3)); @@ -143,11 +140,10 @@ public void Equality_WhenFalse() [Fact] public void Rgba64_FromRgba32() { - var source = new Rgba32(20, 38, 76, 115); - var expected = new Rgba64(5140, 9766, 19532, 29555); + Rgba32 source = new(20, 38, 76, 115); + Rgba64 expected = new(5140, 9766, 19532, 29555); - Rgba64 actual = default; - actual.FromRgba32(source); + Rgba64 actual = Rgba64.FromRgba32(source); Assert.Equal(expected, actual); } @@ -155,9 +151,9 @@ public void Rgba64_FromRgba32() [Fact] public void ConstructFrom_Rgba32() { - var expected = new Rgba64(5140, 9766, 19532, 29555); - var source = new Rgba32(20, 38, 76, 115); - var actual = new Rgba64(source); + Rgba64 expected = new(5140, 9766, 19532, 29555); + Rgba32 source = new(20, 38, 76, 115); + Rgba64 actual = new(source); Assert.Equal(expected, actual); } @@ -165,9 +161,9 @@ public void ConstructFrom_Rgba32() [Fact] public void ConstructFrom_Bgra32() { - var expected = new Rgba64(5140, 9766, 19532, 29555); - var source = new Bgra32(20, 38, 76, 115); - var actual = new Rgba64(source); + Rgba64 expected = new(5140, 9766, 19532, 29555); + Bgra32 source = new(20, 38, 76, 115); + Rgba64 actual = new(source); Assert.Equal(expected, actual); } @@ -175,9 +171,9 @@ public void ConstructFrom_Bgra32() [Fact] public void ConstructFrom_Argb32() { - var expected = new Rgba64(5140, 9766, 19532, 29555); - var source = new Argb32(20, 38, 76, 115); - var actual = new Rgba64(source); + Rgba64 expected = new(5140, 9766, 19532, 29555); + Argb32 source = new(20, 38, 76, 115); + Rgba64 actual = new(source); Assert.Equal(expected, actual); } @@ -185,9 +181,9 @@ public void ConstructFrom_Argb32() [Fact] public void ConstructFrom_Abgr32() { - var expected = new Rgba64(5140, 9766, 19532, 29555); - var source = new Abgr32(20, 38, 76, 115); - var actual = new Rgba64(source); + Rgba64 expected = new(5140, 9766, 19532, 29555); + Abgr32 source = new(20, 38, 76, 115); + Rgba64 actual = new(source); Assert.Equal(expected, actual); } @@ -195,9 +191,9 @@ public void ConstructFrom_Abgr32() [Fact] public void ConstructFrom_Rgb24() { - var expected = new Rgba64(5140, 9766, 19532, ushort.MaxValue); - var source = new Rgb24(20, 38, 76); - var actual = new Rgba64(source); + Rgba64 expected = new(5140, 9766, 19532, ushort.MaxValue); + Rgb24 source = new(20, 38, 76); + Rgba64 actual = new(source); Assert.Equal(expected, actual); } @@ -205,9 +201,9 @@ public void ConstructFrom_Rgb24() [Fact] public void ConstructFrom_Bgr24() { - var expected = new Rgba64(5140, 9766, 19532, ushort.MaxValue); - var source = new Bgr24(20, 38, 76); - var actual = new Rgba64(source); + Rgba64 expected = new(5140, 9766, 19532, ushort.MaxValue); + Bgr24 source = new(20, 38, 76); + Rgba64 actual = new(source); Assert.Equal(expected, actual); } @@ -215,11 +211,10 @@ public void ConstructFrom_Bgr24() [Fact] public void ConstructFrom_Vector4() { - var source = new Vector4(0f, 0.2f, 0.5f, 1f); - Rgba64 expected = default; - expected.FromScaledVector4(source); + Vector4 source = new(0f, 0.2f, 0.5f, 1f); + Rgba64 expected = Rgba64.FromScaledVector4(source); - var actual = new Rgba64(source); + Rgba64 actual = new(source); Assert.Equal(expected, actual); } @@ -228,11 +223,11 @@ public void ConstructFrom_Vector4() public void ToRgba32_Retval() { // arrange - var source = new Rgba64(5140, 9766, 19532, 29555); - var expected = new Rgba32(20, 38, 76, 115); + Rgba64 source = new(5140, 9766, 19532, 29555); + Rgba32 expected = new(20, 38, 76, 115); // act - var actual = source.ToRgba32(); + Rgba32 actual = source.ToRgba32(); // assert Assert.Equal(expected, actual); @@ -242,11 +237,11 @@ public void ToRgba32_Retval() public void ToBgra32_Retval() { // arrange - var source = new Rgba64(5140, 9766, 19532, 29555); - var expected = new Bgra32(20, 38, 76, 115); + Rgba64 source = new(5140, 9766, 19532, 29555); + Bgra32 expected = new(20, 38, 76, 115); // act - var actual = source.ToBgra32(); + Bgra32 actual = source.ToBgra32(); // assert Assert.Equal(expected, actual); @@ -256,11 +251,11 @@ public void ToBgra32_Retval() public void ToArgb32_Retval() { // arrange - var source = new Rgba64(5140, 9766, 19532, 29555); - var expected = new Argb32(20, 38, 76, 115); + Rgba64 source = new(5140, 9766, 19532, 29555); + Argb32 expected = new(20, 38, 76, 115); // act - var actual = source.ToArgb32(); + Argb32 actual = source.ToArgb32(); // assert Assert.Equal(expected, actual); @@ -270,11 +265,11 @@ public void ToArgb32_Retval() public void ToAbgr32_Retval() { // arrange - var source = new Rgba64(5140, 9766, 19532, 29555); - var expected = new Abgr32(20, 38, 76, 115); + Rgba64 source = new(5140, 9766, 19532, 29555); + Abgr32 expected = new(20, 38, 76, 115); // act - var actual = source.ToAbgr32(); + Abgr32 actual = source.ToAbgr32(); // assert Assert.Equal(expected, actual); @@ -284,11 +279,11 @@ public void ToAbgr32_Retval() public void ToRgb24_Retval() { // arrange - var source = new Rgba64(5140, 9766, 19532, 29555); - var expected = new Rgb24(20, 38, 76); + Rgba64 source = new(5140, 9766, 19532, 29555); + Rgb24 expected = new(20, 38, 76); // act - var actual = source.ToRgb24(); + Rgb24 actual = source.ToRgb24(); // assert Assert.Equal(expected, actual); @@ -298,13 +293,31 @@ public void ToRgb24_Retval() public void ToBgr24_Retval() { // arrange - var source = new Rgba64(5140, 9766, 19532, 29555); - var expected = new Bgr24(20, 38, 76); + Rgba64 source = new(5140, 9766, 19532, 29555); + Bgr24 expected = new(20, 38, 76); // act - var actual = source.ToBgr24(); + Bgr24 actual = source.ToBgr24(); // assert Assert.Equal(expected, actual); } + + [Fact] + public void Rgba64_PixelInformation() + { + PixelTypeInfo info = Rgba64.GetPixelTypeInfo(); + Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); + Assert.Equal(PixelAlphaRepresentation.Unassociated, info.AlphaRepresentation); + Assert.Equal(PixelColorType.RGB | PixelColorType.Alpha, info.ColorType); + + PixelComponentInfo componentInfo = info.ComponentInfo.Value; + Assert.Equal(4, componentInfo.ComponentCount); + Assert.Equal(0, componentInfo.Padding); + Assert.Equal(16, componentInfo.GetComponentPrecision(0)); + Assert.Equal(16, componentInfo.GetComponentPrecision(1)); + Assert.Equal(16, componentInfo.GetComponentPrecision(2)); + Assert.Equal(16, componentInfo.GetComponentPrecision(3)); + Assert.Equal(16, componentInfo.GetMaximumComponentPrecision()); + } } diff --git a/tests/ImageSharp.Tests/PixelFormats/RgbaVectorTests.cs b/tests/ImageSharp.Tests/PixelFormats/RgbaVectorTests.cs index ac6d2e3ca5..5273482efb 100644 --- a/tests/ImageSharp.Tests/PixelFormats/RgbaVectorTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/RgbaVectorTests.cs @@ -19,12 +19,12 @@ public class RgbaVectorTests [Fact] public void AreEqual() { - var color1 = new RgbaVector(0, 0, 0F); - var color2 = new RgbaVector(0, 0, 0, 1F); - var color3 = RgbaVector.FromHex("#000"); - var color4 = RgbaVector.FromHex("#000F"); - var color5 = RgbaVector.FromHex("#000000"); - var color6 = RgbaVector.FromHex("#000000FF"); + RgbaVector color1 = new(0, 0, 0F); + RgbaVector color2 = new(0, 0, 0, 1F); + RgbaVector color3 = RgbaVector.FromHex("#000"); + RgbaVector color4 = RgbaVector.FromHex("#000F"); + RgbaVector color5 = RgbaVector.FromHex("#000000"); + RgbaVector color6 = RgbaVector.FromHex("#000000FF"); Assert.Equal(color1, color2); Assert.Equal(color1, color3); @@ -39,11 +39,11 @@ public void AreEqual() [Fact] public void AreNotEqual() { - var color1 = new RgbaVector(1, 0, 0, 1); - var color2 = new RgbaVector(0, 0, 0, 1); - var color3 = RgbaVector.FromHex("#000"); - var color4 = RgbaVector.FromHex("#000000"); - var color5 = RgbaVector.FromHex("#FF000000"); + RgbaVector color1 = new(1, 0, 0, 1); + RgbaVector color2 = new(0, 0, 0, 1); + RgbaVector color3 = RgbaVector.FromHex("#000"); + RgbaVector color4 = RgbaVector.FromHex("#000000"); + RgbaVector color5 = RgbaVector.FromHex("#FF000000"); Assert.NotEqual(color1, color2); Assert.NotEqual(color1, color3); @@ -57,13 +57,13 @@ public void AreNotEqual() [Fact] public void ConstructorAssignsProperties() { - var color1 = new RgbaVector(1, .1F, .133F, .864F); + RgbaVector color1 = new(1, .1F, .133F, .864F); Assert.Equal(1F, color1.R); Assert.Equal(.1F, color1.G); Assert.Equal(.133F, color1.B); Assert.Equal(.864F, color1.A); - var color2 = new RgbaVector(1, .1f, .133f); + RgbaVector color2 = new(1, .1f, .133f); Assert.Equal(1F, color2.R); Assert.Equal(.1F, color2.G); Assert.Equal(.133F, color2.B); @@ -76,7 +76,7 @@ public void ConstructorAssignsProperties() [Fact] public void FromAndToHex() { - var color = RgbaVector.FromHex("#AABBCCDD"); + RgbaVector color = RgbaVector.FromHex("#AABBCCDD"); Assert.Equal(170 / 255F, color.R); Assert.Equal(187 / 255F, color.G); Assert.Equal(204 / 255F, color.B); @@ -104,7 +104,7 @@ public void FromAndToHex() [Fact] public void FloatLayout() { - var color = new RgbaVector(1F, 2, 3, 4); + RgbaVector color = new(1F, 2, 3, 4); Vector4 colorBase = Unsafe.As(ref Unsafe.Add(ref color, 0)); float[] ordered = new float[4]; colorBase.CopyTo(ordered); @@ -119,13 +119,11 @@ public void FloatLayout() public void RgbaVector_FromRgb48() { // arrange - var input = default(RgbaVector); - var actual = default(Rgb48); - var expected = new Rgb48(65535, 0, 65535); + Rgb48 expected = new(65535, 0, 65535); // act - input.FromRgb48(expected); - actual.FromScaledVector4(input.ToScaledVector4()); + RgbaVector input = RgbaVector.FromRgb48(expected); + Rgb48 actual = Rgb48.FromScaledVector4(input.ToScaledVector4()); // assert Assert.Equal(expected, actual); @@ -135,13 +133,11 @@ public void RgbaVector_FromRgb48() public void RgbaVector_FromRgba64() { // arrange - var input = default(RgbaVector); - var actual = default(Rgba64); - var expected = new Rgba64(65535, 0, 65535, 0); + Rgba64 expected = new(65535, 0, 65535, 0); // act - input.FromRgba64(expected); - actual.FromScaledVector4(input.ToScaledVector4()); + RgbaVector input = RgbaVector.FromRgba64(expected); + Rgba64 actual = Rgba64.FromScaledVector4(input.ToScaledVector4()); // assert Assert.Equal(expected, actual); @@ -151,11 +147,10 @@ public void RgbaVector_FromRgba64() public void RgbaVector_FromBgra5551() { // arrange - var rgb = default(RgbaVector); Vector4 expected = Vector4.One; // act - rgb.FromBgra5551(new Bgra5551(1.0f, 1.0f, 1.0f, 1.0f)); + RgbaVector rgb = RgbaVector.FromBgra5551(new Bgra5551(1.0f, 1.0f, 1.0f, 1.0f)); // assert Assert.Equal(expected, rgb.ToScaledVector4()); @@ -165,11 +160,10 @@ public void RgbaVector_FromBgra5551() public void RgbaVector_FromGrey16() { // arrange - var rgba = default(RgbaVector); Vector4 expected = Vector4.One; // act - rgba.FromL16(new L16(ushort.MaxValue)); + RgbaVector rgba = RgbaVector.FromL16(new L16(ushort.MaxValue)); // assert Assert.Equal(expected, rgba.ToScaledVector4()); @@ -179,11 +173,10 @@ public void RgbaVector_FromGrey16() public void RgbaVector_FromGrey8() { // arrange - var rgba = default(RgbaVector); Vector4 expected = Vector4.One; // act - rgba.FromL8(new L8(byte.MaxValue)); + RgbaVector rgba = RgbaVector.FromL8(new L8(byte.MaxValue)); // assert Assert.Equal(expected, rgba.ToScaledVector4()); @@ -197,11 +190,27 @@ public void Issue2048() using Image source = new(Configuration.Default, 1, 1, green); using Image clone = source.CloneAs(); - Rgba32 srcColor = default; - Rgba32 cloneColor = default; - source[0, 0].ToRgba32(ref srcColor); - clone[0, 0].ToRgba32(ref cloneColor); + Rgba32 srcColor = source[0, 0].ToRgba32(); + Rgba32 cloneColor = clone[0, 0].ToRgba32(); Assert.Equal(srcColor, cloneColor); } + + [Fact] + public void RgbaVector_PixelInformation() + { + PixelTypeInfo info = RgbaVector.GetPixelTypeInfo(); + Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); + Assert.Equal(PixelAlphaRepresentation.Unassociated, info.AlphaRepresentation); + Assert.Equal(PixelColorType.RGB | PixelColorType.Alpha, info.ColorType); + + PixelComponentInfo componentInfo = info.ComponentInfo.Value; + Assert.Equal(4, componentInfo.ComponentCount); + Assert.Equal(0, componentInfo.Padding); + Assert.Equal(32, componentInfo.GetComponentPrecision(0)); + Assert.Equal(32, componentInfo.GetComponentPrecision(1)); + Assert.Equal(32, componentInfo.GetComponentPrecision(2)); + Assert.Equal(32, componentInfo.GetComponentPrecision(3)); + Assert.Equal(32, componentInfo.GetMaximumComponentPrecision()); + } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Short2Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Short2Tests.cs index 8fc080d818..f23da0c7a6 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Short2Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Short2Tests.cs @@ -2,6 +2,7 @@ // Licensed under the Six Labors Split License. using System.Numerics; +using System.Runtime.CompilerServices; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Tests.PixelFormats; @@ -51,7 +52,7 @@ public void Short2_Clamping() public void Short2_ToScaledVector4() { // arrange - var short2 = new Short2(Vector2.One * 0x7FFF); + Short2 short2 = new(Vector2.One * 0x7FFF); // act Vector4 actual = short2.ToScaledVector4(); @@ -67,13 +68,12 @@ public void Short2_ToScaledVector4() public void Short2_FromScaledVector4() { // arrange - var pixel = default(Short2); - var short2 = new Short2(Vector2.One * 0x7FFF); + Short2 short2 = new(Vector2.One * 0x7FFF); const ulong expected = 0x7FFF7FFF; // act Vector4 scaled = short2.ToScaledVector4(); - pixel.FromScaledVector4(scaled); + Short2 pixel = Short2.FromScaledVector4(scaled); uint actual = pixel.PackedValue; // assert @@ -84,12 +84,11 @@ public void Short2_FromScaledVector4() public void Short2_ToRgba32() { // arrange - var short2 = new Short2(127.5f, -5.3f); - var actual = default(Rgba32); - var expected = new Rgba32(128, 127, 0, 255); + Short2 short2 = new(127.5f, -5.3f); + Rgba32 expected = new(128, 127, 0, 255); // act - short2.ToRgba32(ref actual); + Rgba32 actual = short2.ToRgba32(); // assert Assert.Equal(expected, actual); @@ -99,13 +98,11 @@ public void Short2_ToRgba32() public void Short2_FromRgba32_ToRgba32() { // arrange - var short2 = default(Short2); - var actual = default(Rgba32); - var expected = new Rgba32(20, 38, 0, 255); + Rgba32 expected = new(20, 38, 0, 255); // act - short2.FromRgba32(expected); - short2.ToRgba32(ref actual); + Short2 short2 = Short2.FromRgba32(expected); + Rgba32 actual = short2.ToRgba32(); // assert Assert.Equal(expected, actual); @@ -115,13 +112,11 @@ public void Short2_FromRgba32_ToRgba32() public void Short2_FromRgb48() { // arrange - var input = default(Short2); - var actual = default(Rgb48); - var expected = new Rgb48(65535, 65535, 0); + Rgb48 expected = new(65535, 65535, 0); // act - input.FromRgb48(expected); - actual.FromScaledVector4(input.ToScaledVector4()); + Short2 input = Short2.FromRgb48(expected); + Rgb48 actual = Rgb48.FromScaledVector4(input.ToScaledVector4()); // assert Assert.Equal(expected, actual); @@ -131,13 +126,11 @@ public void Short2_FromRgb48() public void Short2_FromRgba64() { // arrange - var input = default(Short2); - var actual = default(Rgba64); - var expected = new Rgba64(65535, 65535, 0, 65535); + Rgba64 expected = new(65535, 65535, 0, 65535); // act - input.FromRgba64(expected); - actual.FromScaledVector4(input.ToScaledVector4()); + Short2 input = Short2.FromRgba64(expected); + Rgba64 actual = Rgba64.FromScaledVector4(input.ToScaledVector4()); // assert Assert.Equal(expected, actual); @@ -146,11 +139,8 @@ public void Short2_FromRgba64() [Fact] public void Short2_FromBgra5551() { - // arrange - var short2 = default(Short2); - // act - short2.FromBgra5551(new Bgra5551(1.0f, 1.0f, 1.0f, 1.0f)); + Short2 short2 = Short2.FromBgra5551(new Bgra5551(1.0f, 1.0f, 1.0f, 1.0f)); // assert Vector4 actual = short2.ToScaledVector4(); @@ -159,4 +149,20 @@ public void Short2_FromBgra5551() Assert.Equal(0, actual.Z); Assert.Equal(1, actual.W); } + + [Fact] + public void Short2_PixelInformation() + { + PixelTypeInfo info = Short2.GetPixelTypeInfo(); + Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); + Assert.Equal(PixelAlphaRepresentation.None, info.AlphaRepresentation); + Assert.Equal(PixelColorType.Red | PixelColorType.Green, info.ColorType); + + PixelComponentInfo componentInfo = info.ComponentInfo.Value; + Assert.Equal(2, componentInfo.ComponentCount); + Assert.Equal(0, componentInfo.Padding); + Assert.Equal(16, componentInfo.GetComponentPrecision(0)); + Assert.Equal(16, componentInfo.GetComponentPrecision(1)); + Assert.Equal(16, componentInfo.GetMaximumComponentPrecision()); + } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Short4Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Short4Tests.cs index c420627034..819ff0e1e5 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Short4Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Short4Tests.cs @@ -2,6 +2,7 @@ // Licensed under the Six Labors Split License. using System.Numerics; +using System.Runtime.CompilerServices; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Tests.PixelFormats; @@ -12,8 +13,8 @@ public class Short4Tests [Fact] public void Short4_PackedValues() { - var shortValue1 = new Short4(11547, 12653, 29623, 193); - var shortValue2 = new Short4(0.1f, -0.3f, 0.5f, -0.7f); + Short4 shortValue1 = new(11547, 12653, 29623, 193); + Short4 shortValue2 = new(0.1f, -0.3f, 0.5f, -0.7f); Assert.Equal(0x00c173b7316d2d1bUL, shortValue1.PackedValue); Assert.Equal(18446462598732840960, shortValue2.PackedValue); @@ -38,7 +39,7 @@ public void Short4_ToVector4() public void Short4_ToScaledVector4() { // arrange - var short4 = new Short4(Vector4.One * 0x7FFF); + Short4 short4 = new(Vector4.One * 0x7FFF); // act Vector4 actual = short4.ToScaledVector4(); @@ -54,13 +55,12 @@ public void Short4_ToScaledVector4() public void Short4_FromScaledVector4() { // arrange - var short4 = new Short4(Vector4.One * 0x7FFF); + Short4 short4 = new(Vector4.One * 0x7FFF); Vector4 scaled = short4.ToScaledVector4(); const long expected = 0x7FFF7FFF7FFF7FFF; // act - var pixel = default(Short4); - pixel.FromScaledVector4(scaled); + Short4 pixel = Short4.FromScaledVector4(scaled); // assert Assert.Equal((ulong)expected, pixel.PackedValue); @@ -70,12 +70,12 @@ public void Short4_FromScaledVector4() public void Short4_Clamping() { // arrange - var short1 = new Short4(Vector4.One * 1234567.0f); - var short2 = new Short4(Vector4.One * -1234567.0f); + Short4 short1 = new(Vector4.One * 1234567.0f); + Short4 short2 = new(Vector4.One * -1234567.0f); // act - var vector1 = short1.ToVector4(); - var vector2 = short2.ToVector4(); + Vector4 vector1 = short1.ToVector4(); + Vector4 vector2 = short2.ToVector4(); // assert Assert.Equal(Vector4.One * 0x7FFF, vector1); @@ -86,12 +86,11 @@ public void Short4_Clamping() public void Short4_ToRgba32() { // arrange - var shortValue = new Short4(11547, 12653, 29623, 193); - var actual = default(Rgba32); - var expected = new Rgba32(172, 177, 243, 128); + Short4 shortValue = new(11547, 12653, 29623, 193); + Rgba32 expected = new(172, 177, 243, 128); // act - shortValue.ToRgba32(ref actual); + Rgba32 actual = shortValue.ToRgba32(); // assert Assert.Equal(expected, actual); @@ -101,13 +100,11 @@ public void Short4_ToRgba32() public void Short4_FromRgba32_ToRgba32() { // arrange - var short4 = default(Short4); - var actual = default(Rgba32); - var expected = new Rgba32(20, 38, 0, 255); + Rgba32 expected = new(20, 38, 0, 255); // act - short4.FromRgba32(expected); - short4.ToRgba32(ref actual); + Short4 short4 = Short4.FromRgba32(expected); + Rgba32 actual = short4.ToRgba32(); // assert Assert.Equal(expected, actual); @@ -117,15 +114,12 @@ public void Short4_FromRgba32_ToRgba32() public void Short4_FromBgra32_ToRgba32() { // arrange - var short4 = default(Short4); - var actual = default(Bgra32); - var expected = new Bgra32(20, 38, 0, 255); + Bgra32 expected = new(20, 38, 0, 255); // act - short4.FromBgra32(expected); - Rgba32 temp = default; - short4.ToRgba32(ref temp); - actual.FromRgba32(temp); + Short4 short4 = Short4.FromBgra32(expected); + Rgba32 temp = short4.ToRgba32(); + Bgra32 actual = Bgra32.FromRgba32(temp); // assert Assert.Equal(expected, actual); @@ -135,15 +129,12 @@ public void Short4_FromBgra32_ToRgba32() public void Short4_FromArgb32_ToRgba32() { // arrange - var short4 = default(Short4); - var actual = default(Argb32); - var expected = new Argb32(20, 38, 0, 255); + Argb32 expected = new(20, 38, 0, 255); // act - short4.FromArgb32(expected); - Rgba32 temp = default; - short4.ToRgba32(ref temp); - actual.FromRgba32(temp); + Short4 short4 = Short4.FromArgb32(expected); + Rgba32 temp = short4.ToRgba32(); + Argb32 actual = Argb32.FromRgba32(temp); // assert Assert.Equal(expected, actual); @@ -153,15 +144,12 @@ public void Short4_FromArgb32_ToRgba32() public void Short4_FromAbgrb32_ToRgba32() { // arrange - var short4 = default(Short4); - var actual = default(Abgr32); - var expected = new Abgr32(20, 38, 0, 255); + Abgr32 expected = new(20, 38, 0, 255); // act - short4.FromAbgr32(expected); - Rgba32 temp = default; - short4.ToRgba32(ref temp); - actual.FromRgba32(temp); + Short4 short4 = Short4.FromAbgr32(expected); + Rgba32 temp = short4.ToRgba32(); + Abgr32 actual = Abgr32.FromRgba32(temp); // assert Assert.Equal(expected, actual); @@ -171,13 +159,11 @@ public void Short4_FromAbgrb32_ToRgba32() public void Short4_FromRgb48_ToRgb48() { // arrange - var input = default(Short4); - var actual = default(Rgb48); - var expected = new Rgb48(65535, 0, 65535); + Rgb48 expected = new(65535, 0, 65535); // act - input.FromRgb48(expected); - actual.FromScaledVector4(input.ToScaledVector4()); + Short4 input = Short4.FromRgb48(expected); + Rgb48 actual = Rgb48.FromScaledVector4(input.ToScaledVector4()); // assert Assert.Equal(expected, actual); @@ -187,13 +173,11 @@ public void Short4_FromRgb48_ToRgb48() public void Short4_FromRgba64_ToRgba64() { // arrange - var input = default(Short4); - var actual = default(Rgba64); - var expected = new Rgba64(65535, 0, 65535, 0); + Rgba64 expected = new(65535, 0, 65535, 0); // act - input.FromRgba64(expected); - actual.FromScaledVector4(input.ToScaledVector4()); + Short4 input = Short4.FromRgba64(expected); + Rgba64 actual = Rgba64.FromScaledVector4(input.ToScaledVector4()); // assert Assert.Equal(expected, actual); @@ -203,13 +187,30 @@ public void Short4_FromRgba64_ToRgba64() public void Short4_FromBgra5551() { // arrange - var short4 = default(Short4); Vector4 expected = Vector4.One; // act - short4.FromBgra5551(new Bgra5551(1.0f, 1.0f, 1.0f, 1.0f)); + Short4 short4 = Short4.FromBgra5551(new Bgra5551(1.0f, 1.0f, 1.0f, 1.0f)); // assert Assert.Equal(expected, short4.ToScaledVector4()); } + + [Fact] + public void Short4_PixelInformation() + { + PixelTypeInfo info = Short4.GetPixelTypeInfo(); + Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); + Assert.Equal(PixelAlphaRepresentation.Unassociated, info.AlphaRepresentation); + Assert.Equal(PixelColorType.RGB | PixelColorType.Alpha, info.ColorType); + + PixelComponentInfo componentInfo = info.ComponentInfo.Value; + Assert.Equal(4, componentInfo.ComponentCount); + Assert.Equal(0, componentInfo.Padding); + Assert.Equal(16, componentInfo.GetComponentPrecision(0)); + Assert.Equal(16, componentInfo.GetComponentPrecision(1)); + Assert.Equal(16, componentInfo.GetComponentPrecision(2)); + Assert.Equal(16, componentInfo.GetComponentPrecision(3)); + Assert.Equal(16, componentInfo.GetMaximumComponentPrecision()); + } } diff --git a/tests/ImageSharp.Tests/PixelFormats/UnPackedPixelTests.cs b/tests/ImageSharp.Tests/PixelFormats/UnPackedPixelTests.cs index 5cc35b43ed..651f6fe7f8 100644 --- a/tests/ImageSharp.Tests/PixelFormats/UnPackedPixelTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/UnPackedPixelTests.cs @@ -12,8 +12,8 @@ public class UnPackedPixelTests [Fact] public void Color_Types_From_Bytes_Produce_Equal_Scaled_Component_OutPut() { - var color = new Rgba32(24, 48, 96, 192); - var colorVector = new RgbaVector(24 / 255F, 48 / 255F, 96 / 255F, 192 / 255F); + Rgba32 color = new(24, 48, 96, 192); + RgbaVector colorVector = new(24 / 255F, 48 / 255F, 96 / 255F, 192 / 255F); Assert.Equal(color.R, (byte)(colorVector.R * 255)); Assert.Equal(color.G, (byte)(colorVector.G * 255)); @@ -24,8 +24,8 @@ public void Color_Types_From_Bytes_Produce_Equal_Scaled_Component_OutPut() [Fact] public void Color_Types_From_Floats_Produce_Equal_Scaled_Component_OutPut() { - var color = new Rgba32(24 / 255F, 48 / 255F, 96 / 255F, 192 / 255F); - var colorVector = new RgbaVector(24 / 255F, 48 / 255F, 96 / 255F, 192 / 255F); + Rgba32 color = new(24 / 255F, 48 / 255F, 96 / 255F, 192 / 255F); + RgbaVector colorVector = new(24 / 255F, 48 / 255F, 96 / 255F, 192 / 255F); Assert.Equal(color.R, (byte)(colorVector.R * 255)); Assert.Equal(color.G, (byte)(colorVector.G * 255)); @@ -36,8 +36,8 @@ public void Color_Types_From_Floats_Produce_Equal_Scaled_Component_OutPut() [Fact] public void Color_Types_From_Vector4_Produce_Equal_Scaled_Component_OutPut() { - var color = new Rgba32(new Vector4(24 / 255F, 48 / 255F, 96 / 255F, 192 / 255F)); - var colorVector = new RgbaVector(24 / 255F, 48 / 255F, 96 / 255F, 192 / 255F); + Rgba32 color = new(new Vector4(24 / 255F, 48 / 255F, 96 / 255F, 192 / 255F)); + RgbaVector colorVector = new(24 / 255F, 48 / 255F, 96 / 255F, 192 / 255F); Assert.Equal(color.R, (byte)(colorVector.R * 255)); Assert.Equal(color.G, (byte)(colorVector.G * 255)); @@ -48,8 +48,8 @@ public void Color_Types_From_Vector4_Produce_Equal_Scaled_Component_OutPut() [Fact] public void Color_Types_From_Vector3_Produce_Equal_Scaled_Component_OutPut() { - var color = new Rgba32(new Vector3(24 / 255F, 48 / 255F, 96 / 255F)); - var colorVector = new RgbaVector(24 / 255F, 48 / 255F, 96 / 255F); + Rgba32 color = new(new Vector3(24 / 255F, 48 / 255F, 96 / 255F)); + RgbaVector colorVector = new(24 / 255F, 48 / 255F, 96 / 255F); Assert.Equal(color.R, (byte)(colorVector.R * 255)); Assert.Equal(color.G, (byte)(colorVector.G * 255)); @@ -60,8 +60,8 @@ public void Color_Types_From_Vector3_Produce_Equal_Scaled_Component_OutPut() [Fact] public void Color_Types_From_Hex_Produce_Equal_Scaled_Component_OutPut() { - var color = Rgba32.ParseHex("183060C0"); - var colorVector = RgbaVector.FromHex("183060C0"); + Rgba32 color = Rgba32.ParseHex("183060C0"); + RgbaVector colorVector = RgbaVector.FromHex("183060C0"); Assert.Equal(color.R, (byte)(colorVector.R * 255)); Assert.Equal(color.G, (byte)(colorVector.G * 255)); @@ -72,8 +72,8 @@ public void Color_Types_From_Hex_Produce_Equal_Scaled_Component_OutPut() [Fact] public void Color_Types_To_Vector4_Produce_Equal_OutPut() { - var color = new Rgba32(24, 48, 96, 192); - var colorVector = new RgbaVector(24 / 255F, 48 / 255F, 96 / 255F, 192 / 255F); + Rgba32 color = new(24, 48, 96, 192); + RgbaVector colorVector = new(24 / 255F, 48 / 255F, 96 / 255F, 192 / 255F); Assert.Equal(color.ToVector4(), colorVector.ToVector4()); } @@ -81,13 +81,11 @@ public void Color_Types_To_Vector4_Produce_Equal_OutPut() [Fact] public void Color_Types_To_RgbaBytes_Produce_Equal_OutPut() { - var color = new Rgba32(24, 48, 96, 192); - var colorVector = new RgbaVector(24 / 255F, 48 / 255F, 96 / 255F, 192 / 255F); + Rgba32 color = new(24, 48, 96, 192); + RgbaVector colorVector = new(24 / 255F, 48 / 255F, 96 / 255F, 192 / 255F); - Rgba32 rgba = default; - Rgba32 rgbaVector = default; - color.ToRgba32(ref rgba); - colorVector.ToRgba32(ref rgbaVector); + Rgba32 rgba = color.ToRgba32(); + Rgba32 rgbaVector = colorVector.ToRgba32(); Assert.Equal(rgba, rgbaVector); } @@ -95,8 +93,8 @@ public void Color_Types_To_RgbaBytes_Produce_Equal_OutPut() [Fact] public void Color_Types_To_Hex_Produce_Equal_OutPut() { - var color = new Rgba32(24, 48, 96, 192); - var colorVector = new RgbaVector(24 / 255F, 48 / 255F, 96 / 255F, 192 / 255F); + Rgba32 color = new(24, 48, 96, 192); + RgbaVector colorVector = new(24 / 255F, 48 / 255F, 96 / 255F, 192 / 255F); // 183060C0 Assert.Equal(color.ToHex(), colorVector.ToHex()); diff --git a/tests/ImageSharp.Tests/Processing/IntegralImageTests.cs b/tests/ImageSharp.Tests/Processing/IntegralImageTests.cs index cd61d68be5..81ba1693d2 100644 --- a/tests/ImageSharp.Tests/Processing/IntegralImageTests.cs +++ b/tests/ImageSharp.Tests/Processing/IntegralImageTests.cs @@ -21,14 +21,7 @@ public void CalculateIntegralImage_Rgba32Works(TestImageProvider provide Buffer2D integralBuffer = image.CalculateIntegralImage(); // Assert: - VerifySumValues(provider, integralBuffer, (Rgba32 pixel) => - { - L8 outputPixel = default; - - outputPixel.FromRgba32(pixel); - - return outputPixel.PackedValue; - }); + VerifySumValues(provider, integralBuffer, (Rgba32 pixel) => L8.FromRgba32(pixel).PackedValue); } [Theory] @@ -45,14 +38,7 @@ public void CalculateIntegralImage_WithBounds_Rgba32Works(TestImageProvider integralBuffer = image.CalculateIntegralImage(interest); // Assert: - VerifySumValues(provider, integralBuffer, interest, (Rgba32 pixel) => - { - L8 outputPixel = default; - - outputPixel.FromRgba32(pixel); - - return outputPixel.PackedValue; - }); + VerifySumValues(provider, integralBuffer, interest, (Rgba32 pixel) => L8.FromRgba32(pixel).PackedValue); } [Theory] @@ -88,7 +74,7 @@ public void CalculateIntegralImage_WithBounds_L8Works(TestImageProvider prov private static void VerifySumValues( TestImageProvider provider, Buffer2D integralBuffer, - System.Func getPixel) + Func getPixel) where TPixel : unmanaged, IPixel => VerifySumValues(provider, integralBuffer, integralBuffer.Bounds(), getPixel); @@ -96,7 +82,7 @@ private static void VerifySumValues( TestImageProvider provider, Buffer2D integralBuffer, Rectangle bounds, - System.Func getPixel) + Func getPixel) where TPixel : unmanaged, IPixel { Buffer2DRegion image = provider.GetImage().GetRootFramePixelBuffer().GetRegion(bounds); diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/AffineTransformTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/AffineTransformTests.cs index 05604ac6e6..a7855e23aa 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/AffineTransformTests.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/AffineTransformTests.cs @@ -21,8 +21,8 @@ public class AffineTransformTests /// angleDeg, sx, sy, tx, ty /// public static readonly TheoryData TransformValues - = new TheoryData - { + = new() + { { 0, 1, 1, 0, 0 }, { 50, 1, 1, 0, 0 }, { 0, 1, 1, 20, 10 }, @@ -35,7 +35,7 @@ public static readonly TheoryData TransformVa { 0, 1f, 2f, 0, 0 }, }; - public static readonly TheoryData ResamplerNames = new TheoryData + public static readonly TheoryData ResamplerNames = new() { nameof(KnownResamplers.Bicubic), nameof(KnownResamplers.Box), @@ -55,8 +55,8 @@ public static readonly TheoryData TransformVa }; public static readonly TheoryData Transform_DoesNotCreateEdgeArtifacts_ResamplerNames = - new TheoryData - { + new() + { nameof(KnownResamplers.NearestNeighbor), nameof(KnownResamplers.Triangle), nameof(KnownResamplers.Bicubic), @@ -75,16 +75,14 @@ public void Transform_DoesNotCreateEdgeArtifacts(TestImageProvider { IResampler resampler = GetResampler(resamplerName); - using (Image image = provider.GetImage()) - { - AffineTransformBuilder builder = new AffineTransformBuilder() - .AppendRotationDegrees(30); + using Image image = provider.GetImage(); + AffineTransformBuilder builder = new AffineTransformBuilder() + .AppendRotationDegrees(30); - image.Mutate(c => c.Transform(builder, resampler)); - image.DebugSave(provider, resamplerName); + image.Mutate(c => c.Transform(builder, resampler)); + image.DebugSave(provider, resamplerName); - VerifyAllPixelsAreWhiteOrTransparent(image); - } + VerifyAllPixelsAreWhiteOrTransparent(image); } [Theory] @@ -98,22 +96,20 @@ public void Transform_RotateScaleTranslate( float ty) where TPixel : unmanaged, IPixel { - using (Image image = provider.GetImage()) - { - image.DebugSave(provider, $"_original"); - AffineTransformBuilder builder = new AffineTransformBuilder() - .AppendRotationDegrees(angleDeg) - .AppendScale(new SizeF(sx, sy)) - .AppendTranslation(new PointF(tx, ty)); + using Image image = provider.GetImage(); + image.DebugSave(provider, $"_original"); + AffineTransformBuilder builder = new AffineTransformBuilder() + .AppendRotationDegrees(angleDeg) + .AppendScale(new SizeF(sx, sy)) + .AppendTranslation(new PointF(tx, ty)); - this.PrintMatrix(builder.BuildMatrix(image.Size)); + this.PrintMatrix(builder.BuildMatrix(image.Size)); - image.Mutate(i => i.Transform(builder, KnownResamplers.Bicubic)); + image.Mutate(i => i.Transform(builder, KnownResamplers.Bicubic)); - FormattableString testOutputDetails = $"R({angleDeg})_S({sx},{sy})_T({tx},{ty})"; - image.DebugSave(provider, testOutputDetails); - image.CompareToReferenceOutput(ValidatorComparer, provider, testOutputDetails); - } + FormattableString testOutputDetails = $"R({angleDeg})_S({sx},{sy})_T({tx},{ty})"; + image.DebugSave(provider, testOutputDetails); + image.CompareToReferenceOutput(ValidatorComparer, provider, testOutputDetails); } [Theory] @@ -121,23 +117,21 @@ public void Transform_RotateScaleTranslate( public void Transform_RotateScale_ManuallyCentered(TestImageProvider provider, float angleDeg, float s) where TPixel : unmanaged, IPixel { - using (Image image = provider.GetImage()) - { - AffineTransformBuilder builder = new AffineTransformBuilder() - .AppendRotationDegrees(angleDeg) - .AppendScale(new SizeF(s, s)); + using Image image = provider.GetImage(); + AffineTransformBuilder builder = new AffineTransformBuilder() + .AppendRotationDegrees(angleDeg) + .AppendScale(new SizeF(s, s)); - image.Mutate(i => i.Transform(builder, KnownResamplers.Bicubic)); + image.Mutate(i => i.Transform(builder, KnownResamplers.Bicubic)); - FormattableString testOutputDetails = $"R({angleDeg})_S({s})"; - image.DebugSave(provider, testOutputDetails); - image.CompareToReferenceOutput(ValidatorComparer, provider, testOutputDetails); - } + FormattableString testOutputDetails = $"R({angleDeg})_S({s})"; + image.DebugSave(provider, testOutputDetails); + image.CompareToReferenceOutput(ValidatorComparer, provider, testOutputDetails); } public static readonly TheoryData Transform_IntoRectangle_Data = - new TheoryData - { + new() + { { 0, 0, 10, 10 }, { 0, 0, 5, 10 }, { 0, 0, 10, 5 }, @@ -155,19 +149,17 @@ public void Transform_RotateScale_ManuallyCentered(TestImageProvider(TestImageProvider provider) where TPixel : unmanaged, IPixel { - var rectangle = new Rectangle(48, 0, 48, 24); + Rectangle rectangle = new(48, 0, 48, 24); - using (Image image = provider.GetImage()) - { - image.DebugSave(provider, $"_original"); - AffineTransformBuilder builder = new AffineTransformBuilder() - .AppendScale(new SizeF(2, 1.5F)); + using Image image = provider.GetImage(); + image.DebugSave(provider, $"_original"); + AffineTransformBuilder builder = new AffineTransformBuilder() + .AppendScale(new SizeF(2, 1.5F)); - image.Mutate(i => i.Transform(rectangle, builder, KnownResamplers.Spline)); + image.Mutate(i => i.Transform(rectangle, builder, KnownResamplers.Spline)); - image.DebugSave(provider); - image.CompareToReferenceOutput(ValidatorComparer, provider); - } + image.DebugSave(provider); + image.CompareToReferenceOutput(ValidatorComparer, provider); } [Theory] @@ -175,18 +167,16 @@ public void Transform_FromSourceRectangle1(TestImageProvider pro public void Transform_FromSourceRectangle2(TestImageProvider provider) where TPixel : unmanaged, IPixel { - var rectangle = new Rectangle(0, 24, 48, 24); + Rectangle rectangle = new(0, 24, 48, 24); - using (Image image = provider.GetImage()) - { - AffineTransformBuilder builder = new AffineTransformBuilder() - .AppendScale(new SizeF(1F, 2F)); + using Image image = provider.GetImage(); + AffineTransformBuilder builder = new AffineTransformBuilder() + .AppendScale(new SizeF(1F, 2F)); - image.Mutate(i => i.Transform(rectangle, builder, KnownResamplers.Spline)); + image.Mutate(i => i.Transform(rectangle, builder, KnownResamplers.Spline)); - image.DebugSave(provider); - image.CompareToReferenceOutput(ValidatorComparer, provider); - } + image.DebugSave(provider); + image.CompareToReferenceOutput(ValidatorComparer, provider); } [Theory] @@ -195,17 +185,15 @@ public void Transform_WithSampler(TestImageProvider provider, st where TPixel : unmanaged, IPixel { IResampler sampler = GetResampler(resamplerName); - using (Image image = provider.GetImage()) - { - AffineTransformBuilder builder = new AffineTransformBuilder() - .AppendRotationDegrees(50) - .AppendScale(new SizeF(.6F, .6F)); + using Image image = provider.GetImage(); + AffineTransformBuilder builder = new AffineTransformBuilder() + .AppendRotationDegrees(50) + .AppendScale(new SizeF(.6F, .6F)); - image.Mutate(i => i.Transform(builder, sampler)); + image.Mutate(i => i.Transform(builder, sampler)); - image.DebugSave(provider, resamplerName); - image.CompareToReferenceOutput(ValidatorComparer, provider, resamplerName); - } + image.DebugSave(provider, resamplerName); + image.CompareToReferenceOutput(ValidatorComparer, provider, resamplerName); } [Theory] @@ -224,7 +212,7 @@ public void WorksWithDiscoBuffers(TestImageProvider provider, in [Fact] public void Issue1911() { - using var image = new Image(100, 100); + using Image image = new(100, 100); image.Mutate(x => x = x.Transform(new Rectangle(0, 0, 99, 100), Matrix3x2.Identity, new Size(99, 100), KnownResamplers.Lanczos2)); Assert.Equal(99, image.Width); @@ -272,7 +260,7 @@ public void Transform_With_Custom_Dimensions(TestImageProvider p { using Image image = provider.GetImage(); - var m = Matrix3x2.CreateRotation(radians, new Vector2(50, 50)); + Matrix3x2 m = Matrix3x2.CreateRotation(radians, new Vector2(50, 50)); Rectangle r = new(25, 25, 50, 50); image.Mutate(x => x.Transform(r, m, new Size(100, 100), KnownResamplers.Bicubic)); image.DebugSave(provider, testOutputDetails: radians); @@ -282,23 +270,24 @@ public void Transform_With_Custom_Dimensions(TestImageProvider p [Fact] public void TransformRotationDoesNotOffset() { - Rgba32 marker = Color.Aqua; + Rgba32 background = Color.DimGray.ToPixel(); + Rgba32 marker = Color.Aqua.ToPixel(); - using Image img = new(100, 100, Color.DimGray); + using Image img = new(100, 100, background); img[0, 0] = marker; img.Mutate(c => c.Rotate(180)); Assert.Equal(marker, img[99, 99]); - using Image img2 = new(100, 100, Color.DimGray); + using Image img2 = new(100, 100, background); img2[0, 0] = marker; img2.Mutate( c => c.Transform(new AffineTransformBuilder().AppendRotationDegrees(180), KnownResamplers.NearestNeighbor)); - using Image img3 = new(100, 100, Color.DimGray); + using Image img3 = new(100, 100, background); img3[0, 0] = marker; img3.Mutate(c => c.Transform(new AffineTransformBuilder().AppendRotationDegrees(180))); @@ -309,12 +298,8 @@ public void TransformRotationDoesNotOffset() private static IResampler GetResampler(string name) { - PropertyInfo property = typeof(KnownResamplers).GetTypeInfo().GetProperty(name); - - if (property is null) - { - throw new Exception($"No resampler named {name}"); - } + PropertyInfo property = typeof(KnownResamplers).GetTypeInfo().GetProperty(name) + ?? throw new InvalidOperationException($"No resampler named {name}"); return (IResampler)property.GetValue(null); } @@ -323,11 +308,10 @@ private static void VerifyAllPixelsAreWhiteOrTransparent(Image i where TPixel : unmanaged, IPixel { Assert.True(image.Frames.RootFrame.DangerousTryGetSinglePixelMemory(out Memory data)); - var white = new Rgb24(255, 255, 255); + Rgb24 white = new(255, 255, 255); foreach (TPixel pixel in data.Span) { - Rgba32 rgba = default; - pixel.ToRgba32(ref rgba); + Rgba32 rgba = pixel.ToRgba32(); if (rgba.A == 0) { continue; diff --git a/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformTests.cs b/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformTests.cs index 128df01a06..38ac9c18c6 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformTests.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformTests.cs @@ -188,23 +188,24 @@ public void Transform_With_Custom_Dimensions(TestImageProvider p [Fact] public void TransformRotationDoesNotOffset() { - Rgba32 marker = Color.Aqua; + Rgba32 background = Color.DimGray.ToPixel(); + Rgba32 marker = Color.Aqua.ToPixel(); - using Image img = new(100, 100, Color.DimGray); + using Image img = new(100, 100, background); img[0, 0] = marker; img.Mutate(c => c.Rotate(180)); Assert.Equal(marker, img[99, 99]); - using Image img2 = new(100, 100, Color.DimGray); + using Image img2 = new(100, 100, background); img2[0, 0] = marker; img2.Mutate( c => c.Transform(new ProjectiveTransformBuilder().AppendRotationDegrees(180), KnownResamplers.NearestNeighbor)); - using Image img3 = new(100, 100, Color.DimGray); + using Image img3 = new(100, 100, background); img3[0, 0] = marker; img3.Mutate(c => c.Transform(new AffineTransformBuilder().AppendRotationDegrees(180))); diff --git a/tests/ImageSharp.Tests/Quantization/WuQuantizerTests.cs b/tests/ImageSharp.Tests/Quantization/WuQuantizerTests.cs index d6b1f1f980..ccb79debda 100644 --- a/tests/ImageSharp.Tests/Quantization/WuQuantizerTests.cs +++ b/tests/ImageSharp.Tests/Quantization/WuQuantizerTests.cs @@ -14,7 +14,7 @@ public void SinglePixelOpaque() Configuration config = Configuration.Default; var quantizer = new WuQuantizer(new QuantizerOptions { Dither = null }); - using var image = new Image(config, 1, 1, Color.Black); + using var image = new Image(config, 1, 1, Color.Black.ToPixel()); ImageFrame frame = image.Frames.RootFrame; using IQuantizer frameQuantizer = quantizer.CreatePixelSpecificQuantizer(config); @@ -24,7 +24,7 @@ public void SinglePixelOpaque() Assert.Equal(1, result.Width); Assert.Equal(1, result.Height); - Assert.Equal(Color.Black, (Color)result.Palette.Span[0]); + Assert.Equal(Color.Black, Color.FromPixel(result.Palette.Span[0])); Assert.Equal(0, result.DangerousGetRowSpan(0)[0]); } diff --git a/tests/ImageSharp.Tests/TestFormat.cs b/tests/ImageSharp.Tests/TestFormat.cs index f597b708d5..d30ce7846d 100644 --- a/tests/ImageSharp.Tests/TestFormat.cs +++ b/tests/ImageSharp.Tests/TestFormat.cs @@ -7,6 +7,7 @@ using SixLabors.ImageSharp.Metadata; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Tests.TestUtilities; +using SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs; namespace SixLabors.ImageSharp.Tests; @@ -89,7 +90,7 @@ public Image Sample() { if (!this.sampleImages.ContainsKey(typeof(TPixel))) { - this.sampleImages.Add(typeof(TPixel), new Image(1, 1)); + this.sampleImages.Add(typeof(TPixel), ReferenceCodecUtilities.EnsureDecodedMetadata(new Image(1, 1), this)); } return (Image)this.sampleImages[typeof(TPixel)]; @@ -202,11 +203,12 @@ public class TestDecoder : SpecializedImageDecoder protected override ImageInfo Identify(DecoderOptions options, Stream stream, CancellationToken cancellationToken) { - Image image = - this.Decode(this.CreateDefaultSpecializedOptions(options), stream, cancellationToken); - ImageFrameCollection m = image.Frames; - - return new(image.PixelType, image.Size, image.Metadata, new List(image.Frames.Select(x => x.Metadata))); + using Image image = this.Decode(this.CreateDefaultSpecializedOptions(options), stream, cancellationToken); + ImageMetadata metadata = image.Metadata; + return new(image.Size, metadata, new List(image.Frames.Select(x => x.Metadata))) + { + PixelType = metadata.GetDecodedPixelTypeInfo() + }; } protected override TestDecoderOptions CreateDefaultSpecializedOptions(DecoderOptions options) @@ -263,75 +265,49 @@ public Task EncodeAsync(Image image, Stream stream, Cancellation public struct TestPixelForAgnosticDecode : IPixel { - public PixelOperations CreatePixelOperations() => new(); + public readonly Rgba32 ToRgba32() => default; - public void FromScaledVector4(Vector4 vector) - { - } + public readonly Vector4 ToScaledVector4() => default; - public Vector4 ToScaledVector4() => default; + public readonly Vector4 ToVector4() => default; - public void FromVector4(Vector4 vector) - { - } + public static PixelTypeInfo GetPixelTypeInfo() + => PixelTypeInfo.Create( + PixelComponentInfo.Create(2, 8, 8), + PixelColorType.Red | PixelColorType.Green, + PixelAlphaRepresentation.None); - public Vector4 ToVector4() => default; + public static PixelOperations CreatePixelOperations() => new(); - public void FromArgb32(Argb32 source) - { - } + public static TestPixelForAgnosticDecode FromScaledVector4(Vector4 vector) => default; - public void FromBgra5551(Bgra5551 source) - { - } + public static TestPixelForAgnosticDecode FromVector4(Vector4 vector) => default; - public void FromBgr24(Bgr24 source) - { - } + public static TestPixelForAgnosticDecode FromAbgr32(Abgr32 source) => default; - public void FromBgra32(Bgra32 source) - { - } + public static TestPixelForAgnosticDecode FromArgb32(Argb32 source) => default; - public void FromAbgr32(Abgr32 source) - { - } + public static TestPixelForAgnosticDecode FromBgra5551(Bgra5551 source) => default; - public void FromL8(L8 source) - { - } + public static TestPixelForAgnosticDecode FromBgr24(Bgr24 source) => default; - public void FromL16(L16 source) - { - } + public static TestPixelForAgnosticDecode FromBgra32(Bgra32 source) => default; - public void FromLa16(La16 source) - { - } + public static TestPixelForAgnosticDecode FromL8(L8 source) => default; - public void FromLa32(La32 source) - { - } + public static TestPixelForAgnosticDecode FromL16(L16 source) => default; - public void FromRgb24(Rgb24 source) - { - } + public static TestPixelForAgnosticDecode FromLa16(La16 source) => default; - public void FromRgba32(Rgba32 source) - { - } + public static TestPixelForAgnosticDecode FromLa32(La32 source) => default; - public void ToRgba32(ref Rgba32 dest) - { - } + public static TestPixelForAgnosticDecode FromRgb24(Rgb24 source) => default; - public void FromRgb48(Rgb48 source) - { - } + public static TestPixelForAgnosticDecode FromRgba32(Rgba32 source) => default; - public void FromRgba64(Rgba64 source) - { - } + public static TestPixelForAgnosticDecode FromRgb48(Rgb48 source) => default; + + public static TestPixelForAgnosticDecode FromRgba64(Rgba64 source) => default; public bool Equals(TestPixelForAgnosticDecode other) => false; } diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index 847aac3478..13f72a6345 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -322,6 +322,7 @@ public static class Issues public const string Issue2564 = "Jpg/issues/issue-2564.jpg"; public const string HangBadScan = "Jpg/issues/Hang_C438A851.jpg"; public const string Issue2517 = "Jpg/issues/issue2517-bad-d7.jpg"; + public const string Issue2067_CommentMarker = "Jpg/issues/issue-2067-comment.jpg"; public const string Issue2638 = "Jpg/issues/Issue2638.jpg"; public const string Issue2758 = "Jpg/issues/issue-2758.jpg"; @@ -636,6 +637,8 @@ public static class Tga public const string Github_RLE_legacy = "Tga/Github_RLE_legacy.tga"; public const string WhiteStripesPattern = "Tga/whitestripes.png"; + + public const string Issue2629 = "Tga/issues/Issue2629.tga"; } public static class Webp @@ -1044,6 +1047,7 @@ public static class Tiff public const string Issues2255 = "Tiff/Issues/Issue2255.png"; public const string Issues2435 = "Tiff/Issues/Issue2435.tiff"; public const string Issues2587 = "Tiff/Issues/Issue2587.tiff"; + public const string Issues2679 = "Tiff/Issues/Issue2679.tiff"; public const string JpegCompressedGray0000539558 = "Tiff/Issues/JpegCompressedGray-0000539558.tiff"; public const string Tiled0000023664 = "Tiff/Issues/tiled-0000023664.tiff"; @@ -1125,4 +1129,128 @@ public static class Qoi public const string TestCardRGBA = "Qoi/testcard_rgba.qoi"; public const string Wikipedia008 = "Qoi/wikipedia_008.qoi"; } + + public static class Ico + { + public const string Flutter = "Icon/flutter.ico"; + public const string Bpp1Size15x15 = "Icon/1bpp_size_15x15.ico"; + public const string Bpp1Size16x16 = "Icon/1bpp_size_16x16.ico"; + public const string Bpp1Size17x17 = "Icon/1bpp_size_17x17.ico"; + public const string Bpp1Size1x1 = "Icon/1bpp_size_1x1.ico"; + public const string Bpp1Size256x256 = "Icon/1bpp_size_256x256.ico"; + public const string Bpp1Size2x2 = "Icon/1bpp_size_2x2.ico"; + public const string Bpp1Size31x31 = "Icon/1bpp_size_31x31.ico"; + public const string Bpp1Size32x32 = "Icon/1bpp_size_32x32.ico"; + public const string Bpp1Size33x33 = "Icon/1bpp_size_33x33.ico"; + public const string Bpp1Size3x3 = "Icon/1bpp_size_3x3.ico"; + public const string Bpp1Size4x4 = "Icon/1bpp_size_4x4.ico"; + public const string Bpp1Size5x5 = "Icon/1bpp_size_5x5.ico"; + public const string Bpp1Size6x6 = "Icon/1bpp_size_6x6.ico"; + public const string Bpp1Size7x7 = "Icon/1bpp_size_7x7.ico"; + public const string Bpp1Size8x8 = "Icon/1bpp_size_8x8.ico"; + public const string Bpp1Size9x9 = "Icon/1bpp_size_9x9.ico"; + public const string Bpp1TranspNotSquare = "Icon/1bpp_transp_not_square.ico"; + public const string Bpp1TranspPartial = "Icon/1bpp_transp_partial.ico"; + public const string Bpp24Size15x15 = "Icon/24bpp_size_15x15.ico"; + public const string Bpp24Size16x16 = "Icon/24bpp_size_16x16.ico"; + public const string Bpp24Size17x17 = "Icon/24bpp_size_17x17.ico"; + public const string Bpp24Size1x1 = "Icon/24bpp_size_1x1.ico"; + public const string Bpp24Size256x256 = "Icon/24bpp_size_256x256.ico"; + public const string Bpp24Size2x2 = "Icon/24bpp_size_2x2.ico"; + public const string Bpp24Size31x31 = "Icon/24bpp_size_31x31.ico"; + public const string Bpp24Size32x32 = "Icon/24bpp_size_32x32.ico"; + public const string Bpp24Size33x33 = "Icon/24bpp_size_33x33.ico"; + public const string Bpp24Size3x3 = "Icon/24bpp_size_3x3.ico"; + public const string Bpp24Size4x4 = "Icon/24bpp_size_4x4.ico"; + public const string Bpp24Size5x5 = "Icon/24bpp_size_5x5.ico"; + public const string Bpp24Size6x6 = "Icon/24bpp_size_6x6.ico"; + public const string Bpp24Size7x7 = "Icon/24bpp_size_7x7.ico"; + public const string Bpp24Size8x8 = "Icon/24bpp_size_8x8.ico"; + public const string Bpp24Size9x9 = "Icon/24bpp_size_9x9.ico"; + public const string Bpp24TranspNotSquare = "Icon/24bpp_transp_not_square.ico"; + public const string Bpp24TranspPartial = "Icon/24bpp_transp_partial.ico"; + public const string Bpp24Transp = "Icon/24bpp_transp.ico"; + public const string Bpp32Size15x15 = "Icon/32bpp_size_15x15.ico"; + public const string Bpp32Size16x16 = "Icon/32bpp_size_16x16.ico"; + public const string Bpp32Size17x17 = "Icon/32bpp_size_17x17.ico"; + public const string Bpp32Size1x1 = "Icon/32bpp_size_1x1.ico"; + public const string Bpp32Size256x256 = "Icon/32bpp_size_256x256.ico"; + public const string Bpp32Size2x2 = "Icon/32bpp_size_2x2.ico"; + public const string Bpp32Size31x31 = "Icon/32bpp_size_31x31.ico"; + public const string Bpp32Size32x32 = "Icon/32bpp_size_32x32.ico"; + public const string Bpp32Size33x33 = "Icon/32bpp_size_33x33.ico"; + public const string Bpp32Size3x3 = "Icon/32bpp_size_3x3.ico"; + public const string Bpp32Size4x4 = "Icon/32bpp_size_4x4.ico"; + public const string Bpp32Size5x5 = "Icon/32bpp_size_5x5.ico"; + public const string Bpp32Size6x6 = "Icon/32bpp_size_6x6.ico"; + public const string Bpp32Size7x7 = "Icon/32bpp_size_7x7.ico"; + public const string Bpp32Size8x8 = "Icon/32bpp_size_8x8.ico"; + public const string Bpp32Size9x9 = "Icon/32bpp_size_9x9.ico"; + public const string Bpp32TranspNotSquare = "Icon/32bpp_transp_not_square.ico"; + public const string Bpp32TranspPartial = "Icon/32bpp_transp_partial.ico"; + public const string Bpp32Transp = "Icon/32bpp_transp.ico"; + public const string Bpp4Size15x15 = "Icon/4bpp_size_15x15.ico"; + public const string Bpp4Size16x16 = "Icon/4bpp_size_16x16.ico"; + public const string Bpp4Size17x17 = "Icon/4bpp_size_17x17.ico"; + public const string Bpp4Size1x1 = "Icon/4bpp_size_1x1.ico"; + public const string Bpp4Size256x256 = "Icon/4bpp_size_256x256.ico"; + public const string Bpp4Size2x2 = "Icon/4bpp_size_2x2.ico"; + public const string Bpp4Size31x31 = "Icon/4bpp_size_31x31.ico"; + public const string Bpp4Size32x32 = "Icon/4bpp_size_32x32.ico"; + public const string Bpp4Size33x33 = "Icon/4bpp_size_33x33.ico"; + public const string Bpp4Size3x3 = "Icon/4bpp_size_3x3.ico"; + public const string Bpp4Size4x4 = "Icon/4bpp_size_4x4.ico"; + public const string Bpp4Size5x5 = "Icon/4bpp_size_5x5.ico"; + public const string Bpp4Size6x6 = "Icon/4bpp_size_6x6.ico"; + public const string Bpp4Size7x7 = "Icon/4bpp_size_7x7.ico"; + public const string Bpp4Size8x8 = "Icon/4bpp_size_8x8.ico"; + public const string Bpp4Size9x9 = "Icon/4bpp_size_9x9.ico"; + public const string Bpp4TranspNotSquare = "Icon/4bpp_transp_not_square.ico"; + public const string Bpp4TranspPartial = "Icon/4bpp_transp_partial.ico"; + public const string Bpp8Size15x15 = "Icon/8bpp_size_15x15.ico"; + public const string Bpp8Size16x16 = "Icon/8bpp_size_16x16.ico"; + public const string Bpp8Size17x17 = "Icon/8bpp_size_17x17.ico"; + public const string Bpp8Size1x1 = "Icon/8bpp_size_1x1.ico"; + public const string Bpp8Size256x256 = "Icon/8bpp_size_256x256.ico"; + public const string Bpp8Size2x2 = "Icon/8bpp_size_2x2.ico"; + public const string Bpp8Size31x31 = "Icon/8bpp_size_31x31.ico"; + public const string Bpp8Size32x32 = "Icon/8bpp_size_32x32.ico"; + public const string Bpp8Size33x33 = "Icon/8bpp_size_33x33.ico"; + public const string Bpp8Size3x3 = "Icon/8bpp_size_3x3.ico"; + public const string Bpp8Size4x4 = "Icon/8bpp_size_4x4.ico"; + public const string Bpp8Size5x5 = "Icon/8bpp_size_5x5.ico"; + public const string Bpp8Size6x6 = "Icon/8bpp_size_6x6.ico"; + public const string Bpp8Size7x7 = "Icon/8bpp_size_7x7.ico"; + public const string Bpp8Size8x8 = "Icon/8bpp_size_8x8.ico"; + public const string Bpp8Size9x9 = "Icon/8bpp_size_9x9.ico"; + public const string Bpp8TranspNotSquare = "Icon/8bpp_transp_not_square.ico"; + public const string Bpp8TranspPartial = "Icon/8bpp_transp_partial.ico"; + public const string InvalidAll = "Icon/invalid_all.ico"; + public const string InvalidBpp = "Icon/invalid_bpp.ico"; + public const string InvalidCompression = "Icon/invalid_compression.ico"; + public const string InvalidPng = "Icon/invalid_png.ico"; + public const string InvalidRLE4 = "Icon/invalid_RLE4.ico"; + public const string InvalidRLE8 = "Icon/invalid_RLE8.ico"; + public const string MixedBmpPngA = "Icon/mixed_bmp_png_a.ico"; + public const string MixedBmpPngB = "Icon/mixed_bmp_png_b.ico"; + public const string MixedBmpPngC = "Icon/mixed_bmp_png_c.ico"; + public const string MultiSizeA = "Icon/multi_size_a.ico"; + public const string MultiSizeB = "Icon/multi_size_b.ico"; + public const string MultiSizeC = "Icon/multi_size_c.ico"; + public const string MultiSizeD = "Icon/multi_size_d.ico"; + public const string MultiSizeE = "Icon/multi_size_e.ico"; + public const string MultiSizeF = "Icon/multi_size_f.ico"; + public const string MultiSizeMultiBitsA = "Icon/multi_size_multi_bits_a.ico"; + public const string MultiSizeMultiBitsB = "Icon/multi_size_multi_bits_b.ico"; + public const string MultiSizeMultiBitsC = "Icon/multi_size_multi_bits_c.ico"; + public const string MultiSizeMultiBitsD = "Icon/multi_size_multi_bits_d.ico"; + public const string IcoFake = "Icon/ico_fake.cur"; + } + + public static class Cur + { + public const string WindowsMouse = "Icon/aero_arrow.cur"; + public const string CurReal = "Icon/cur_real.cur"; + public const string CurFake = "Icon/cur_fake.ico"; + } } diff --git a/tests/ImageSharp.Tests/TestUtilities/ApproximateFloatComparer.cs b/tests/ImageSharp.Tests/TestUtilities/ApproximateFloatComparer.cs index e35f36feec..21ac6966b8 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ApproximateFloatComparer.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ApproximateFloatComparer.cs @@ -4,7 +4,6 @@ using System.Diagnostics.CodeAnalysis; using System.Numerics; using System.Runtime.Intrinsics; -using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Tests; @@ -14,7 +13,6 @@ namespace SixLabors.ImageSharp.Tests; internal readonly struct ApproximateFloatComparer : IEqualityComparer, IEqualityComparer, - IEqualityComparer, IEqualityComparer, IEqualityComparer, IEqualityComparer> @@ -47,13 +45,6 @@ public bool Equals(Vector2 x, Vector2 y) public int GetHashCode(Vector2 obj) => obj.GetHashCode(); - /// - public bool Equals(IPixel x, IPixel y) - => this.Equals(x.ToScaledVector4(), y.ToScaledVector4()); - - public int GetHashCode(IPixel obj) - => obj.ToScaledVector4().GetHashCode(); - /// public bool Equals(Vector4 x, Vector4 y) => this.Equals(x.X, y.X) diff --git a/tests/ImageSharp.Tests/TestUtilities/BasicSerializer.cs b/tests/ImageSharp.Tests/TestUtilities/BasicSerializer.cs index d161b80197..216ed95b8b 100644 --- a/tests/ImageSharp.Tests/TestUtilities/BasicSerializer.cs +++ b/tests/ImageSharp.Tests/TestUtilities/BasicSerializer.cs @@ -13,14 +13,14 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities; /// internal class BasicSerializer : IXunitSerializationInfo { - private readonly Dictionary map = new Dictionary(); + private readonly Dictionary map = []; public const char Separator = ':'; private string DumpToString(Type type) { - using var ms = new MemoryStream(); - using var writer = new StreamWriter(ms); + using MemoryStream ms = new(); + using StreamWriter writer = new(ms); writer.WriteLine(type.FullName); foreach (KeyValuePair kv in this.map) { @@ -29,16 +29,16 @@ private string DumpToString(Type type) writer.Flush(); byte[] data = ms.ToArray(); - return System.Convert.ToBase64String(data); + return Convert.ToBase64String(data); } private Type LoadDump(string dump) { - byte[] data = System.Convert.FromBase64String(dump); + byte[] data = Convert.FromBase64String(dump); - using var ms = new MemoryStream(data); - using var reader = new StreamReader(ms); - var type = Type.GetType(reader.ReadLine()); + using MemoryStream ms = new(data); + using StreamReader reader = new(ms); + Type type = Type.GetType(reader.ReadLine()); for (string s = reader.ReadLine(); s != null; s = reader.ReadLine()) { string[] kv = s.Split(Separator); @@ -50,7 +50,7 @@ private Type LoadDump(string dump) public static string Serialize(IXunitSerializable serializable) { - var serializer = new BasicSerializer(); + BasicSerializer serializer = new(); serializable.Serialize(serializer); return serializer.DumpToString(serializable.GetType()); } @@ -58,10 +58,10 @@ public static string Serialize(IXunitSerializable serializable) public static T Deserialize(string dump) where T : IXunitSerializable { - var serializer = new BasicSerializer(); + BasicSerializer serializer = new(); Type type = serializer.LoadDump(dump); - var result = (T)Activator.CreateInstance(type); + T result = (T)Activator.CreateInstance(type); result.Deserialize(serializer); return result; } diff --git a/tests/ImageSharp.Tests/TestUtilities/FeatureTesting/FeatureTestRunner.cs b/tests/ImageSharp.Tests/TestUtilities/FeatureTesting/FeatureTestRunner.cs index 5a9a72f967..07ad5e8f03 100644 --- a/tests/ImageSharp.Tests/TestUtilities/FeatureTesting/FeatureTestRunner.cs +++ b/tests/ImageSharp.Tests/TestUtilities/FeatureTesting/FeatureTestRunner.cs @@ -2,6 +2,7 @@ // Licensed under the Six Labors Split License. using System.Diagnostics; +using System.Globalization; using Microsoft.DotNet.RemoteExecutor; using Xunit.Abstractions; @@ -12,7 +13,7 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities; /// public static class FeatureTestRunner { - private static readonly char[] SplitChars = { ',', ' ' }; + private static readonly char[] SplitChars = [',', ' ']; /// /// Allows the deserialization of parameters passed to the feature test. @@ -40,7 +41,7 @@ public static T DeserializeForXunit(string value) /// The value. public static T Deserialize(string value) where T : IConvertible - => (T)Convert.ChangeType(value, typeof(T)); + => (T)Convert.ChangeType(value, typeof(T), CultureInfo.InvariantCulture); /// /// Runs the given test within an environment @@ -127,6 +128,7 @@ public static void RunWithHwIntrinsicsFeature( /// Runs the given test within an environment /// where the given features. /// + /// The type of argument. /// The test action to run. /// The intrinsics features. /// The value to pass as a parameter to the test action. @@ -170,6 +172,7 @@ public static void RunWithHwIntrinsicsFeature( /// Runs the given test within an environment /// where the given features. /// + /// The type of argument. /// The test action to run. /// The intrinsics features. /// The value to pass as a parameter to the test action. @@ -214,6 +217,8 @@ public static void RunWithHwIntrinsicsFeature( /// Runs the given test within an environment /// where the given features. /// + /// The type of argument. + /// The addition type of argument. /// The test action to run. /// The intrinsics features. /// The value to pass as a parameter to the test action. @@ -261,6 +266,7 @@ public static void RunWithHwIntrinsicsFeature( /// Runs the given test within an environment /// where the given features. /// + /// The type of argument. /// The test action to run. /// The intrinsics features. /// The value to pass as a parameter to the test action. @@ -307,6 +313,7 @@ public static void RunWithHwIntrinsicsFeature( /// Runs the given test within an environment /// where the given features. /// + /// The type of argument. /// The test action to run. /// The value to pass as a parameter to the test action. /// The intrinsics features. @@ -350,6 +357,7 @@ public static void RunWithHwIntrinsicsFeature( /// Runs the given test within an environment /// where the given features. /// + /// The type of argument. /// The test action to run. /// The value to pass as a parameter #0 to the test action. /// The value to pass as a parameter #1 to the test action. @@ -395,10 +403,10 @@ public static void RunWithHwIntrinsicsFeature( internal static Dictionary ToFeatureKeyValueCollection(this HwIntrinsics intrinsics) { // Loop through and translate the given values into COMPlus equivalents - Dictionary features = new(); + Dictionary features = []; foreach (string intrinsic in intrinsics.ToString("G").Split(SplitChars, StringSplitOptions.RemoveEmptyEntries)) { - HwIntrinsics key = (HwIntrinsics)Enum.Parse(typeof(HwIntrinsics), intrinsic); + HwIntrinsics key = Enum.Parse(intrinsic); switch (intrinsic) { case nameof(HwIntrinsics.AllowAll): @@ -418,40 +426,47 @@ internal static Dictionary ToFeatureKeyValueCollection(thi } /// -/// See -/// -/// ends up impacting all SIMD support(including System.Numerics) -/// but not things like , , and . -/// +/// See /// [Flags] #pragma warning disable RCS1135 // Declare enum member with zero value (when enum has FlagsAttribute). -public enum HwIntrinsics +public enum HwIntrinsics : long #pragma warning restore RCS1135 // Declare enum member with zero value (when enum has FlagsAttribute). { // Use flags so we can pass multiple values without using params. // Don't base on 0 or use inverse for All as that doesn't translate to string values. - DisableHWIntrinsic = 1 << 0, - DisableSSE = 1 << 1, - DisableSSE2 = 1 << 2, - DisableAES = 1 << 3, - DisablePCLMULQDQ = 1 << 4, - DisableSSE3 = 1 << 5, - DisableSSSE3 = 1 << 6, - DisableSSE41 = 1 << 7, - DisableSSE42 = 1 << 8, - DisablePOPCNT = 1 << 9, - DisableAVX = 1 << 10, - DisableFMA = 1 << 11, - DisableAVX2 = 1 << 12, - DisableBMI1 = 1 << 13, - DisableBMI2 = 1 << 14, - DisableLZCNT = 1 << 15, - DisableArm64AdvSimd = 1 << 16, - DisableArm64Crc32 = 1 << 17, - DisableArm64Dp = 1 << 18, - DisableArm64Aes = 1 << 19, - DisableArm64Sha1 = 1 << 20, - DisableArm64Sha256 = 1 << 21, - AllowAll = 1 << 22 + DisableHWIntrinsic = 1L << 0, + DisableSSE = 1L << 1, + DisableSSE2 = 1L << 2, + DisableAES = 1L << 3, + DisablePCLMULQDQ = 1L << 4, + DisableSSE3 = 1L << 5, + DisableSSSE3 = 1L << 6, + DisableSSE41 = 1L << 7, + DisableSSE42 = 1L << 8, + DisablePOPCNT = 1L << 9, + DisableAVX = 1L << 10, + DisableFMA = 1L << 11, + DisableAVX2 = 1L << 12, + DisableAVXVNNI = 1L << 13, + DisableAVX512BW = 1L << 14, + DisableAVX512BW_VL = 1L << 15, + DisableAVX512CD = 1L << 16, + DisableAVX512CD_VL = 1L << 17, + DisableAVX512DQ = 1L << 18, + DisableAVX512DQ_VL = 1L << 19, + DisableAVX512F = 1L << 20, + DisableAVX512F_VL = 1L << 21, + DisableAVX512VBMI = 1L << 22, + DisableAVX512VBMI_VL = 1L << 23, + DisableBMI1 = 1L << 24, + DisableBMI2 = 1L << 25, + DisableLZCNT = 1L << 26, + DisableArm64AdvSimd = 1L << 27, + DisableArm64Crc32 = 1L << 28, + DisableArm64Dp = 1L << 29, + DisableArm64Aes = 1L << 30, + DisableArm64Sha1 = 1L << 31, + DisableArm64Sha256 = 1L << 32, + AllowAll = 1L << 33 } diff --git a/tests/ImageSharp.Tests/TestUtilities/ImageProviders/BasicTestPatternProvider.cs b/tests/ImageSharp.Tests/TestUtilities/ImageProviders/BasicTestPatternProvider.cs index 1e3ad3a5d5..813ed505d8 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImageProviders/BasicTestPatternProvider.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImageProviders/BasicTestPatternProvider.cs @@ -1,4 +1,4 @@ -// Copyright (c) Six Labors. +// Copyright (c) Six Labors. // Licensed under the Six Labors Split License. using System.Numerics; @@ -8,11 +8,14 @@ namespace SixLabors.ImageSharp.Tests; public abstract partial class TestImageProvider : IXunitSerializable { - public virtual TPixel GetExpectedBasicTestPatternPixelAt(int x, int y) + [Obsolete("Called by the de-serializer; should only be called by deriving classes for de-serialization purposes")] + public TestImageProvider() { - throw new NotSupportedException("GetExpectedBasicTestPatternPixelAt(x,y) only works with BasicTestPattern"); } + public virtual TPixel GetExpectedBasicTestPatternPixelAt(int x, int y) + => throw new NotSupportedException("GetExpectedBasicTestPatternPixelAt(x,y) only works with BasicTestPattern"); + private class BasicTestPatternProvider : BlankProvider { private static readonly TPixel TopLeftColor = Color.Red.ToPixel(); @@ -36,7 +39,7 @@ public BasicTestPatternProvider() public override Image GetImage() { - var result = new Image(this.Configuration, this.Width, this.Height); + Image result = new(this.Configuration, this.Width, this.Height); result.ProcessPixelRows(accessor => { int midY = this.Height / 2; @@ -46,16 +49,16 @@ public override Image GetImage() { Span row = accessor.GetRowSpan(y); - row.Slice(0, midX).Fill(TopLeftColor); - row.Slice(midX, this.Width - midX).Fill(TopRightColor); + row[..midX].Fill(TopLeftColor); + row[midX..this.Width].Fill(TopRightColor); } for (int y = midY; y < this.Height; y++) { Span row = accessor.GetRowSpan(y); - row.Slice(0, midX).Fill(BottomLeftColor); - row.Slice(midX, this.Width - midX).Fill(BottomRightColor); + row[..midX].Fill(BottomLeftColor); + row[midX..this.Width].Fill(BottomRightColor); } }); @@ -71,17 +74,10 @@ public override TPixel GetExpectedBasicTestPatternPixelAt(int x, int y) { return x < midX ? TopLeftColor : TopRightColor; } - else - { - return x < midX ? BottomLeftColor : BottomRightColor; - } - } - private static TPixel GetBottomRightColor() - { - TPixel bottomRightColor = default; - bottomRightColor.FromVector4(new Vector4(1f, 0f, 1f, 0.5f)); - return bottomRightColor; + return x < midX ? BottomLeftColor : BottomRightColor; } + + private static TPixel GetBottomRightColor() => TPixel.FromScaledVector4(new Vector4(1f, 0f, 1f, 0.5f)); } } diff --git a/tests/ImageSharp.Tests/TestUtilities/ImageProviders/SolidProvider.cs b/tests/ImageSharp.Tests/TestUtilities/ImageProviders/SolidProvider.cs index 8c5101013f..d78edf5bc3 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImageProviders/SolidProvider.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImageProviders/SolidProvider.cs @@ -51,7 +51,7 @@ public override string SourceFileOrDescription public override Image GetImage() { Image image = base.GetImage(); - Color color = new Rgba32(this.r, this.g, this.b, this.a); + Color color = Color.FromPixel(new Rgba32(this.r, this.g, this.b, this.a)); image.GetRootFramePixelBuffer().FastMemoryGroup.Fill(color.ToPixel()); return image; diff --git a/tests/ImageSharp.Tests/TestUtilities/ImageProviders/TestPatternProvider.cs b/tests/ImageSharp.Tests/TestUtilities/ImageProviders/TestPatternProvider.cs index 63307f7e21..405d048fc5 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImageProviders/TestPatternProvider.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImageProviders/TestPatternProvider.cs @@ -1,6 +1,7 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. +using System.Numerics; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; using Xunit.Abstractions; @@ -15,19 +16,19 @@ public abstract partial class TestImageProvider : IXunitSerializable /// private class TestPatternProvider : BlankProvider { - private static readonly Dictionary> TestImages = new Dictionary>(); + private static readonly Dictionary> TestImages = []; private static readonly TPixel[] BlackWhitePixels = - { - Color.Black.ToPixel(), - Color.White.ToPixel() - }; + [ + Color.Black.ToPixel(), + Color.White.ToPixel() + ]; private static readonly TPixel[] PinkBluePixels = - { - Color.HotPink.ToPixel(), - Color.Blue.ToPixel() - }; + [ + Color.HotPink.ToPixel(), + Color.Blue.ToPixel() + ]; public TestPatternProvider(int width, int height) : base(width, height) @@ -47,14 +48,15 @@ public override Image GetImage() { lock (TestImages) { - if (!TestImages.ContainsKey(this.SourceFileOrDescription)) + if (!TestImages.TryGetValue(this.SourceFileOrDescription, out Image value)) { - var image = new Image(this.Width, this.Height); + Image image = new(this.Width, this.Height); DrawTestPattern(image); - TestImages.Add(this.SourceFileOrDescription, image); + value = image; + TestImages.Add(this.SourceFileOrDescription, value); } - return TestImages[this.SourceFileOrDescription].Clone(this.Configuration); + return value.Clone(this.Configuration); } } @@ -75,12 +77,13 @@ private static void DrawTestPattern(Image image) /// /// Fills the top right quadrant with alternating solid vertical bars. /// + /// The pixel buffer. private static void VerticalBars(Buffer2D pixels) { // topLeft int left = pixels.Width / 2; int right = pixels.Width; - int top = 0; + const int top = 0; int bottom = pixels.Height / 2; int stride = pixels.Width / 12; if (stride < 1) @@ -96,7 +99,7 @@ private static void VerticalBars(Buffer2D pixels) if (x % stride == 0) { p++; - p = p % PinkBluePixels.Length; + p %= PinkBluePixels.Length; } pixels[x, y] = PinkBluePixels[p]; @@ -107,12 +110,13 @@ private static void VerticalBars(Buffer2D pixels) /// /// fills the top left quadrant with a black and white checker board. /// + /// The pixel buffer. private static void BlackWhiteChecker(Buffer2D pixels) { // topLeft - int left = 0; + const int left = 0; int right = pixels.Width / 2; - int top = 0; + const int top = 0; int bottom = pixels.Height / 2; int stride = pixels.Width / 6; @@ -122,63 +126,62 @@ private static void BlackWhiteChecker(Buffer2D pixels) if (y % stride is 0) { p++; - p = p % BlackWhitePixels.Length; + p %= BlackWhitePixels.Length; } - int pstart = p; + int pStart = p; for (int x = left; x < right; x++) { if (x % stride is 0) { p++; - p = p % BlackWhitePixels.Length; + p %= BlackWhitePixels.Length; } pixels[x, y] = BlackWhitePixels[p]; } - p = pstart; + p = pStart; } } /// /// Fills the bottom left quadrant with 3 horizontal bars in Red, Green and Blue with a alpha gradient from left (transparent) to right (solid). /// + /// The pixel buffer private static void TransparentGradients(Buffer2D pixels) { // topLeft - int left = 0; + const int left = 0; int right = pixels.Width / 2; int top = pixels.Height / 2; int bottom = pixels.Height; int height = (int)Math.Ceiling(pixels.Height / 6f); - var red = Color.Red.ToPixel().ToVector4(); // use real color so we can see how it translates in the test pattern - var green = Color.Green.ToPixel().ToVector4(); // use real color so we can see how it translates in the test pattern - var blue = Color.Blue.ToPixel().ToVector4(); // use real color so we can see how it translates in the test pattern - - var c = default(TPixel); + Vector4 red = Color.Red.ToPixel().ToVector4(); // use real color so we can see how it translates in the test pattern + Vector4 green = Color.Green.ToPixel().ToVector4(); // use real color so we can see how it translates in the test pattern + Vector4 blue = Color.Blue.ToPixel().ToVector4(); // use real color so we can see how it translates in the test pattern for (int x = left; x < right; x++) { - blue.W = red.W = green.W = (float)x / (float)right; + blue.W = red.W = green.W = x / (float)right; - c.FromVector4(red); + TPixel c = TPixel.FromVector4(red); int topBand = top; for (int y = topBand; y < top + height; y++) { pixels[x, y] = c; } - topBand = topBand + height; - c.FromVector4(green); + topBand += height; + c = TPixel.FromVector4(green); for (int y = topBand; y < topBand + height; y++) { pixels[x, y] = c; } - topBand = topBand + height; - c.FromVector4(blue); + topBand += height; + c = TPixel.FromVector4(blue); for (int y = topBand; y < bottom; y++) { pixels[x, y] = c; @@ -190,6 +193,7 @@ private static void TransparentGradients(Buffer2D pixels) /// Fills the bottom right quadrant with all the colors producible by converting iterating over a uint and unpacking it. /// A better algorithm could be used but it works /// + /// The pixel buffer. private static void Rainbow(Buffer2D pixels) { int left = pixels.Width / 2; @@ -199,19 +203,14 @@ private static void Rainbow(Buffer2D pixels) int pixelCount = left * top; uint stepsPerPixel = (uint)(uint.MaxValue / pixelCount); - TPixel c = default; - var t = new Rgba32(0); + Rgba32 t = default; for (int x = left; x < right; x++) { for (int y = top; y < bottom; y++) { t.PackedValue += stepsPerPixel; - var v = t.ToVector4(); - - // v.W = (x - left) / (float)left; - c.FromVector4(v); - pixels[x, y] = c; + pixels[x, y] = TPixel.FromRgba32(t); } } } diff --git a/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs b/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs index 2243c852d2..78e5c90204 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs @@ -1,6 +1,7 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. +using System.Globalization; using System.Reflection; using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.PixelFormats; @@ -62,7 +63,7 @@ private string GetTestOutputFileNameImpl( extension = ".bmp"; } - extension = extension.ToLower(); + extension = extension.ToLower(CultureInfo.InvariantCulture); if (extension[0] != '.') { @@ -86,7 +87,7 @@ private string GetTestOutputFileNameImpl( } } - details = details ?? string.Empty; + details ??= string.Empty; if (details != string.Empty) { details = '_' + details; @@ -277,8 +278,7 @@ public static void ModifyPixel(ImageFrame img, int x, int y, byt where TPixel : unmanaged, IPixel { TPixel pixel = img[x, y]; - Rgba64 rgbaPixel = default; - rgbaPixel.FromScaledVector4(pixel.ToScaledVector4()); + Rgba64 rgbaPixel = Rgba64.FromScaledVector4(pixel.ToScaledVector4()); ushort change = (ushort)Math.Round((perChannelChange / 255F) * 65535F); if (rgbaPixel.R + perChannelChange <= 255) @@ -317,7 +317,6 @@ public static void ModifyPixel(ImageFrame img, int x, int y, byt rgbaPixel.A -= perChannelChange; } - pixel.FromRgba64(rgbaPixel); - img[x, y] = pixel; + img[x, y] = TPixel.FromRgba64(rgbaPixel); } } diff --git a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs index 80b5536ebd..f96dc19ee0 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs @@ -5,6 +5,11 @@ using ImageMagick; using ImageMagick.Formats; using SixLabors.ImageSharp.Formats; +using SixLabors.ImageSharp.Formats.Bmp; +using SixLabors.ImageSharp.Formats.Jpeg; +using SixLabors.ImageSharp.Formats.Png; +using SixLabors.ImageSharp.Formats.Tiff; +using SixLabors.ImageSharp.Formats.Webp; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Metadata; using SixLabors.ImageSharp.PixelFormats; @@ -13,19 +18,34 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs; public class MagickReferenceDecoder : ImageDecoder { + private readonly IImageFormat imageFormat; private readonly bool validate; - public MagickReferenceDecoder() - : this(true) + public MagickReferenceDecoder(IImageFormat imageFormat) + : this(imageFormat, true) { } - public MagickReferenceDecoder(bool validate) => this.validate = validate; + public MagickReferenceDecoder(IImageFormat imageFormat, bool validate) + { + this.imageFormat = imageFormat; + this.validate = validate; + } + + public static MagickReferenceDecoder Png { get; } = new MagickReferenceDecoder(PngFormat.Instance); + + public static MagickReferenceDecoder Bmp { get; } = new MagickReferenceDecoder(BmpFormat.Instance); + + public static MagickReferenceDecoder Jpeg { get; } = new MagickReferenceDecoder(JpegFormat.Instance); - public static MagickReferenceDecoder Instance { get; } = new(); + public static MagickReferenceDecoder Tiff { get; } = new MagickReferenceDecoder(TiffFormat.Instance); + + public static MagickReferenceDecoder WebP { get; } = new MagickReferenceDecoder(WebpFormat.Instance); protected override Image Decode(DecoderOptions options, Stream stream, CancellationToken cancellationToken) { + ImageMetadata metadata = new(); + Configuration configuration = options.Configuration; BmpReadDefines bmpReadDefines = new() { @@ -44,7 +64,7 @@ protected override Image Decode(DecoderOptions options, Stream s settings.SetDefines(pngReadDefines); using MagickImageCollection magickImageCollection = new(stream, settings); - List> framesList = new(); + List> framesList = []; foreach (IMagickImage magicFrame in magickImageCollection) { ImageFrame frame = new(configuration, magicFrame.Width, magicFrame.Height); @@ -61,6 +81,11 @@ protected override Image Decode(DecoderOptions options, Stream s } else if (magicFrame.Depth is 16 or 14) { + if (this.imageFormat is PngFormat png) + { + metadata.GetPngMetadata().BitDepth = PngBitDepth.Bit16; + } + ushort[] data = pixels.ToShortArray(PixelMapping.RGBA); Span bytes = MemoryMarshal.Cast(data.AsSpan()); FromRgba64Bytes(configuration, bytes, framePixels); @@ -71,7 +96,7 @@ protected override Image Decode(DecoderOptions options, Stream s } } - return new Image(configuration, new ImageMetadata(), framesList); + return ReferenceCodecUtilities.EnsureDecodedMetadata(new(configuration, metadata, framesList), this.imageFormat); } protected override Image Decode(DecoderOptions options, Stream stream, CancellationToken cancellationToken) @@ -80,7 +105,11 @@ protected override Image Decode(DecoderOptions options, Stream stream, Cancellat protected override ImageInfo Identify(DecoderOptions options, Stream stream, CancellationToken cancellationToken) { using Image image = this.Decode(options, stream, cancellationToken); - return new(image.PixelType, image.Size, image.Metadata, new List(image.Frames.Select(x => x.Metadata))); + ImageMetadata metadata = image.Metadata; + return new(image.Size, metadata, new List(image.Frames.Select(x => x.Metadata))) + { + PixelType = metadata.GetDecodedPixelTypeInfo() + }; } private static void FromRgba32Bytes(Configuration configuration, Span rgbaBytes, IMemoryGroup destinationGroup) diff --git a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/ReferenceCodecUtilities.cs b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/ReferenceCodecUtilities.cs new file mode 100644 index 0000000000..e48116fed3 --- /dev/null +++ b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/ReferenceCodecUtilities.cs @@ -0,0 +1,94 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.Formats; +using SixLabors.ImageSharp.Formats.Bmp; +using SixLabors.ImageSharp.Formats.Gif; +using SixLabors.ImageSharp.Formats.Jpeg; +using SixLabors.ImageSharp.Formats.Pbm; +using SixLabors.ImageSharp.Formats.Png; +using SixLabors.ImageSharp.Formats.Qoi; +using SixLabors.ImageSharp.Formats.Tga; +using SixLabors.ImageSharp.Formats.Tiff; +using SixLabors.ImageSharp.Formats.Webp; +using SixLabors.ImageSharp.PixelFormats; + +namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs; + +internal static class ReferenceCodecUtilities +{ + /// + /// Ensures that the metadata is properly initialized for reference and test encoders which cannot initialize + /// metadata in the same manner as our built in decoders. + /// + /// The type of pixel format. + /// The decoded image. + /// The image format + /// The format is unknown. + public static Image EnsureDecodedMetadata(Image image, IImageFormat format) + where TPixel : unmanaged, IPixel + { + if (image.Metadata.DecodedImageFormat is null) + { + image.Metadata.DecodedImageFormat = format; + } + + foreach (ImageFrame frame in image.Frames) + { + frame.Metadata.DecodedImageFormat = format; + } + + switch (format) + { + case BmpFormat: + image.Metadata.GetBmpMetadata(); + break; + case GifFormat: + image.Metadata.GetGifMetadata(); + foreach (ImageFrame frame in image.Frames) + { + frame.Metadata.GetGifMetadata(); + } + + break; + case JpegFormat: + image.Metadata.GetJpegMetadata(); + break; + case PbmFormat: + image.Metadata.GetPbmMetadata(); + break; + case PngFormat: + image.Metadata.GetPngMetadata(); + foreach (ImageFrame frame in image.Frames) + { + frame.Metadata.GetPngMetadata(); + } + + break; + case QoiFormat: + image.Metadata.GetQoiMetadata(); + break; + case TgaFormat: + image.Metadata.GetTgaMetadata(); + break; + case TiffFormat: + image.Metadata.GetTiffMetadata(); + foreach (ImageFrame frame in image.Frames) + { + frame.Metadata.GetTiffMetadata(); + } + + break; + case WebpFormat: + image.Metadata.GetWebpMetadata(); + foreach (ImageFrame frame in image.Frames) + { + frame.Metadata.GetWebpMetadata(); + } + + break; + } + + return image; + } +} diff --git a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingReferenceDecoder.cs b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingReferenceDecoder.cs index a3408bedb4..14a655823d 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingReferenceDecoder.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingReferenceDecoder.cs @@ -1,23 +1,35 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. +#pragma warning disable CA1416 // Validate platform compatibility using SixLabors.ImageSharp.Formats; +using SixLabors.ImageSharp.Formats.Bmp; +using SixLabors.ImageSharp.Formats.Png; using SixLabors.ImageSharp.Metadata; using SixLabors.ImageSharp.PixelFormats; using SDBitmap = System.Drawing.Bitmap; -using SDImage = System.Drawing.Image; namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs; public class SystemDrawingReferenceDecoder : ImageDecoder { - public static SystemDrawingReferenceDecoder Instance { get; } = new SystemDrawingReferenceDecoder(); + private readonly IImageFormat imageFormat; + + public SystemDrawingReferenceDecoder(IImageFormat imageFormat) + => this.imageFormat = imageFormat; + + public static SystemDrawingReferenceDecoder Png { get; } = new SystemDrawingReferenceDecoder(PngFormat.Instance); + + public static SystemDrawingReferenceDecoder Bmp { get; } = new SystemDrawingReferenceDecoder(BmpFormat.Instance); protected override ImageInfo Identify(DecoderOptions options, Stream stream, CancellationToken cancellationToken) { - using SDBitmap sourceBitmap = new(stream); - PixelTypeInfo pixelType = new(SDImage.GetPixelFormatSize(sourceBitmap.PixelFormat)); - return new ImageInfo(pixelType, new(sourceBitmap.Width, sourceBitmap.Height), new ImageMetadata()); + using Image image = this.Decode(options, stream, cancellationToken); + ImageMetadata metadata = image.Metadata; + return new(image.Size, metadata, new List(image.Frames.Select(x => x.Metadata))) + { + PixelType = metadata.GetDecodedPixelTypeInfo() + }; } protected override Image Decode(DecoderOptions options, Stream stream, CancellationToken cancellationToken) @@ -42,7 +54,9 @@ protected override Image Decode(DecoderOptions options, Stream s g.DrawImage(sourceBitmap, 0, 0, sourceBitmap.Width, sourceBitmap.Height); } - return SystemDrawingBridge.From32bppArgbSystemDrawingBitmap(convertedBitmap); + return ReferenceCodecUtilities.EnsureDecodedMetadata( + SystemDrawingBridge.From32bppArgbSystemDrawingBitmap(convertedBitmap), + this.imageFormat); } protected override Image Decode(DecoderOptions options, Stream stream, CancellationToken cancellationToken) diff --git a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingReferenceEncoder.cs b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingReferenceEncoder.cs index d8dda2eea8..0789ab2634 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingReferenceEncoder.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingReferenceEncoder.cs @@ -1,6 +1,7 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. +#pragma warning disable CA1416 // Validate platform compatibility using System.Drawing.Imaging; using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.PixelFormats; diff --git a/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.Formats.cs b/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.Formats.cs index 9508de2469..e4bee955b9 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.Formats.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.Formats.cs @@ -71,13 +71,13 @@ private static Configuration CreateDefaultConfiguration() // Magick codecs should work on all platforms cfg.ConfigureCodecs( PngFormat.Instance, - MagickReferenceDecoder.Instance, + MagickReferenceDecoder.Png, pngEncoder, new PngImageFormatDetector()); cfg.ConfigureCodecs( BmpFormat.Instance, - IsWindows ? SystemDrawingReferenceDecoder.Instance : MagickReferenceDecoder.Instance, + IsWindows ? SystemDrawingReferenceDecoder.Bmp : MagickReferenceDecoder.Bmp, bmpEncoder, new BmpImageFormatDetector()); diff --git a/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs b/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs index 3c74b48938..05abedbd8e 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs @@ -692,29 +692,11 @@ internal static AllocatorBufferCapacityConfigurator LimitAllocatorBufferCapacity this TestImageProvider provider) where TPixel : unmanaged, IPixel { - var allocator = new TestMemoryAllocator(); + TestMemoryAllocator allocator = new(); provider.Configuration.MemoryAllocator = allocator; return new AllocatorBufferCapacityConfigurator(allocator, Unsafe.SizeOf()); } - internal static Image ToGrayscaleImage(this Buffer2D buffer, float scale) - { - var image = new Image(buffer.Width, buffer.Height); - - Assert.True(image.Frames.RootFrame.DangerousTryGetSinglePixelMemory(out Memory pixelMem)); - Span pixels = pixelMem.Span; - Span bufferSpan = buffer.DangerousGetSingleSpan(); - - for (int i = 0; i < bufferSpan.Length; i++) - { - float value = bufferSpan[i] * scale; - var v = new Vector4(value, value, value, 1f); - pixels[i].FromVector4(v); - } - - return image; - } - private class MakeOpaqueProcessor : IImageProcessor { public IImageProcessor CreatePixelSpecificProcessor(Configuration configuration, Image source, Rectangle sourceRectangle) @@ -735,7 +717,7 @@ protected override void OnFrameApply(ImageFrame source) Rectangle sourceRectangle = this.SourceRectangle; Configuration configuration = this.Configuration; - var operation = new RowOperation(configuration, sourceRectangle, source.PixelBuffer); + RowOperation operation = new(configuration, sourceRectangle, source.PixelBuffer); ParallelRowIterator.IterateRowIntervals( configuration, diff --git a/tests/ImageSharp.Tests/TestUtilities/TestPixel.cs b/tests/ImageSharp.Tests/TestUtilities/TestPixel.cs index fb879c7697..f0344e2b9c 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestPixel.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestPixel.cs @@ -35,14 +35,9 @@ public TestPixel(float red, float green, float blue, float alpha) public float Alpha { get; set; } - public TPixel AsPixel() - { - var pix = default(TPixel); - pix.FromScaledVector4(new Vector4(this.Red, this.Green, this.Blue, this.Alpha)); - return pix; - } + public TPixel AsPixel() => TPixel.FromScaledVector4(new Vector4(this.Red, this.Green, this.Blue, this.Alpha)); - internal Span AsSpan() => new(new[] { this.AsPixel() }); + internal Span AsSpan() => new([this.AsPixel()]); public void Deserialize(IXunitSerializationInfo info) { diff --git a/tests/ImageSharp.Tests/TestUtilities/TestUtils.cs b/tests/ImageSharp.Tests/TestUtilities/TestUtils.cs index 0b792b7fb0..fbdfb9d619 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestUtils.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestUtils.cs @@ -19,11 +19,11 @@ namespace SixLabors.ImageSharp.Tests; /// public static class TestUtils { - private static readonly Dictionary ClrTypes2PixelTypes = new Dictionary(); + private static readonly Dictionary ClrTypes2PixelTypes = new(); private static readonly Assembly ImageSharpAssembly = typeof(Rgba32).GetTypeInfo().Assembly; - private static readonly Dictionary PixelTypes2ClrTypes = new Dictionary(); + private static readonly Dictionary PixelTypes2ClrTypes = new(); private static readonly PixelTypes[] AllConcretePixelTypes = GetAllPixelTypes() .Except(new[] { PixelTypes.Undefined, PixelTypes.All }) @@ -52,7 +52,7 @@ static TestUtils() public static byte[] GetRandomBytes(int length, int seed = 42) { - var rnd = new Random(42); + Random rnd = new(seed); byte[] bytes = new byte[length]; rnd.NextBytes(bytes); return bytes; @@ -60,7 +60,7 @@ public static byte[] GetRandomBytes(int length, int seed = 42) internal static byte[] FillImageWithRandomBytes(Image image) { - byte[] expected = TestUtils.GetRandomBytes(image.Width * image.Height * 2); + byte[] expected = GetRandomBytes(image.Width * image.Height * 2); image.ProcessPixelRows(accessor => { int cnt = 0; @@ -84,9 +84,6 @@ public static bool IsEquivalentTo(this Image a, Image b, return false; } - var rgb1 = default(Rgb24); - var rgb2 = default(Rgb24); - Buffer2D pixA = a.GetRootFramePixelBuffer(); Buffer2D pixB = b.GetRootFramePixelBuffer(); for (int y = 0; y < a.Height; y++) @@ -105,11 +102,11 @@ public static bool IsEquivalentTo(this Image a, Image b, } else { - Rgba32 rgba = default; - ca.ToRgba32(ref rgba); - rgb1 = rgba.Rgb; - cb.ToRgba32(ref rgba); - rgb2 = rgba.Rgb; + Rgba32 rgba = ca.ToRgba32(); + Rgb24 rgb1 = rgba.Rgb; + + rgba = cb.ToRgba32(); + Rgb24 rgb2 = rgba.Rgb; if (!rgb1.Equals(rgb2)) { @@ -144,7 +141,7 @@ public static IEnumerable> ExpandAllTypes(this Pi return PixelTypes2ClrTypes; } - var result = new Dictionary(); + Dictionary result = new(); foreach (PixelTypes pt in AllConcretePixelTypes) { if (pixelTypes.HasAll(pt)) @@ -167,7 +164,7 @@ internal static bool HasAll(this PixelTypes pixelTypes, PixelTypes flagsToCheck) internal static Color GetColorByName(string colorName) { - var f = (FieldInfo)typeof(Color).GetMember(colorName)[0]; + FieldInfo f = (FieldInfo)typeof(Color).GetMember(colorName)[0]; return (Color)f.GetValue(null); } @@ -188,7 +185,7 @@ internal static void RunBufferCapacityLimitProcessorTest( int width = expected.Width; expected.Mutate(process); - var allocator = new TestMemoryAllocator(); + TestMemoryAllocator allocator = new(); provider.Configuration.MemoryAllocator = allocator; allocator.BufferCapacityInBytes = bufferCapacityInPixelRows * width * Unsafe.SizeOf(); @@ -301,9 +298,9 @@ public static void RunValidatingProcessorTestOnWrappedMemoryImage( using (Image image0 = provider.GetImage()) { Assert.True(image0.DangerousTryGetSinglePixelMemory(out Memory imageMem)); - var mmg = TestMemoryManager.CreateAsCopyOf(imageMem.Span); + TestMemoryManager mmg = TestMemoryManager.CreateAsCopyOf(imageMem.Span); - using (var image1 = Image.WrapMemory(mmg.Memory, image0.Width, image0.Height)) + using (Image image1 = Image.WrapMemory(mmg.Memory, image0.Width, image0.Height)) { image1.Mutate(process); image1.DebugSave( @@ -353,7 +350,7 @@ internal static void RunRectangleConstrainedValidatingProcessorTest( using (Image image = provider.GetImage()) { - var bounds = new Rectangle(image.Width / 4, image.Width / 4, image.Width / 2, image.Height / 2); + Rectangle bounds = new(image.Width / 4, image.Width / 4, image.Width / 2, image.Height / 2); image.Mutate(x => process(x, bounds)); image.DebugSave(provider, testOutputDetails, appendPixelTypeToFileName: appendPixelTypeToFileName); image.CompareToReferenceOutput(comparer, provider, testOutputDetails: testOutputDetails, appendPixelTypeToFileName: appendPixelTypeToFileName); @@ -384,7 +381,7 @@ public static IResampler GetResampler(string name) if (property is null) { - throw new Exception($"No resampler named '{name}"); + throw new InvalidOperationException($"No resampler named '{name}"); } return (IResampler)property.GetValue(null); diff --git a/tests/ImageSharp.Tests/TestUtilities/Tests/MagickReferenceCodecTests.cs b/tests/ImageSharp.Tests/TestUtilities/Tests/MagickReferenceCodecTests.cs index 81ea77b6b6..b818e80b05 100644 --- a/tests/ImageSharp.Tests/TestUtilities/Tests/MagickReferenceCodecTests.cs +++ b/tests/ImageSharp.Tests/TestUtilities/Tests/MagickReferenceCodecTests.cs @@ -7,14 +7,13 @@ using SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs; using Xunit.Abstractions; -// ReSharper disable InconsistentNaming namespace SixLabors.ImageSharp.Tests.TestUtilities.Tests; public class MagickReferenceCodecTests { public MagickReferenceCodecTests(ITestOutputHelper output) => this.Output = output; - private ITestOutputHelper Output { get; } + public ITestOutputHelper Output { get; } public const PixelTypes PixelTypesToTest32 = PixelTypes.Rgba32 | PixelTypes.Bgra32 | PixelTypes.Rgb24; @@ -32,8 +31,8 @@ public void MagickDecode_8BitDepthImage_IsEquivalentTo_SystemDrawingResult mImage = magickDecoder.Decode(DecoderOptions.Default, mStream); diff --git a/tests/ImageSharp.Tests/TestUtilities/Tests/ReferenceDecoderBenchmarks.cs b/tests/ImageSharp.Tests/TestUtilities/Tests/ReferenceDecoderBenchmarks.cs index 3a3fcefdbe..6e1eba28e8 100644 --- a/tests/ImageSharp.Tests/TestUtilities/Tests/ReferenceDecoderBenchmarks.cs +++ b/tests/ImageSharp.Tests/TestUtilities/Tests/ReferenceDecoderBenchmarks.cs @@ -47,7 +47,7 @@ public ReferenceDecoderBenchmarks(ITestOutputHelper output) public void BenchmarkMagickPngDecoder(TestImageProvider provider) where TPixel : unmanaged, IPixel { - this.BenchmarkDecoderImpl(PngBenchmarkFiles, new MagickReferenceDecoder(), "Magick Decode Png"); + this.BenchmarkDecoderImpl(PngBenchmarkFiles, MagickReferenceDecoder.Png, "Magick Decode Png"); } [Theory(Skip = SkipBenchmarks)] @@ -55,7 +55,7 @@ public void BenchmarkMagickPngDecoder(TestImageProvider provider public void BenchmarkSystemDrawingPngDecoder(TestImageProvider provider) where TPixel : unmanaged, IPixel { - this.BenchmarkDecoderImpl(PngBenchmarkFiles, new SystemDrawingReferenceDecoder(), "System.Drawing Decode Png"); + this.BenchmarkDecoderImpl(PngBenchmarkFiles, SystemDrawingReferenceDecoder.Png, "System.Drawing Decode Png"); } [Theory(Skip = SkipBenchmarks)] @@ -63,7 +63,7 @@ public void BenchmarkSystemDrawingPngDecoder(TestImageProvider p public void BenchmarkMagickBmpDecoder(TestImageProvider provider) where TPixel : unmanaged, IPixel { - this.BenchmarkDecoderImpl(BmpBenchmarkFiles, new MagickReferenceDecoder(), "Magick Decode Bmp"); + this.BenchmarkDecoderImpl(BmpBenchmarkFiles, MagickReferenceDecoder.Bmp, "Magick Decode Bmp"); } [Theory(Skip = SkipBenchmarks)] @@ -71,7 +71,7 @@ public void BenchmarkMagickBmpDecoder(TestImageProvider provider public void BenchmarkSystemDrawingBmpDecoder(TestImageProvider provider) where TPixel : unmanaged, IPixel { - this.BenchmarkDecoderImpl(BmpBenchmarkFiles, new SystemDrawingReferenceDecoder(), "System.Drawing Decode Bmp"); + this.BenchmarkDecoderImpl(BmpBenchmarkFiles, SystemDrawingReferenceDecoder.Bmp, "System.Drawing Decode Bmp"); } private void BenchmarkDecoderImpl(IEnumerable testFiles, IImageDecoder decoder, string info, int times = DefaultExecutionCount) diff --git a/tests/ImageSharp.Tests/TestUtilities/Tests/SystemDrawingReferenceCodecTests.cs b/tests/ImageSharp.Tests/TestUtilities/Tests/SystemDrawingReferenceCodecTests.cs index a89feb3c35..4608583791 100644 --- a/tests/ImageSharp.Tests/TestUtilities/Tests/SystemDrawingReferenceCodecTests.cs +++ b/tests/ImageSharp.Tests/TestUtilities/Tests/SystemDrawingReferenceCodecTests.cs @@ -93,7 +93,7 @@ public void OpenWithReferenceDecoder(TestImageProvider dummyProv { string path = TestFile.GetInputFileFullPath(TestImages.Png.Splash); using FileStream stream = File.OpenRead(path); - using Image image = SystemDrawingReferenceDecoder.Instance.Decode(DecoderOptions.Default, stream); + using Image image = SystemDrawingReferenceDecoder.Png.Decode(DecoderOptions.Default, stream); image.DebugSave(dummyProvider); } diff --git a/tests/ImageSharp.Tests/TestUtilities/Tests/TestImageProviderTests.cs b/tests/ImageSharp.Tests/TestUtilities/Tests/TestImageProviderTests.cs index 3dceaf2524..f33811206a 100644 --- a/tests/ImageSharp.Tests/TestUtilities/Tests/TestImageProviderTests.cs +++ b/tests/ImageSharp.Tests/TestUtilities/Tests/TestImageProviderTests.cs @@ -2,11 +2,12 @@ // Licensed under the Six Labors Split License. using System.Collections.Concurrent; -using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Formats; +using SixLabors.ImageSharp.Formats.Png; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Metadata; using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs; using Xunit.Abstractions; // ReSharper disable InconsistentNaming @@ -26,7 +27,7 @@ public class TestImageProviderTests TestImageProvider.File(TestImages.Bmp.F) }; - public static string[] AllBmpFiles = { TestImages.Bmp.F, TestImages.Bmp.Bit8 }; + public static string[] AllBmpFiles = [TestImages.Bmp.F, TestImages.Bmp.Bit8]; public TestImageProviderTests(ITestOutputHelper output) => this.Output = output; @@ -81,9 +82,9 @@ public void GetImage_WithCustomParameterlessDecoder_ShouldUtilizeCache( TestDecoder.DoTestThreadSafe( () => { - string testName = nameof(this.GetImage_WithCustomParameterlessDecoder_ShouldUtilizeCache); + const string testName = nameof(this.GetImage_WithCustomParameterlessDecoder_ShouldUtilizeCache); - var decoder = new TestDecoder(); + TestDecoder decoder = new(); decoder.InitCaller(testName); provider.GetImage(decoder); @@ -302,12 +303,11 @@ public void Use_WithSolidFilledImagesAttribute(TestImageProvider Assert.Equal(20, img.Height); Buffer2D pixels = img.GetRootFramePixelBuffer(); - Rgba32 rgba = default; for (int y = 0; y < pixels.Height; y++) { for (int x = 0; x < pixels.Width; x++) { - pixels[x, y].ToRgba32(ref rgba); + Rgba32 rgba = pixels[x, y].ToRgba32(); Assert.Equal(255, rgba.R); Assert.Equal(100, rgba.G); @@ -337,7 +337,7 @@ private static void EnsureCustomConfigurationIsApplied(TestImageProvider { using (provider.GetImage()) { - var customConfiguration = Configuration.CreateDefaultInstance(); + Configuration customConfiguration = Configuration.CreateDefaultInstance(); provider.Configuration = customConfiguration; using Image image2 = provider.GetImage(); @@ -367,13 +367,17 @@ public static void DoTestThreadSafe(Action action) protected override ImageInfo Identify(DecoderOptions options, Stream stream, CancellationToken cancellationToken) { using Image image = this.Decode(this.CreateDefaultSpecializedOptions(options), stream, cancellationToken); - return new(image.PixelType, image.Size, image.Metadata, new List(image.Frames.Select(x => x.Metadata))); + ImageMetadata metadata = image.Metadata; + return new(image.Size, metadata, new List(image.Frames.Select(x => x.Metadata))) + { + PixelType = metadata.GetDecodedPixelTypeInfo() + }; } protected override Image Decode(TestDecoderOptions options, Stream stream, CancellationToken cancellationToken) { InvocationCounts[this.callerName]++; - return new Image(42, 42); + return ReferenceCodecUtilities.EnsureDecodedMetadata(new Image(42, 42), PngFormat.Instance); } protected override Image Decode(TestDecoderOptions options, Stream stream, CancellationToken cancellationToken) @@ -410,13 +414,17 @@ public static void DoTestThreadSafe(Action action) protected override ImageInfo Identify(DecoderOptions options, Stream stream, CancellationToken cancellationToken) { using Image image = this.Decode(this.CreateDefaultSpecializedOptions(options), stream, cancellationToken); - return new(image.PixelType, image.Size, image.Metadata, new List(image.Frames.Select(x => x.Metadata))); + ImageMetadata metadata = image.Metadata; + return new(image.Size, metadata, new List(image.Frames.Select(x => x.Metadata))) + { + PixelType = metadata.GetDecodedPixelTypeInfo() + }; } protected override Image Decode(TestDecoderWithParametersOptions options, Stream stream, CancellationToken cancellationToken) { InvocationCounts[this.callerName]++; - return new Image(42, 42); + return ReferenceCodecUtilities.EnsureDecodedMetadata(new Image(42, 42), PngFormat.Instance); } protected override Image Decode(TestDecoderWithParametersOptions options, Stream stream, CancellationToken cancellationToken) diff --git a/tests/ImageSharp.Tests/TestUtilities/Tests/TestUtilityExtensionsTests.cs b/tests/ImageSharp.Tests/TestUtilities/Tests/TestUtilityExtensionsTests.cs index 33ee68068f..46fb7159e8 100644 --- a/tests/ImageSharp.Tests/TestUtilities/Tests/TestUtilityExtensionsTests.cs +++ b/tests/ImageSharp.Tests/TestUtilities/Tests/TestUtilityExtensionsTests.cs @@ -21,20 +21,17 @@ public TestUtilityExtensionsTests(ITestOutputHelper output) public static Image CreateTestImage() where TPixel : unmanaged, IPixel { - var image = new Image(10, 10); + Image image = new(10, 10); Buffer2D pixels = image.GetRootFramePixelBuffer(); for (int i = 0; i < 10; i++) { for (int j = 0; j < 10; j++) { - var v = new Vector4(i, j, 0, 1); + Vector4 v = new(i, j, 0, 1); v /= 10; - var color = default(TPixel); - color.FromVector4(v); - - pixels[i, j] = color; + pixels[i, j] = TPixel.FromVector4(v); } } diff --git a/tests/Images/External/ReferenceOutput/TgaDecoderTests/TgaDecoder_CanDecode_WhenAlphaBitsNotSet_Rgba32_32bit_no_alphabits.png b/tests/Images/External/ReferenceOutput/TgaDecoderTests/TgaDecoder_CanDecode_WhenAlphaBitsNotSet_Rgba32_32bit_no_alphabits.png deleted file mode 100644 index e12985f7ae..0000000000 --- a/tests/Images/External/ReferenceOutput/TgaDecoderTests/TgaDecoder_CanDecode_WhenAlphaBitsNotSet_Rgba32_32bit_no_alphabits.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:d3dc0516f656c14b5ffcc40f88d3912f2a8fb310dfbda5836e15847e205919b5 -size 1012 diff --git a/tests/Images/External/ReferenceOutput/TgaDecoderTests/TgaDecoder_CanDecode_WhenAlphaBitsNotSet_Rgba32_32bit_rle_no_alphabits.png b/tests/Images/External/ReferenceOutput/TgaDecoderTests/TgaDecoder_CanDecode_WhenAlphaBitsNotSet_Rgba32_32bit_rle_no_alphabits.png deleted file mode 100644 index 726721824e..0000000000 --- a/tests/Images/External/ReferenceOutput/TgaDecoderTests/TgaDecoder_CanDecode_WhenAlphaBitsNotSet_Rgba32_32bit_rle_no_alphabits.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:cad24c7e4657f2bc8d8a60ea76397eac0adf8dee5fc81f60bc5bc02dd7eeed8f -size 90589 diff --git a/tests/Images/External/ReferenceOutput/TiffDecoderTests/TiffDecoder_CanDecode_JpegCompressedWithIssue2679_Issue2679.png b/tests/Images/External/ReferenceOutput/TiffDecoderTests/TiffDecoder_CanDecode_JpegCompressedWithIssue2679_Issue2679.png new file mode 100644 index 0000000000..6150aacb37 --- /dev/null +++ b/tests/Images/External/ReferenceOutput/TiffDecoderTests/TiffDecoder_CanDecode_JpegCompressedWithIssue2679_Issue2679.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6cd36c7e07a08e22cceecd28a056c80e5553a8c092bfc091e902d13bd5c46f4d +size 120054 diff --git a/tests/Images/Input/Icon/1bpp_size_15x15.ico b/tests/Images/Input/Icon/1bpp_size_15x15.ico new file mode 100644 index 0000000000..39fc9c521c --- /dev/null +++ b/tests/Images/Input/Icon/1bpp_size_15x15.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:846dda605ee23bb641534b272fa57300eacd85038feea5dd1a3f6d4b543a935e +size 190 diff --git a/tests/Images/Input/Icon/1bpp_size_16x16.ico b/tests/Images/Input/Icon/1bpp_size_16x16.ico new file mode 100644 index 0000000000..6179678bce --- /dev/null +++ b/tests/Images/Input/Icon/1bpp_size_16x16.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:029d0438eda83d4d9e087cf79abe2d0234728c37f570de808355c0e79c71be17 +size 198 diff --git a/tests/Images/Input/Icon/1bpp_size_17x17.ico b/tests/Images/Input/Icon/1bpp_size_17x17.ico new file mode 100644 index 0000000000..90138a08d5 --- /dev/null +++ b/tests/Images/Input/Icon/1bpp_size_17x17.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8db024a49fdd91c9d5d1fc0c1d6f60991518a5776031f58cdafbdd3ed9e4f26b +size 206 diff --git a/tests/Images/Input/Icon/1bpp_size_1x1.ico b/tests/Images/Input/Icon/1bpp_size_1x1.ico new file mode 100644 index 0000000000..1161a3f3cb --- /dev/null +++ b/tests/Images/Input/Icon/1bpp_size_1x1.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f13d1bbfa5b29bc386270cb492b705eded0825a9eb3a6341f4ea2b3dbe085cd1 +size 78 diff --git a/tests/Images/Input/Icon/1bpp_size_256x256.ico b/tests/Images/Input/Icon/1bpp_size_256x256.ico new file mode 100644 index 0000000000..d6524a31f2 --- /dev/null +++ b/tests/Images/Input/Icon/1bpp_size_256x256.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c1aa37daf2fd65b424c5e13e94bed165328e624584cc5664d73bb4030a1e1f12 +size 16454 diff --git a/tests/Images/Input/Icon/1bpp_size_2x2.ico b/tests/Images/Input/Icon/1bpp_size_2x2.ico new file mode 100644 index 0000000000..73394156aa --- /dev/null +++ b/tests/Images/Input/Icon/1bpp_size_2x2.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:18be2a5384812de1bec70733fb0b283a159edc5d0bc03981de8fb3ccddb8911e +size 86 diff --git a/tests/Images/Input/Icon/1bpp_size_31x31.ico b/tests/Images/Input/Icon/1bpp_size_31x31.ico new file mode 100644 index 0000000000..8dffe659f5 --- /dev/null +++ b/tests/Images/Input/Icon/1bpp_size_31x31.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a3a4e7964e3ed5ca2a98929e2f903a6b969961410aab6a935a0c54fbe716d0c3 +size 318 diff --git a/tests/Images/Input/Icon/1bpp_size_32x32.ico b/tests/Images/Input/Icon/1bpp_size_32x32.ico new file mode 100644 index 0000000000..e281eb3785 --- /dev/null +++ b/tests/Images/Input/Icon/1bpp_size_32x32.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:06a55f8219234e43beec6776fe15a7d6d4ad314deaf64df115ea45f2100e5283 +size 326 diff --git a/tests/Images/Input/Icon/1bpp_size_33x33.ico b/tests/Images/Input/Icon/1bpp_size_33x33.ico new file mode 100644 index 0000000000..c5e4677d3a --- /dev/null +++ b/tests/Images/Input/Icon/1bpp_size_33x33.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:82fa82f6b954515eace3cdd6d4681abd149b37354a7dee4f0d1966f516f27850 +size 598 diff --git a/tests/Images/Input/Icon/1bpp_size_3x3.ico b/tests/Images/Input/Icon/1bpp_size_3x3.ico new file mode 100644 index 0000000000..89872b9595 --- /dev/null +++ b/tests/Images/Input/Icon/1bpp_size_3x3.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5ff0bf1c415925642d99691a9a9a6b92d9995447bc62ed80b9b0c6d4efdcd19b +size 94 diff --git a/tests/Images/Input/Icon/1bpp_size_4x4.ico b/tests/Images/Input/Icon/1bpp_size_4x4.ico new file mode 100644 index 0000000000..1e47b45963 --- /dev/null +++ b/tests/Images/Input/Icon/1bpp_size_4x4.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5853ba73b06e0f2a0c71850011526419db3bd7c76e5b7b2f6b22f748ce919bf2 +size 102 diff --git a/tests/Images/Input/Icon/1bpp_size_5x5.ico b/tests/Images/Input/Icon/1bpp_size_5x5.ico new file mode 100644 index 0000000000..5152c75755 --- /dev/null +++ b/tests/Images/Input/Icon/1bpp_size_5x5.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ecd253a6862ec9a9870c8a8a370528b28c22d23247dfc29e09fab65d95b9416d +size 110 diff --git a/tests/Images/Input/Icon/1bpp_size_6x6.ico b/tests/Images/Input/Icon/1bpp_size_6x6.ico new file mode 100644 index 0000000000..a1d5c09c04 --- /dev/null +++ b/tests/Images/Input/Icon/1bpp_size_6x6.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a80c7f8d37dc3997bcd674a5af835cae802cacbf5d65020f0aaae67f70cfc31e +size 118 diff --git a/tests/Images/Input/Icon/1bpp_size_7x7.ico b/tests/Images/Input/Icon/1bpp_size_7x7.ico new file mode 100644 index 0000000000..9c5a227e30 --- /dev/null +++ b/tests/Images/Input/Icon/1bpp_size_7x7.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:00a26274e8563e6378f8bfa4d1aa9695030593a38791ca366cecd3949b0f52af +size 126 diff --git a/tests/Images/Input/Icon/1bpp_size_8x8.ico b/tests/Images/Input/Icon/1bpp_size_8x8.ico new file mode 100644 index 0000000000..c019914ee0 --- /dev/null +++ b/tests/Images/Input/Icon/1bpp_size_8x8.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:78150aee2f5d5ccd2a172abfe11f1127efb950cb9173e22e380809afb2a94d3c +size 134 diff --git a/tests/Images/Input/Icon/1bpp_size_9x9.ico b/tests/Images/Input/Icon/1bpp_size_9x9.ico new file mode 100644 index 0000000000..2f3fd28eb0 --- /dev/null +++ b/tests/Images/Input/Icon/1bpp_size_9x9.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d8cecf833b31208710c1dde1bed3322a95453468a3f4b39afdad66ac9bc5f86b +size 142 diff --git a/tests/Images/Input/Icon/1bpp_transp_not_square.ico b/tests/Images/Input/Icon/1bpp_transp_not_square.ico new file mode 100644 index 0000000000..1c678ec40e --- /dev/null +++ b/tests/Images/Input/Icon/1bpp_transp_not_square.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bd9f41711b53d4e1e915ddb992522b97a981fbe3f4536826f0c66e2d6a3677fb +size 182 diff --git a/tests/Images/Input/Icon/1bpp_transp_partial.ico b/tests/Images/Input/Icon/1bpp_transp_partial.ico new file mode 100644 index 0000000000..6365a53df8 --- /dev/null +++ b/tests/Images/Input/Icon/1bpp_transp_partial.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:cedcd221abf4b95115f9f8f34f15da456b09e7e56972cced24a99fa56bf8aca9 +size 326 diff --git a/tests/Images/Input/Icon/24bpp_size_15x15.ico b/tests/Images/Input/Icon/24bpp_size_15x15.ico new file mode 100644 index 0000000000..f8697e2b5b --- /dev/null +++ b/tests/Images/Input/Icon/24bpp_size_15x15.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b506403852d936d14975ed9aba1c50ab3873cbbd81afcf38381f8e5e841fafd0 +size 842 diff --git a/tests/Images/Input/Icon/24bpp_size_16x16.ico b/tests/Images/Input/Icon/24bpp_size_16x16.ico new file mode 100644 index 0000000000..e6de107d78 --- /dev/null +++ b/tests/Images/Input/Icon/24bpp_size_16x16.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8bfa9de0f613e9e82e9037193c4124f87d05ac1390459e2f018da45c16200de6 +size 894 diff --git a/tests/Images/Input/Icon/24bpp_size_17x17.ico b/tests/Images/Input/Icon/24bpp_size_17x17.ico new file mode 100644 index 0000000000..2c37ffa8b0 --- /dev/null +++ b/tests/Images/Input/Icon/24bpp_size_17x17.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a4cd2ad22e55000a706d365e0a3395f3e4d9a3933c00880d5f12903ac0aed60e +size 1014 diff --git a/tests/Images/Input/Icon/24bpp_size_1x1.ico b/tests/Images/Input/Icon/24bpp_size_1x1.ico new file mode 100644 index 0000000000..f9137f61ae --- /dev/null +++ b/tests/Images/Input/Icon/24bpp_size_1x1.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3b20e9a6479c3831b7af75d30bc909ce3046e45384bfd62d7a10ac6816c1c947 +size 70 diff --git a/tests/Images/Input/Icon/24bpp_size_256x256.ico b/tests/Images/Input/Icon/24bpp_size_256x256.ico new file mode 100644 index 0000000000..08f928c8e4 --- /dev/null +++ b/tests/Images/Input/Icon/24bpp_size_256x256.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1175641f39e68bd6cd38b8f64f02510b22c5a642afc7503d357b064163b3d37b +size 204862 diff --git a/tests/Images/Input/Icon/24bpp_size_2x2.ico b/tests/Images/Input/Icon/24bpp_size_2x2.ico new file mode 100644 index 0000000000..d6d472a255 --- /dev/null +++ b/tests/Images/Input/Icon/24bpp_size_2x2.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:72a1380a306b51ae37eabd3edeb0b134b0f8e8e120e6c64b6b08bd833a9c70a4 +size 86 diff --git a/tests/Images/Input/Icon/24bpp_size_31x31.ico b/tests/Images/Input/Icon/24bpp_size_31x31.ico new file mode 100644 index 0000000000..5c585c582b --- /dev/null +++ b/tests/Images/Input/Icon/24bpp_size_31x31.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:574b0971908b44334f1f3be79e5b0ff336e74a8b9947b43a295d3a2b86733965 +size 3162 diff --git a/tests/Images/Input/Icon/24bpp_size_32x32.ico b/tests/Images/Input/Icon/24bpp_size_32x32.ico new file mode 100644 index 0000000000..3663b87673 --- /dev/null +++ b/tests/Images/Input/Icon/24bpp_size_32x32.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fa45880e5611436fc06de0603481d0a61044e52a1a053961fdda1139bb5660a6 +size 3262 diff --git a/tests/Images/Input/Icon/24bpp_size_33x33.ico b/tests/Images/Input/Icon/24bpp_size_33x33.ico new file mode 100644 index 0000000000..4834b48c86 --- /dev/null +++ b/tests/Images/Input/Icon/24bpp_size_33x33.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8704a77d6264f6f104e23950099e3d3a4a577787e67c7c39d7925f9d0a347572 +size 3626 diff --git a/tests/Images/Input/Icon/24bpp_size_3x3.ico b/tests/Images/Input/Icon/24bpp_size_3x3.ico new file mode 100644 index 0000000000..f2c11ccfec --- /dev/null +++ b/tests/Images/Input/Icon/24bpp_size_3x3.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:81229c27fbc684c0da99b1b04189046d5b9f531ee4111ccc43bde6404dce4f12 +size 110 diff --git a/tests/Images/Input/Icon/24bpp_size_4x4.ico b/tests/Images/Input/Icon/24bpp_size_4x4.ico new file mode 100644 index 0000000000..2d7880a03b --- /dev/null +++ b/tests/Images/Input/Icon/24bpp_size_4x4.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f7cb620eb83acbf20d308f5c6cb8b0246b8b156cdcc43e39f5809754fd4d5ddb +size 126 diff --git a/tests/Images/Input/Icon/24bpp_size_5x5.ico b/tests/Images/Input/Icon/24bpp_size_5x5.ico new file mode 100644 index 0000000000..a98c85c197 --- /dev/null +++ b/tests/Images/Input/Icon/24bpp_size_5x5.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bdf1718e3d9695cdf2552e42219d1e3166ad5a94f53cbb44db4a7222e2a32f9a +size 162 diff --git a/tests/Images/Input/Icon/24bpp_size_6x6.ico b/tests/Images/Input/Icon/24bpp_size_6x6.ico new file mode 100644 index 0000000000..5dd3c57c2c --- /dev/null +++ b/tests/Images/Input/Icon/24bpp_size_6x6.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1e5f3a8f59e297cf67251a89558d4406c4c515c3e3ce7555df4a53ef5420fc38 +size 206 diff --git a/tests/Images/Input/Icon/24bpp_size_7x7.ico b/tests/Images/Input/Icon/24bpp_size_7x7.ico new file mode 100644 index 0000000000..d9622629e7 --- /dev/null +++ b/tests/Images/Input/Icon/24bpp_size_7x7.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0ee1b5836c9f8c89e9b8c8873f1ad92f7555ed9706f4dc76345a727bf3e9f334 +size 258 diff --git a/tests/Images/Input/Icon/24bpp_size_8x8.ico b/tests/Images/Input/Icon/24bpp_size_8x8.ico new file mode 100644 index 0000000000..39be58ce45 --- /dev/null +++ b/tests/Images/Input/Icon/24bpp_size_8x8.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b46ca32ddb84074d9140224738480eaa0a6c0dce2dbf2074625add1901c27117 +size 286 diff --git a/tests/Images/Input/Icon/24bpp_size_9x9.ico b/tests/Images/Input/Icon/24bpp_size_9x9.ico new file mode 100644 index 0000000000..9e7873eaf1 --- /dev/null +++ b/tests/Images/Input/Icon/24bpp_size_9x9.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7454d6332f4bdba929d610e4a8a232b1443d5a64119de4e69c00e0f03e55e237 +size 350 diff --git a/tests/Images/Input/Icon/24bpp_transp.ico b/tests/Images/Input/Icon/24bpp_transp.ico new file mode 100644 index 0000000000..a64157a63b --- /dev/null +++ b/tests/Images/Input/Icon/24bpp_transp.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:eb8ea41822350e5f40bac2aef19ec7a4c40561ce6637948b3fa6db7835c1fded +size 3262 diff --git a/tests/Images/Input/Icon/24bpp_transp_not_square.ico b/tests/Images/Input/Icon/24bpp_transp_not_square.ico new file mode 100644 index 0000000000..5abf2ad66a --- /dev/null +++ b/tests/Images/Input/Icon/24bpp_transp_not_square.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:44b4c79ff497df0e99f55d68d82f59c0d7c2f4d5e9bb63bcc1b5910f4a2853db +size 1126 diff --git a/tests/Images/Input/Icon/24bpp_transp_partial.ico b/tests/Images/Input/Icon/24bpp_transp_partial.ico new file mode 100644 index 0000000000..d1a37498b6 --- /dev/null +++ b/tests/Images/Input/Icon/24bpp_transp_partial.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f8d109413d7f699b92e9d6a5e2c52d2b5c747f2ca9ff31d326f8d4ec2fd5840f +size 3262 diff --git a/tests/Images/Input/Icon/32bpp_size_15x15.ico b/tests/Images/Input/Icon/32bpp_size_15x15.ico new file mode 100644 index 0000000000..a7f94e94dc --- /dev/null +++ b/tests/Images/Input/Icon/32bpp_size_15x15.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:02b5abd8e15ef2fba1a26cdbdf6e8f66abbbf9aa188404ef911a1d2d02b7b050 +size 1022 diff --git a/tests/Images/Input/Icon/32bpp_size_16x16.ico b/tests/Images/Input/Icon/32bpp_size_16x16.ico new file mode 100644 index 0000000000..609a51826b --- /dev/null +++ b/tests/Images/Input/Icon/32bpp_size_16x16.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:50bb07bd12f9b388ba6a3abbb815aaf1c800438e35ec48201269fa23342e5622 +size 1150 diff --git a/tests/Images/Input/Icon/32bpp_size_17x17.ico b/tests/Images/Input/Icon/32bpp_size_17x17.ico new file mode 100644 index 0000000000..13a71140f6 --- /dev/null +++ b/tests/Images/Input/Icon/32bpp_size_17x17.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6bf4c701d38fc988186e3fcfee6e426ed5a84807b54b91e4ab8c1b12e0794746 +size 1286 diff --git a/tests/Images/Input/Icon/32bpp_size_1x1.ico b/tests/Images/Input/Icon/32bpp_size_1x1.ico new file mode 100644 index 0000000000..3f449eefea --- /dev/null +++ b/tests/Images/Input/Icon/32bpp_size_1x1.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f62be892b36609a57c34eb4784dfb6dc82698ecd15709898a6579ee4f21f668e +size 70 diff --git a/tests/Images/Input/Icon/32bpp_size_256x256.ico b/tests/Images/Input/Icon/32bpp_size_256x256.ico new file mode 100644 index 0000000000..2229aee95e --- /dev/null +++ b/tests/Images/Input/Icon/32bpp_size_256x256.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b15f75adc54e70c4751cf9973854f225ef15b12bdaddb5ab00cb9edfd8b386b1 +size 270398 diff --git a/tests/Images/Input/Icon/32bpp_size_2x2.ico b/tests/Images/Input/Icon/32bpp_size_2x2.ico new file mode 100644 index 0000000000..cbb64292b0 --- /dev/null +++ b/tests/Images/Input/Icon/32bpp_size_2x2.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fa859752136cdf055874ae71589f9585aaaeaef804b13ce192991793d9e57e57 +size 86 diff --git a/tests/Images/Input/Icon/32bpp_size_31x31.ico b/tests/Images/Input/Icon/32bpp_size_31x31.ico new file mode 100644 index 0000000000..837e8f512b --- /dev/null +++ b/tests/Images/Input/Icon/32bpp_size_31x31.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d5ecf1dc1fdd3dc6cb2fd90b49632b19260e73ad3a6624372d1e9eefc470ed6b +size 4030 diff --git a/tests/Images/Input/Icon/32bpp_size_32x32.ico b/tests/Images/Input/Icon/32bpp_size_32x32.ico new file mode 100644 index 0000000000..b359d4d844 --- /dev/null +++ b/tests/Images/Input/Icon/32bpp_size_32x32.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:395ccdc596487ed63db4d893d03b6aa24743b37279d896196d8d38e7028415ea +size 4286 diff --git a/tests/Images/Input/Icon/32bpp_size_33x33.ico b/tests/Images/Input/Icon/32bpp_size_33x33.ico new file mode 100644 index 0000000000..01df9ae7dc --- /dev/null +++ b/tests/Images/Input/Icon/32bpp_size_33x33.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7e8b89c061abcf959b90149585cc34237aad19e1f67c162d62e5adbad4826970 +size 4682 diff --git a/tests/Images/Input/Icon/32bpp_size_3x3.ico b/tests/Images/Input/Icon/32bpp_size_3x3.ico new file mode 100644 index 0000000000..8879d3f1f2 --- /dev/null +++ b/tests/Images/Input/Icon/32bpp_size_3x3.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:52b7772a9c8fae189abc3cf37d5d24bcdfe94077e6b1cf7be8cc7e0bc6f6bddf +size 110 diff --git a/tests/Images/Input/Icon/32bpp_size_4x4.ico b/tests/Images/Input/Icon/32bpp_size_4x4.ico new file mode 100644 index 0000000000..d800b21983 --- /dev/null +++ b/tests/Images/Input/Icon/32bpp_size_4x4.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2bb0831fab10fb0ff9a0b2b2ea137609a45a6ec3982d594878996eafc32836ad +size 142 diff --git a/tests/Images/Input/Icon/32bpp_size_5x5.ico b/tests/Images/Input/Icon/32bpp_size_5x5.ico new file mode 100644 index 0000000000..710c38a23b --- /dev/null +++ b/tests/Images/Input/Icon/32bpp_size_5x5.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:10e2ed5cbacc761f2d467c22a8d72dcc4086b9423c5487ba05826804c642730a +size 182 diff --git a/tests/Images/Input/Icon/32bpp_size_6x6.ico b/tests/Images/Input/Icon/32bpp_size_6x6.ico new file mode 100644 index 0000000000..4223c1fc29 --- /dev/null +++ b/tests/Images/Input/Icon/32bpp_size_6x6.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1ab79a308d24592557b368f00566999d777e38de385eb6ebabc90d53ac723ae9 +size 230 diff --git a/tests/Images/Input/Icon/32bpp_size_7x7.ico b/tests/Images/Input/Icon/32bpp_size_7x7.ico new file mode 100644 index 0000000000..1e321acb6a --- /dev/null +++ b/tests/Images/Input/Icon/32bpp_size_7x7.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3799164811b0284535fa90ca60f13e9c0754ca4e8f00d96a83951e91e748d760 +size 286 diff --git a/tests/Images/Input/Icon/32bpp_size_8x8.ico b/tests/Images/Input/Icon/32bpp_size_8x8.ico new file mode 100644 index 0000000000..b44fe22d5c --- /dev/null +++ b/tests/Images/Input/Icon/32bpp_size_8x8.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2a3187750c9313024f983fdfca270f5db2c5d730831adfce0fb19ddac25deecc +size 350 diff --git a/tests/Images/Input/Icon/32bpp_size_9x9.ico b/tests/Images/Input/Icon/32bpp_size_9x9.ico new file mode 100644 index 0000000000..682b148ed9 --- /dev/null +++ b/tests/Images/Input/Icon/32bpp_size_9x9.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1ab8bd47cc2d2ce0e9c1a5810b5ccbe3f46e35001114c18f34cbf51ff0566bf6 +size 422 diff --git a/tests/Images/Input/Icon/32bpp_transp.ico b/tests/Images/Input/Icon/32bpp_transp.ico new file mode 100644 index 0000000000..5925362903 --- /dev/null +++ b/tests/Images/Input/Icon/32bpp_transp.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b4f94718304fa41041b8cebad7b76762d410b366b46d620f5599b03a2fa7ba00 +size 4286 diff --git a/tests/Images/Input/Icon/32bpp_transp_not_square.ico b/tests/Images/Input/Icon/32bpp_transp_not_square.ico new file mode 100644 index 0000000000..3a0bb3dd00 --- /dev/null +++ b/tests/Images/Input/Icon/32bpp_transp_not_square.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6e3c2061b64df989e8ae68aee993eba5e11d03e23f282f063cc3929ec3ef2b0c +size 1462 diff --git a/tests/Images/Input/Icon/32bpp_transp_partial.ico b/tests/Images/Input/Icon/32bpp_transp_partial.ico new file mode 100644 index 0000000000..334a0b75cd --- /dev/null +++ b/tests/Images/Input/Icon/32bpp_transp_partial.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c5bd34021ec302f203c39d038854607d9fe8bcd3133ea57b65ebc6da81aa8a4b +size 4286 diff --git a/tests/Images/Input/Icon/4bpp_size_15x15.ico b/tests/Images/Input/Icon/4bpp_size_15x15.ico new file mode 100644 index 0000000000..ce67e54cc1 --- /dev/null +++ b/tests/Images/Input/Icon/4bpp_size_15x15.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:dd1fd73648c1b7acc4aef4e0c4e6672ab7241e47cb52345c4459aa86185f4dfd +size 306 diff --git a/tests/Images/Input/Icon/4bpp_size_16x16.ico b/tests/Images/Input/Icon/4bpp_size_16x16.ico new file mode 100644 index 0000000000..f26d88b36d --- /dev/null +++ b/tests/Images/Input/Icon/4bpp_size_16x16.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e5f8547e5e6aae3a2f662fa266d0f78731d310fb051f99dce5693d6adcbfbb4f +size 318 diff --git a/tests/Images/Input/Icon/4bpp_size_17x17.ico b/tests/Images/Input/Icon/4bpp_size_17x17.ico new file mode 100644 index 0000000000..aa44dd4f16 --- /dev/null +++ b/tests/Images/Input/Icon/4bpp_size_17x17.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1fd0286a127371d4b40a5c30c6b221753a711231e386b636fcb07d2f1f92967f +size 398 diff --git a/tests/Images/Input/Icon/4bpp_size_1x1.ico b/tests/Images/Input/Icon/4bpp_size_1x1.ico new file mode 100644 index 0000000000..7049b0b367 --- /dev/null +++ b/tests/Images/Input/Icon/4bpp_size_1x1.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:313f969c26d12cae6e778563d1c6c9df248c5d28ff657ad5054a280e06573106 +size 134 diff --git a/tests/Images/Input/Icon/4bpp_size_256x256.ico b/tests/Images/Input/Icon/4bpp_size_256x256.ico new file mode 100644 index 0000000000..fa07400658 --- /dev/null +++ b/tests/Images/Input/Icon/4bpp_size_256x256.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:dcad369c1e56dd01b8644a5903ad25af19cc78047b5e0821546d1171a0ab31ff +size 41086 diff --git a/tests/Images/Input/Icon/4bpp_size_2x2.ico b/tests/Images/Input/Icon/4bpp_size_2x2.ico new file mode 100644 index 0000000000..2b8d74afad --- /dev/null +++ b/tests/Images/Input/Icon/4bpp_size_2x2.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:11b1142401678412ce8718dd6e943fab05ec7974c7ae36286316e7f4d168f0f5 +size 142 diff --git a/tests/Images/Input/Icon/4bpp_size_31x31.ico b/tests/Images/Input/Icon/4bpp_size_31x31.ico new file mode 100644 index 0000000000..86b71f36ca --- /dev/null +++ b/tests/Images/Input/Icon/4bpp_size_31x31.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2b19f60f3441b268a19be0f99078d079c4eb416b882118071ad43ceff41ca40b +size 746 diff --git a/tests/Images/Input/Icon/4bpp_size_32x32.ico b/tests/Images/Input/Icon/4bpp_size_32x32.ico new file mode 100644 index 0000000000..aa8fc09320 --- /dev/null +++ b/tests/Images/Input/Icon/4bpp_size_32x32.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7f0863b486575dca2d5e3ce07da10cb30e039524f17026d9668d75bad780e833 +size 766 diff --git a/tests/Images/Input/Icon/4bpp_size_33x33.ico b/tests/Images/Input/Icon/4bpp_size_33x33.ico new file mode 100644 index 0000000000..ad93685f23 --- /dev/null +++ b/tests/Images/Input/Icon/4bpp_size_33x33.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:64b77f80fb48237a0f9cfbd808289e53ed7a70b107f190c93d76d32342829ccb +size 1050 diff --git a/tests/Images/Input/Icon/4bpp_size_3x3.ico b/tests/Images/Input/Icon/4bpp_size_3x3.ico new file mode 100644 index 0000000000..781266a670 --- /dev/null +++ b/tests/Images/Input/Icon/4bpp_size_3x3.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f8cb358defec66494d3be4eb01fd7e304edfd04435b4552d51769d0858659686 +size 150 diff --git a/tests/Images/Input/Icon/4bpp_size_4x4.ico b/tests/Images/Input/Icon/4bpp_size_4x4.ico new file mode 100644 index 0000000000..ffe599149e --- /dev/null +++ b/tests/Images/Input/Icon/4bpp_size_4x4.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:53083ae340dcc04d88acaf9d75a2dc68b23500c294eb3ed4e15e3fba86c5843f +size 158 diff --git a/tests/Images/Input/Icon/4bpp_size_5x5.ico b/tests/Images/Input/Icon/4bpp_size_5x5.ico new file mode 100644 index 0000000000..70f2db036d --- /dev/null +++ b/tests/Images/Input/Icon/4bpp_size_5x5.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e4f1401d87e285b18e6f818dfb00a3fb275e72e2fd4bce6652bfdd74bf9565f3 +size 166 diff --git a/tests/Images/Input/Icon/4bpp_size_6x6.ico b/tests/Images/Input/Icon/4bpp_size_6x6.ico new file mode 100644 index 0000000000..230d8e85fa --- /dev/null +++ b/tests/Images/Input/Icon/4bpp_size_6x6.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a3fa6bdd6125a9de6d3ddaafd5e62e0435b14c52f82239a6d36d44aaf5a49361 +size 174 diff --git a/tests/Images/Input/Icon/4bpp_size_7x7.ico b/tests/Images/Input/Icon/4bpp_size_7x7.ico new file mode 100644 index 0000000000..7c4b9834bc --- /dev/null +++ b/tests/Images/Input/Icon/4bpp_size_7x7.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c4025a4bd2dde619f950f69d38e042ae38d2a1840d7b00540c372546b5d8ccb0 +size 182 diff --git a/tests/Images/Input/Icon/4bpp_size_8x8.ico b/tests/Images/Input/Icon/4bpp_size_8x8.ico new file mode 100644 index 0000000000..b1f3050bff --- /dev/null +++ b/tests/Images/Input/Icon/4bpp_size_8x8.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:332563676808485aac8e2635baacad3f4d1ce5fc64c6be07daa25962f4fa1687 +size 190 diff --git a/tests/Images/Input/Icon/4bpp_size_9x9.ico b/tests/Images/Input/Icon/4bpp_size_9x9.ico new file mode 100644 index 0000000000..fc7751086c --- /dev/null +++ b/tests/Images/Input/Icon/4bpp_size_9x9.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:da5169395108194503853db2f431e0d02b98a191a1bf597c31fe269e7d84206a +size 234 diff --git a/tests/Images/Input/Icon/4bpp_transp_not_square.ico b/tests/Images/Input/Icon/4bpp_transp_not_square.ico new file mode 100644 index 0000000000..6b2babe8ed --- /dev/null +++ b/tests/Images/Input/Icon/4bpp_transp_not_square.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2dede473b7a427029cdb319ecf04aaf71cf8ce1d806efb65d7e3844ebd1703f9 +size 350 diff --git a/tests/Images/Input/Icon/4bpp_transp_partial.ico b/tests/Images/Input/Icon/4bpp_transp_partial.ico new file mode 100644 index 0000000000..4394b9e432 --- /dev/null +++ b/tests/Images/Input/Icon/4bpp_transp_partial.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7e0617f49eb057ab0346203e0cd04fd4e93de71053bbbfaa3c9655696b10a80d +size 766 diff --git a/tests/Images/Input/Icon/8bpp_size_15x15.ico b/tests/Images/Input/Icon/8bpp_size_15x15.ico new file mode 100644 index 0000000000..086edb7454 --- /dev/null +++ b/tests/Images/Input/Icon/8bpp_size_15x15.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:577c86aa8b78cca86885ed20b702b260150eacf738beb18da28c25bcb01cfdcd +size 1386 diff --git a/tests/Images/Input/Icon/8bpp_size_16x16.ico b/tests/Images/Input/Icon/8bpp_size_16x16.ico new file mode 100644 index 0000000000..e09d744472 --- /dev/null +++ b/tests/Images/Input/Icon/8bpp_size_16x16.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9900b6783aac800836e19890f11fda1bf1d2138dee63403adbc79bf207a71dfd +size 1406 diff --git a/tests/Images/Input/Icon/8bpp_size_17x17.ico b/tests/Images/Input/Icon/8bpp_size_17x17.ico new file mode 100644 index 0000000000..9a5684b4d0 --- /dev/null +++ b/tests/Images/Input/Icon/8bpp_size_17x17.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5b1c214eb0fd9f5b1f1da4ceeb98a3cc0d7b6b02d7ed6aaa5138078e48bf8613 +size 1494 diff --git a/tests/Images/Input/Icon/8bpp_size_1x1.ico b/tests/Images/Input/Icon/8bpp_size_1x1.ico new file mode 100644 index 0000000000..20961847a5 --- /dev/null +++ b/tests/Images/Input/Icon/8bpp_size_1x1.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:032c11a8e5aaa5f9beb997c83504233b5ad278d3a4e129cd384a4ca62950a998 +size 1094 diff --git a/tests/Images/Input/Icon/8bpp_size_256x256.ico b/tests/Images/Input/Icon/8bpp_size_256x256.ico new file mode 100644 index 0000000000..59b0bb63b3 --- /dev/null +++ b/tests/Images/Input/Icon/8bpp_size_256x256.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7aa8f4fc33c541f88318d7c36a5b5e964cb0470c541677790b49b85638c63fd6 +size 74814 diff --git a/tests/Images/Input/Icon/8bpp_size_2x2.ico b/tests/Images/Input/Icon/8bpp_size_2x2.ico new file mode 100644 index 0000000000..bcbdf9c074 --- /dev/null +++ b/tests/Images/Input/Icon/8bpp_size_2x2.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6e1c2b72b6ddf0cfedd9e20e5abf3ae3fd19066be811251bb9db404e6dabe279 +size 1102 diff --git a/tests/Images/Input/Icon/8bpp_size_31x31.ico b/tests/Images/Input/Icon/8bpp_size_31x31.ico new file mode 100644 index 0000000000..7c320d1839 --- /dev/null +++ b/tests/Images/Input/Icon/8bpp_size_31x31.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9a588e6f1031c1c8f0d66b9eef770d01b3f79aaea4203d58ee07255c1c6ee258 +size 2238 diff --git a/tests/Images/Input/Icon/8bpp_size_32x32.ico b/tests/Images/Input/Icon/8bpp_size_32x32.ico new file mode 100644 index 0000000000..af7581f35b --- /dev/null +++ b/tests/Images/Input/Icon/8bpp_size_32x32.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6b00ab33cbb42e9f499844e5add713fcc83854cc2cb104d5c9bd04a456662099 +size 2238 diff --git a/tests/Images/Input/Icon/8bpp_size_33x33.ico b/tests/Images/Input/Icon/8bpp_size_33x33.ico new file mode 100644 index 0000000000..3c8043fe67 --- /dev/null +++ b/tests/Images/Input/Icon/8bpp_size_33x33.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e356bb9200375f8fcbc5a0ed70353194a7b1432133e0c61f0b2f03bca3888080 +size 2538 diff --git a/tests/Images/Input/Icon/8bpp_size_3x3.ico b/tests/Images/Input/Icon/8bpp_size_3x3.ico new file mode 100644 index 0000000000..075791998f --- /dev/null +++ b/tests/Images/Input/Icon/8bpp_size_3x3.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:13cccd62e97bbe6cdd6ca5c4bc765794c7babd3638ff4d09b116a62c3c50be56 +size 1110 diff --git a/tests/Images/Input/Icon/8bpp_size_4x4.ico b/tests/Images/Input/Icon/8bpp_size_4x4.ico new file mode 100644 index 0000000000..af95b287d7 --- /dev/null +++ b/tests/Images/Input/Icon/8bpp_size_4x4.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4343544be11a37083219d99d2dfb4a16b02c309d54223897d6c71503414cc2ef +size 1118 diff --git a/tests/Images/Input/Icon/8bpp_size_5x5.ico b/tests/Images/Input/Icon/8bpp_size_5x5.ico new file mode 100644 index 0000000000..2e4f804951 --- /dev/null +++ b/tests/Images/Input/Icon/8bpp_size_5x5.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b7cfdf4a0d696573a4cb5291e3165c98444692f1d03a3cab1630df33c765ecd9 +size 1146 diff --git a/tests/Images/Input/Icon/8bpp_size_6x6.ico b/tests/Images/Input/Icon/8bpp_size_6x6.ico new file mode 100644 index 0000000000..65ca70be25 --- /dev/null +++ b/tests/Images/Input/Icon/8bpp_size_6x6.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d8d36eb593ee34d22e5ff99a08f2b177dbb92355f85210b2a9e53d7ce9e2cc6b +size 1158 diff --git a/tests/Images/Input/Icon/8bpp_size_7x7.ico b/tests/Images/Input/Icon/8bpp_size_7x7.ico new file mode 100644 index 0000000000..e02e8fb372 --- /dev/null +++ b/tests/Images/Input/Icon/8bpp_size_7x7.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:29050464e324a70bb8a41fb5732b96dbf3bcb36a74ca29775e1f37b07b9ee582 +size 1170 diff --git a/tests/Images/Input/Icon/8bpp_size_8x8.ico b/tests/Images/Input/Icon/8bpp_size_8x8.ico new file mode 100644 index 0000000000..39be58ce45 --- /dev/null +++ b/tests/Images/Input/Icon/8bpp_size_8x8.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b46ca32ddb84074d9140224738480eaa0a6c0dce2dbf2074625add1901c27117 +size 286 diff --git a/tests/Images/Input/Icon/8bpp_size_9x9.ico b/tests/Images/Input/Icon/8bpp_size_9x9.ico new file mode 100644 index 0000000000..8819490aec --- /dev/null +++ b/tests/Images/Input/Icon/8bpp_size_9x9.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4ddeaa63b1ec9d389c140499e2b5d2e911a57d8f37467696bb9e9ec3e60ec77b +size 1230 diff --git a/tests/Images/Input/Icon/8bpp_transp_not_square.ico b/tests/Images/Input/Icon/8bpp_transp_not_square.ico new file mode 100644 index 0000000000..6b6bbdc9fd --- /dev/null +++ b/tests/Images/Input/Icon/8bpp_transp_not_square.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:04a255b4cd43ec7005a9a946c2b3dba57eba709b16be85ef77e553943d35f745 +size 1478 diff --git a/tests/Images/Input/Icon/8bpp_transp_partial.ico b/tests/Images/Input/Icon/8bpp_transp_partial.ico new file mode 100644 index 0000000000..73cd34c733 --- /dev/null +++ b/tests/Images/Input/Icon/8bpp_transp_partial.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:20abca3096b955bc91ed95d194ff3f856473d6d372b5bea0d8c75fd20a231a26 +size 2238 diff --git a/tests/Images/Input/Icon/aero_arrow.cur b/tests/Images/Input/Icon/aero_arrow.cur new file mode 100644 index 0000000000..82cbbd33e6 --- /dev/null +++ b/tests/Images/Input/Icon/aero_arrow.cur @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:06678bbf954f0bece61062633dc63a52a34a6f3c27ac7108f28c0f0d26bb22a7 +size 136606 diff --git a/tests/Images/Input/Icon/cur_fake.ico b/tests/Images/Input/Icon/cur_fake.ico new file mode 100644 index 0000000000..cad7542c85 --- /dev/null +++ b/tests/Images/Input/Icon/cur_fake.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6679016e7954e335cef537630d122cc3a7a05cb2f3ef32f72811d724b83d4c28 +size 4286 diff --git a/tests/Images/Input/Icon/cur_real.cur b/tests/Images/Input/Icon/cur_real.cur new file mode 100644 index 0000000000..cad7542c85 --- /dev/null +++ b/tests/Images/Input/Icon/cur_real.cur @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6679016e7954e335cef537630d122cc3a7a05cb2f3ef32f72811d724b83d4c28 +size 4286 diff --git a/tests/Images/Input/Icon/flutter.ico b/tests/Images/Input/Icon/flutter.ico new file mode 100644 index 0000000000..4001f14268 --- /dev/null +++ b/tests/Images/Input/Icon/flutter.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c098d3fc85cacff98b8e69811b48e9f0d852fcee278132d794411d978869cbf8 +size 33772 diff --git a/tests/Images/Input/Icon/ico_fake.cur b/tests/Images/Input/Icon/ico_fake.cur new file mode 100644 index 0000000000..5ab0405380 --- /dev/null +++ b/tests/Images/Input/Icon/ico_fake.cur @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2d3a3185dcf0a2c3f5d3fe821474f6787c4de7cffe08db6bd730073ad94e7538 +size 4286 diff --git a/tests/Images/Input/Icon/invalid_RLE4.ico b/tests/Images/Input/Icon/invalid_RLE4.ico new file mode 100644 index 0000000000..5d2e25fd3b --- /dev/null +++ b/tests/Images/Input/Icon/invalid_RLE4.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:43c543a1c66608a89f0b187afa1526af4be4f7c94265897002b3a150328b964e +size 86 diff --git a/tests/Images/Input/Icon/invalid_RLE8.ico b/tests/Images/Input/Icon/invalid_RLE8.ico new file mode 100644 index 0000000000..2ebefbf330 --- /dev/null +++ b/tests/Images/Input/Icon/invalid_RLE8.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b55b3f3f87d9d5801150ffd999c62623528a33d031ca8d6fe665be3328d8c94d +size 86 diff --git a/tests/Images/Input/Icon/invalid_all.ico b/tests/Images/Input/Icon/invalid_all.ico new file mode 100644 index 0000000000..ca34a25788 --- /dev/null +++ b/tests/Images/Input/Icon/invalid_all.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:93c4f059ced481667315dd7b90e9c1beed0a42a08f3ff8e51e2388919fafa79a +size 283 diff --git a/tests/Images/Input/Icon/invalid_bpp.ico b/tests/Images/Input/Icon/invalid_bpp.ico new file mode 100644 index 0000000000..913f780ed3 --- /dev/null +++ b/tests/Images/Input/Icon/invalid_bpp.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:396bfd08531fc0eae8b5e364ef4c62035e8493a3f59286dedbca6f441d8e9690 +size 86 diff --git a/tests/Images/Input/Icon/invalid_compression.ico b/tests/Images/Input/Icon/invalid_compression.ico new file mode 100644 index 0000000000..7e697d3d28 --- /dev/null +++ b/tests/Images/Input/Icon/invalid_compression.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f051ed80db684748d2b2669c77b95068e209b2fe2917fa65f6218beef4dcead5 +size 830 diff --git a/tests/Images/Input/Icon/invalid_png.ico b/tests/Images/Input/Icon/invalid_png.ico new file mode 100644 index 0000000000..cbd394fc6a --- /dev/null +++ b/tests/Images/Input/Icon/invalid_png.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:61bc9e74d8fd9f72c8ccaf9a3887c517e17c0a39d9d41acabc3699be545b9703 +size 901 diff --git a/tests/Images/Input/Icon/mixed_bmp_png_a.ico b/tests/Images/Input/Icon/mixed_bmp_png_a.ico new file mode 100644 index 0000000000..f35027255c --- /dev/null +++ b/tests/Images/Input/Icon/mixed_bmp_png_a.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:47adfa4e36adf74ae49cfa481cb54cffe659c09d4b52765e973b6adc8cc31e97 +size 3653 diff --git a/tests/Images/Input/Icon/mixed_bmp_png_b.ico b/tests/Images/Input/Icon/mixed_bmp_png_b.ico new file mode 100644 index 0000000000..3efdcab740 --- /dev/null +++ b/tests/Images/Input/Icon/mixed_bmp_png_b.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:96338768d8f9c90a6af94268dc55d94809a412c3164c381926b3759ffbf2df79 +size 45693 diff --git a/tests/Images/Input/Icon/mixed_bmp_png_c.ico b/tests/Images/Input/Icon/mixed_bmp_png_c.ico new file mode 100644 index 0000000000..65b504eef2 --- /dev/null +++ b/tests/Images/Input/Icon/mixed_bmp_png_c.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e9be0358616581f45eddeaee474c0ce0be8a82279428f5ef1890b2fb6f0c0d27 +size 164189 diff --git a/tests/Images/Input/Icon/multi_size_a.ico b/tests/Images/Input/Icon/multi_size_a.ico new file mode 100644 index 0000000000..c34fdc638c --- /dev/null +++ b/tests/Images/Input/Icon/multi_size_a.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:dba75ec62f5785ce5d16c2c5c04637b18ccb164917092373b3d470326e7bc0c4 +size 17542 diff --git a/tests/Images/Input/Icon/multi_size_b.ico b/tests/Images/Input/Icon/multi_size_b.ico new file mode 100644 index 0000000000..2065bd638e --- /dev/null +++ b/tests/Images/Input/Icon/multi_size_b.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1d7ac6313ee263103f4ab6aa5147b1d85bf5ff792c0980189aac9bfab1288011 +size 99678 diff --git a/tests/Images/Input/Icon/multi_size_c.ico b/tests/Images/Input/Icon/multi_size_c.ico new file mode 100644 index 0000000000..c6ee58297b --- /dev/null +++ b/tests/Images/Input/Icon/multi_size_c.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:85e04b807e084bc9a0e1a65289e21ca1baac1e70c3a37fabbea7d69995945f08 +size 202850 diff --git a/tests/Images/Input/Icon/multi_size_d.ico b/tests/Images/Input/Icon/multi_size_d.ico new file mode 100644 index 0000000000..3d9fc96fbc --- /dev/null +++ b/tests/Images/Input/Icon/multi_size_d.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4a0ce27b63b386c4fdbf7835db738f0e98f274f5a112b7bd45c32dfab93952a0 +size 216804 diff --git a/tests/Images/Input/Icon/multi_size_e.ico b/tests/Images/Input/Icon/multi_size_e.ico new file mode 100644 index 0000000000..8f2991acbe --- /dev/null +++ b/tests/Images/Input/Icon/multi_size_e.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:363ff3655e978ffe30a8cefec3bd4202a1ae0a22f3ab48e56362f56a31fb349f +size 372526 diff --git a/tests/Images/Input/Icon/multi_size_f.ico b/tests/Images/Input/Icon/multi_size_f.ico new file mode 100644 index 0000000000..99948cf1e1 --- /dev/null +++ b/tests/Images/Input/Icon/multi_size_f.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:04701ce87eb82280a4e53d816a0ac3ee91ebc28b1959641bddb90787015ff4a8 +size 3084 diff --git a/tests/Images/Input/Icon/multi_size_multi_bits_a.ico b/tests/Images/Input/Icon/multi_size_multi_bits_a.ico new file mode 100644 index 0000000000..12b2bf66cf --- /dev/null +++ b/tests/Images/Input/Icon/multi_size_multi_bits_a.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a1561795509c9e8dbf0633db9b4c242e72e0ebe4ae9a7718328e96b6b273c3ca +size 4710 diff --git a/tests/Images/Input/Icon/multi_size_multi_bits_b.ico b/tests/Images/Input/Icon/multi_size_multi_bits_b.ico new file mode 100644 index 0000000000..599168aea2 --- /dev/null +++ b/tests/Images/Input/Icon/multi_size_multi_bits_b.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8fe15c1a8ca4bae0ad588863418af960fb62def2db4abfcae594de4fc1b2304a +size 31134 diff --git a/tests/Images/Input/Icon/multi_size_multi_bits_c.ico b/tests/Images/Input/Icon/multi_size_multi_bits_c.ico new file mode 100644 index 0000000000..701b574dcc --- /dev/null +++ b/tests/Images/Input/Icon/multi_size_multi_bits_c.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c5afa3da7d278c1d2272581971117408c38ec5fe3aaac17e5234f7a8012fd9e2 +size 72513 diff --git a/tests/Images/Input/Icon/multi_size_multi_bits_d.ico b/tests/Images/Input/Icon/multi_size_multi_bits_d.ico new file mode 100644 index 0000000000..271ec92a5d --- /dev/null +++ b/tests/Images/Input/Icon/multi_size_multi_bits_d.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e0754e570ab3a2ce81759aa206fc6e8780fb1024fb20e60dbdb329ee4c0c1831 +size 293950 diff --git a/tests/Images/Input/Jpg/issues/issue-2067-comment.jpg b/tests/Images/Input/Jpg/issues/issue-2067-comment.jpg new file mode 100644 index 0000000000..18dc6f2e32 --- /dev/null +++ b/tests/Images/Input/Jpg/issues/issue-2067-comment.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d87b5429adeffcfac535aa8af2ec9801bf6c965a2e6751cfec4f8534195ba8f4 +size 21082 diff --git a/tests/Images/Input/Tga/32bit_no_alphabits.tga b/tests/Images/Input/Tga/32bit_no_alphabits.tga index 903eca4594..206e8d7c5e 100644 --- a/tests/Images/Input/Tga/32bit_no_alphabits.tga +++ b/tests/Images/Input/Tga/32bit_no_alphabits.tga @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0aea1128a1bd7477dfa0d007a1eba25907be24847284c48a5f9fbd61bcea3cf0 -size 61522 +oid sha256:019315f9dcbe4516ecb15426a45c210d437e9ad152c8e1a0e80abe9449177e12 +size 235218 diff --git a/tests/Images/Input/Tga/32bit_rle_no_alphabits.tga b/tests/Images/Input/Tga/32bit_rle_no_alphabits.tga index b21dad5e0d..153b0a055b 100644 --- a/tests/Images/Input/Tga/32bit_rle_no_alphabits.tga +++ b/tests/Images/Input/Tga/32bit_rle_no_alphabits.tga @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:98a198392bd527523f8649d6126af81e5a588ad7265dc3d48a1da7b5a6cb6ff7 -size 230578 +oid sha256:33954ae93b4c7d57f52965a9028e97119c546db1da255100c2903a2760c7479e +size 76870 diff --git a/tests/Images/Input/Tga/issues/Issue2629.tga b/tests/Images/Input/Tga/issues/Issue2629.tga new file mode 100644 index 0000000000..4c87196ad5 --- /dev/null +++ b/tests/Images/Input/Tga/issues/Issue2629.tga @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:defc1396481f426a74e8af51ed57f65cbed932f932673ce5a87fa12ea9b460f8 +size 32786 diff --git a/tests/Images/Input/Tiff/Issues/Issue2679.tiff b/tests/Images/Input/Tiff/Issues/Issue2679.tiff new file mode 100644 index 0000000000..1bc49f079c --- /dev/null +++ b/tests/Images/Input/Tiff/Issues/Issue2679.tiff @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:feb938396b9d5b4c258244197ba382937a52c93f72cc91081c7e6810e4a3b94c +size 6136