From 065cb1ca459362fe1aaa6bb8e1afad4491c8515f Mon Sep 17 00:00:00 2001 From: Ynse Hoornenborg Date: Wed, 17 Nov 2021 20:34:26 +0100 Subject: [PATCH 01/65] Fix vanilla build on VS2019 --- src/ImageSharp/ImageSharp.csproj | 1 + tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj | 1 + .../ImageSharp.Tests.ProfilingSandbox.csproj | 1 + tests/ImageSharp.Tests/ImageSharp.Tests.csproj | 1 + 4 files changed, 4 insertions(+) diff --git a/src/ImageSharp/ImageSharp.csproj b/src/ImageSharp/ImageSharp.csproj index 6ad20713d..800b69326 100644 --- a/src/ImageSharp/ImageSharp.csproj +++ b/src/ImageSharp/ImageSharp.csproj @@ -39,6 +39,7 @@ netcoreapp3.1;netcoreapp2.1;netstandard2.1;netstandard2.0;netstandard1.3;net472 + 9.0 diff --git a/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj b/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj index 8f0b4a86f..4d7af89a5 100644 --- a/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj +++ b/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj @@ -28,6 +28,7 @@ net5.0;netcoreapp3.1;netcoreapp2.1;net472 + 9.0 diff --git a/tests/ImageSharp.Tests.ProfilingSandbox/ImageSharp.Tests.ProfilingSandbox.csproj b/tests/ImageSharp.Tests.ProfilingSandbox/ImageSharp.Tests.ProfilingSandbox.csproj index 1a470fa31..a141a58b0 100644 --- a/tests/ImageSharp.Tests.ProfilingSandbox/ImageSharp.Tests.ProfilingSandbox.csproj +++ b/tests/ImageSharp.Tests.ProfilingSandbox/ImageSharp.Tests.ProfilingSandbox.csproj @@ -30,6 +30,7 @@ net5.0;netcoreapp3.1;netcoreapp2.1;net472 + 9.0 diff --git a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj index 471287006..c560b1b78 100644 --- a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj +++ b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj @@ -23,6 +23,7 @@ net5.0;netcoreapp3.1;netcoreapp2.1;net472 + 9.0 From 251e802b7e36d4723f78c4820e945ab0f3c381e2 Mon Sep 17 00:00:00 2001 From: Ynse Hoornenborg Date: Thu, 18 Nov 2021 21:13:59 +0100 Subject: [PATCH 02/65] Revert of: Fix vanilla build on VS2019 --- src/ImageSharp/ImageSharp.csproj | 1 + tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj | 1 + .../ImageSharp.Tests.ProfilingSandbox.csproj | 1 + tests/ImageSharp.Tests/ImageSharp.Tests.csproj | 1 + 4 files changed, 4 insertions(+) diff --git a/src/ImageSharp/ImageSharp.csproj b/src/ImageSharp/ImageSharp.csproj index 6ad20713d..800b69326 100644 --- a/src/ImageSharp/ImageSharp.csproj +++ b/src/ImageSharp/ImageSharp.csproj @@ -39,6 +39,7 @@ netcoreapp3.1;netcoreapp2.1;netstandard2.1;netstandard2.0;netstandard1.3;net472 + 9.0 diff --git a/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj b/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj index 8f0b4a86f..4d7af89a5 100644 --- a/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj +++ b/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj @@ -28,6 +28,7 @@ net5.0;netcoreapp3.1;netcoreapp2.1;net472 + 9.0 diff --git a/tests/ImageSharp.Tests.ProfilingSandbox/ImageSharp.Tests.ProfilingSandbox.csproj b/tests/ImageSharp.Tests.ProfilingSandbox/ImageSharp.Tests.ProfilingSandbox.csproj index 1a470fa31..a141a58b0 100644 --- a/tests/ImageSharp.Tests.ProfilingSandbox/ImageSharp.Tests.ProfilingSandbox.csproj +++ b/tests/ImageSharp.Tests.ProfilingSandbox/ImageSharp.Tests.ProfilingSandbox.csproj @@ -30,6 +30,7 @@ net5.0;netcoreapp3.1;netcoreapp2.1;net472 + 9.0 diff --git a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj index 471287006..c560b1b78 100644 --- a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj +++ b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj @@ -23,6 +23,7 @@ net5.0;netcoreapp3.1;netcoreapp2.1;net472 + 9.0 From 75102503bfd242d56a6a9e49d267a99ff5301002 Mon Sep 17 00:00:00 2001 From: Ynse Hoornenborg Date: Wed, 24 Nov 2021 22:17:46 +0100 Subject: [PATCH 03/65] Support Pbm, Pgm and Ppm images --- src/ImageSharp/Advanced/AotCompilerTools.cs | 5 + src/ImageSharp/Configuration.cs | 3 + .../Formats/ImageExtensions.Save.cs | 104 ++++++++ .../Formats/ImageExtensions.Save.tt | 1 + src/ImageSharp/Formats/Pbm/BinaryDecoder.cs | 192 +++++++++++++++ src/ImageSharp/Formats/Pbm/BinaryEncoder.cs | 203 ++++++++++++++++ .../Pbm/BufferedReadStreamExtensions.cs | 65 +++++ .../Formats/Pbm/IPbmEncoderOptions.cs | 26 ++ .../Formats/Pbm/MetadataExtensions.cs | 21 ++ src/ImageSharp/Formats/Pbm/PbmColorType.cs | 26 ++ .../Formats/Pbm/PbmConfigurationModule.cs | 19 ++ src/ImageSharp/Formats/Pbm/PbmConstants.cs | 28 +++ src/ImageSharp/Formats/Pbm/PbmDecoder.cs | 67 +++++ src/ImageSharp/Formats/Pbm/PbmDecoderCore.cs | 169 +++++++++++++ src/ImageSharp/Formats/Pbm/PbmEncoder.cs | 48 ++++ src/ImageSharp/Formats/Pbm/PbmEncoderCore.cs | 176 ++++++++++++++ src/ImageSharp/Formats/Pbm/PbmEncoding.cs | 21 ++ src/ImageSharp/Formats/Pbm/PbmFormat.cs | 37 +++ .../Formats/Pbm/PbmImageFormatDetector.cs | 33 +++ src/ImageSharp/Formats/Pbm/PbmMetadata.cs | 48 ++++ src/ImageSharp/Formats/Pbm/PlainDecoder.cs | 197 +++++++++++++++ src/ImageSharp/Formats/Pbm/PlainEncoder.cs | 228 ++++++++++++++++++ .../Formats/Pbm/StreamExtensions.cs | 19 ++ src/ImageSharp/ImageSharp.csproj | 2 +- tests/ImageSharp.Tests/ConfigurationTests.cs | 2 +- .../Formats/GeneralFormatTests.cs | 9 + .../Formats/ImageFormatManagerTests.cs | 3 + .../Formats/Pbm/ImageExtensionsTest.cs | 155 ++++++++++++ .../Formats/Pbm/PbmDecoderTests.cs | 40 +++ .../Formats/Pbm/PbmEncoderTests.cs | 144 +++++++++++ .../Formats/Pbm/PbmMetadataTests.cs | 84 +++++++ .../Formats/Pbm/PbmTestUtils.cs | 65 +++++ .../Formats/Pbm/RoundTripTests.cs | 44 ++++ .../Image/ImageTests.SaveAsync.cs | 2 + tests/ImageSharp.Tests/TestImages.cs | 11 + .../TestUtilities/TestEnvironment.Formats.cs | 2 + tests/Images/Input/Pbm/00000_00000.ppm | 4 + .../Pbm/Gene-UP WebSocket RunImageMask.pgm | Bin 0 -> 614417 bytes .../Images/Input/Pbm/blackandwhite_binary.pbm | 3 + .../Images/Input/Pbm/blackandwhite_plain.pbm | 10 + tests/Images/Input/Pbm/grayscale_plain.pgm | 10 + tests/Images/Input/Pbm/rgb_plain.ppm | 8 + tests/Images/Input/Pbm/rings.pgm | Bin 0 -> 40038 bytes 43 files changed, 2332 insertions(+), 2 deletions(-) create mode 100644 src/ImageSharp/Formats/Pbm/BinaryDecoder.cs create mode 100644 src/ImageSharp/Formats/Pbm/BinaryEncoder.cs create mode 100644 src/ImageSharp/Formats/Pbm/BufferedReadStreamExtensions.cs create mode 100644 src/ImageSharp/Formats/Pbm/IPbmEncoderOptions.cs create mode 100644 src/ImageSharp/Formats/Pbm/MetadataExtensions.cs create mode 100644 src/ImageSharp/Formats/Pbm/PbmColorType.cs create mode 100644 src/ImageSharp/Formats/Pbm/PbmConfigurationModule.cs create mode 100644 src/ImageSharp/Formats/Pbm/PbmConstants.cs create mode 100644 src/ImageSharp/Formats/Pbm/PbmDecoder.cs create mode 100644 src/ImageSharp/Formats/Pbm/PbmDecoderCore.cs create mode 100644 src/ImageSharp/Formats/Pbm/PbmEncoder.cs create mode 100644 src/ImageSharp/Formats/Pbm/PbmEncoderCore.cs create mode 100644 src/ImageSharp/Formats/Pbm/PbmEncoding.cs create mode 100644 src/ImageSharp/Formats/Pbm/PbmFormat.cs create mode 100644 src/ImageSharp/Formats/Pbm/PbmImageFormatDetector.cs create mode 100644 src/ImageSharp/Formats/Pbm/PbmMetadata.cs create mode 100644 src/ImageSharp/Formats/Pbm/PlainDecoder.cs create mode 100644 src/ImageSharp/Formats/Pbm/PlainEncoder.cs create mode 100644 src/ImageSharp/Formats/Pbm/StreamExtensions.cs create mode 100644 tests/ImageSharp.Tests/Formats/Pbm/ImageExtensionsTest.cs create mode 100644 tests/ImageSharp.Tests/Formats/Pbm/PbmDecoderTests.cs create mode 100644 tests/ImageSharp.Tests/Formats/Pbm/PbmEncoderTests.cs create mode 100644 tests/ImageSharp.Tests/Formats/Pbm/PbmMetadataTests.cs create mode 100644 tests/ImageSharp.Tests/Formats/Pbm/PbmTestUtils.cs create mode 100644 tests/ImageSharp.Tests/Formats/Pbm/RoundTripTests.cs create mode 100644 tests/Images/Input/Pbm/00000_00000.ppm create mode 100644 tests/Images/Input/Pbm/Gene-UP WebSocket RunImageMask.pgm create mode 100644 tests/Images/Input/Pbm/blackandwhite_binary.pbm create mode 100644 tests/Images/Input/Pbm/blackandwhite_plain.pbm create mode 100644 tests/Images/Input/Pbm/grayscale_plain.pgm create mode 100644 tests/Images/Input/Pbm/rgb_plain.ppm create mode 100644 tests/Images/Input/Pbm/rings.pgm diff --git a/src/ImageSharp/Advanced/AotCompilerTools.cs b/src/ImageSharp/Advanced/AotCompilerTools.cs index 3961cc6c5..e41e38f7f 100644 --- a/src/ImageSharp/Advanced/AotCompilerTools.cs +++ b/src/ImageSharp/Advanced/AotCompilerTools.cs @@ -10,6 +10,7 @@ using SixLabors.ImageSharp.Formats.Bmp; using SixLabors.ImageSharp.Formats.Gif; using SixLabors.ImageSharp.Formats.Jpeg; using SixLabors.ImageSharp.Formats.Jpeg.Components; +using SixLabors.ImageSharp.Formats.Pbm; using SixLabors.ImageSharp.Formats.Png; using SixLabors.ImageSharp.Formats.Tga; using SixLabors.ImageSharp.Formats.Tiff; @@ -200,6 +201,7 @@ namespace SixLabors.ImageSharp.Advanced default(BmpEncoderCore).Encode(default, default, default); default(GifEncoderCore).Encode(default, default, default); default(JpegEncoderCore).Encode(default, default, default); + default(PbmEncoderCore).Encode(default, default, default); default(PngEncoderCore).Encode(default, default, default); default(TgaEncoderCore).Encode(default, default, default); default(TiffEncoderCore).Encode(default, default, default); @@ -217,6 +219,7 @@ namespace SixLabors.ImageSharp.Advanced default(BmpDecoderCore).Decode(default, default, default); default(GifDecoderCore).Decode(default, default, default); default(JpegDecoderCore).Decode(default, default, default); + default(PbmDecoderCore).Decode(default, default, default); default(PngDecoderCore).Decode(default, default, default); default(TgaDecoderCore).Decode(default, default, default); default(TiffDecoderCore).Decode(default, default, default); @@ -234,6 +237,7 @@ namespace SixLabors.ImageSharp.Advanced AotCompileImageEncoder(); AotCompileImageEncoder(); AotCompileImageEncoder(); + AotCompileImageEncoder(); AotCompileImageEncoder(); AotCompileImageEncoder(); AotCompileImageEncoder(); @@ -251,6 +255,7 @@ namespace SixLabors.ImageSharp.Advanced AotCompileImageDecoder(); AotCompileImageDecoder(); AotCompileImageDecoder(); + AotCompileImageDecoder(); AotCompileImageDecoder(); AotCompileImageDecoder(); AotCompileImageDecoder(); diff --git a/src/ImageSharp/Configuration.cs b/src/ImageSharp/Configuration.cs index ea9524827..4b7333de0 100644 --- a/src/ImageSharp/Configuration.cs +++ b/src/ImageSharp/Configuration.cs @@ -8,6 +8,7 @@ using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.Formats.Bmp; using SixLabors.ImageSharp.Formats.Gif; using SixLabors.ImageSharp.Formats.Jpeg; +using SixLabors.ImageSharp.Formats.Pbm; using SixLabors.ImageSharp.Formats.Png; using SixLabors.ImageSharp.Formats.Tga; using SixLabors.ImageSharp.Formats.Tiff; @@ -178,6 +179,7 @@ namespace SixLabors.ImageSharp /// /// /// . + /// . /// . /// . /// . @@ -188,6 +190,7 @@ namespace SixLabors.ImageSharp new JpegConfigurationModule(), new GifConfigurationModule(), new BmpConfigurationModule(), + new PbmConfigurationModule(), new TgaConfigurationModule(), new TiffConfigurationModule(), new WebpConfigurationModule()); diff --git a/src/ImageSharp/Formats/ImageExtensions.Save.cs b/src/ImageSharp/Formats/ImageExtensions.Save.cs index c5237f2bc..a6a65aef6 100644 --- a/src/ImageSharp/Formats/ImageExtensions.Save.cs +++ b/src/ImageSharp/Formats/ImageExtensions.Save.cs @@ -10,6 +10,7 @@ using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Formats.Bmp; using SixLabors.ImageSharp.Formats.Gif; using SixLabors.ImageSharp.Formats.Jpeg; +using SixLabors.ImageSharp.Formats.Pbm; using SixLabors.ImageSharp.Formats.Png; using SixLabors.ImageSharp.Formats.Tga; using SixLabors.ImageSharp.Formats.Webp; @@ -331,6 +332,109 @@ namespace SixLabors.ImageSharp encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(JpegFormat.Instance), cancellationToken); + /// + /// Saves the image to the given stream with the Pbm format. + /// + /// The image this method extends. + /// The file path to save the image to. + /// Thrown if the path is null. + public static void SaveAsPbm(this Image source, string path) => SaveAsPbm(source, path, null); + + /// + /// Saves the image to the given stream with the Pbm format. + /// + /// The image this method extends. + /// The file path to save the image to. + /// Thrown if the path is null. + /// A representing the asynchronous operation. + public static Task SaveAsPbmAsync(this Image source, string path) => SaveAsPbmAsync(source, path, null); + + /// + /// Saves the image to the given stream with the Pbm format. + /// + /// The image this method extends. + /// The file path to save the image to. + /// The token to monitor for cancellation requests. + /// Thrown if the path is null. + /// A representing the asynchronous operation. + public static Task SaveAsPbmAsync(this Image source, string path, CancellationToken cancellationToken) + => SaveAsPbmAsync(source, path, null, cancellationToken); + + /// + /// Saves the image to the given stream with the Pbm format. + /// + /// The image this method extends. + /// The file path to save the image to. + /// The encoder to save the image with. + /// Thrown if the path is null. + public static void SaveAsPbm(this Image source, string path, PbmEncoder encoder) => + source.Save( + path, + encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(PbmFormat.Instance)); + + /// + /// Saves the image to the given stream with the Pbm format. + /// + /// The image this method extends. + /// The file path to save the image to. + /// The encoder to save the image with. + /// The token to monitor for cancellation requests. + /// Thrown if the path is null. + /// A representing the asynchronous operation. + public static Task SaveAsPbmAsync(this Image source, string path, PbmEncoder encoder, CancellationToken cancellationToken = default) => + source.SaveAsync( + path, + encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(PbmFormat.Instance), + cancellationToken); + + /// + /// Saves the image to the given stream with the Pbm format. + /// + /// The image this method extends. + /// The stream to save the image to. + /// Thrown if the stream is null. + public static void SaveAsPbm(this Image source, Stream stream) + => SaveAsPbm(source, stream, null); + + /// + /// Saves the image to the given stream with the Pbm format. + /// + /// The image this method extends. + /// The stream to save the image to. + /// The token to monitor for cancellation requests. + /// Thrown if the stream is null. + /// A representing the asynchronous operation. + public static Task SaveAsPbmAsync(this Image source, Stream stream, CancellationToken cancellationToken = default) + => SaveAsPbmAsync(source, stream, null, cancellationToken); + + /// + /// Saves the image to the given stream with the Pbm format. + /// + /// The image this method extends. + /// The stream to save the image to. + /// The encoder to save the image with. + /// Thrown if the stream is null. + /// A representing the asynchronous operation. + public static void SaveAsPbm(this Image source, Stream stream, PbmEncoder encoder) + => source.Save( + stream, + encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(PbmFormat.Instance)); + + /// + /// Saves the image to the given stream with the Pbm format. + /// + /// The image this method extends. + /// The stream to save the image to. + /// The encoder to save the image with. + /// The token to monitor for cancellation requests. + /// Thrown if the stream is null. + /// A representing the asynchronous operation. + public static Task SaveAsPbmAsync(this Image source, Stream stream, PbmEncoder encoder, CancellationToken cancellationToken = default) => + source.SaveAsync( + stream, + encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(PbmFormat.Instance), + cancellationToken); + /// /// Saves the image to the given stream with the Png format. /// diff --git a/src/ImageSharp/Formats/ImageExtensions.Save.tt b/src/ImageSharp/Formats/ImageExtensions.Save.tt index 874f3ab0d..c4a00b37c 100644 --- a/src/ImageSharp/Formats/ImageExtensions.Save.tt +++ b/src/ImageSharp/Formats/ImageExtensions.Save.tt @@ -15,6 +15,7 @@ using SixLabors.ImageSharp.Advanced; "Bmp", "Gif", "Jpeg", + "Pbm", "Png", "Tga", "Webp", diff --git a/src/ImageSharp/Formats/Pbm/BinaryDecoder.cs b/src/ImageSharp/Formats/Pbm/BinaryDecoder.cs new file mode 100644 index 000000000..1c86b2bd8 --- /dev/null +++ b/src/ImageSharp/Formats/Pbm/BinaryDecoder.cs @@ -0,0 +1,192 @@ +// Copyright (c) Six Labors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Buffers; +using SixLabors.ImageSharp.IO; +using SixLabors.ImageSharp.Memory; +using SixLabors.ImageSharp.PixelFormats; + +namespace SixLabors.ImageSharp.Formats.Pbm +{ + /// + /// Pixel decoding methods for the PBM binary encoding. + /// + internal class BinaryDecoder + { + /// + /// Decode the specified pixels. + /// + /// The type of pixel to encode to. + /// The configuration. + /// The pixel array to encode into. + /// The stream to read the data from. + /// The ColorType to decode. + /// The maximum expected pixel value + /// + /// Thrown if an invalid combination of setting is requested. + /// + public static void Process(Configuration configuration, Buffer2D pixels, BufferedReadStream stream, PbmColorType colorType, int maxPixelValue) + where TPixel : unmanaged, IPixel + { + if (colorType == PbmColorType.Grayscale) + { + if (maxPixelValue < 256) + { + ProcessGrayscale(configuration, pixels, stream); + } + else + { + ProcessWideGrayscale(configuration, pixels, stream); + } + } + else if (colorType == PbmColorType.Rgb) + { + if (maxPixelValue < 256) + { + ProcessRgb(configuration, pixels, stream); + } + else + { + ProcessWideRgb(configuration, pixels, stream); + } + } + else + { + ProcessBlackAndWhite(configuration, pixels, stream); + } + } + + private static void ProcessGrayscale(Configuration configuration, Buffer2D pixels, BufferedReadStream stream) + where TPixel : unmanaged, IPixel + { + int width = pixels.Width; + int height = pixels.Height; + int bytesPerPixel = 1; + MemoryAllocator allocator = configuration.MemoryAllocator; + using IMemoryOwner row = allocator.Allocate(width * bytesPerPixel); + Span rowSpan = row.GetSpan(); + + for (int y = 0; y < height; y++) + { + stream.Read(rowSpan); + Span pixelSpan = pixels.GetRowSpan(y); + PixelOperations.Instance.FromL8Bytes( + configuration, + rowSpan, + pixelSpan, + width); + } + } + + private static void ProcessWideGrayscale(Configuration configuration, Buffer2D pixels, BufferedReadStream stream) + where TPixel : unmanaged, IPixel + { + int width = pixels.Width; + int height = pixels.Height; + int bytesPerPixel = 2; + MemoryAllocator allocator = configuration.MemoryAllocator; + using IMemoryOwner row = allocator.Allocate(width * bytesPerPixel); + Span rowSpan = row.GetSpan(); + + for (int y = 0; y < height; y++) + { + stream.Read(rowSpan); + Span pixelSpan = pixels.GetRowSpan(y); + PixelOperations.Instance.FromL16Bytes( + configuration, + rowSpan, + pixelSpan, + width); + } + } + + private static void ProcessRgb(Configuration configuration, Buffer2D pixels, BufferedReadStream stream) + where TPixel : unmanaged, IPixel + { + int width = pixels.Width; + int height = pixels.Height; + int bytesPerPixel = 3; + MemoryAllocator allocator = configuration.MemoryAllocator; + using IMemoryOwner row = allocator.Allocate(width * bytesPerPixel); + Span rowSpan = row.GetSpan(); + + for (int y = 0; y < height; y++) + { + stream.Read(rowSpan); + Span pixelSpan = pixels.GetRowSpan(y); + PixelOperations.Instance.FromRgb24Bytes( + configuration, + rowSpan, + pixelSpan, + width); + } + } + + private static void ProcessWideRgb(Configuration configuration, Buffer2D pixels, BufferedReadStream stream) + where TPixel : unmanaged, IPixel + { + int width = pixels.Width; + int height = pixels.Height; + int bytesPerPixel = 6; + MemoryAllocator allocator = configuration.MemoryAllocator; + using IMemoryOwner row = allocator.Allocate(width * bytesPerPixel); + Span rowSpan = row.GetSpan(); + + for (int y = 0; y < height; y++) + { + stream.Read(rowSpan); + Span pixelSpan = pixels.GetRowSpan(y); + PixelOperations.Instance.FromRgb48Bytes( + configuration, + rowSpan, + pixelSpan, + width); + } + } + + private static void ProcessBlackAndWhite(Configuration configuration, Buffer2D pixels, BufferedReadStream stream) + where TPixel : unmanaged, IPixel + { + int width = pixels.Width; + int height = pixels.Height; + int startBit = 0; + MemoryAllocator allocator = configuration.MemoryAllocator; + using IMemoryOwner row = allocator.Allocate(width); + Span rowSpan = row.GetSpan(); + var white = new L8(255); + var black = new L8(0); + + for (int y = 0; y < height; y++) + { + for (int x = 0; x < width;) + { + int raw = stream.ReadByte(); + int bit = startBit; + startBit = 0; + for (; bit < 8; bit++) + { + bool bitValue = (raw & (0x80 >> bit)) != 0; + rowSpan[x] = bitValue ? black : white; + x++; + if (x == width) + { + startBit = (bit + 1) % 8; + if (startBit != 0) + { + stream.Seek(-1, System.IO.SeekOrigin.Current); + } + break; + } + } + } + + Span pixelSpan = pixels.GetRowSpan(y); + PixelOperations.Instance.FromL8( + configuration, + rowSpan, + pixelSpan); + } + } + } +} diff --git a/src/ImageSharp/Formats/Pbm/BinaryEncoder.cs b/src/ImageSharp/Formats/Pbm/BinaryEncoder.cs new file mode 100644 index 000000000..1233c87fc --- /dev/null +++ b/src/ImageSharp/Formats/Pbm/BinaryEncoder.cs @@ -0,0 +1,203 @@ +// Copyright (c) Six Labors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Buffers; +using System.IO; +using SixLabors.ImageSharp.Memory; +using SixLabors.ImageSharp.PixelFormats; + +namespace SixLabors.ImageSharp.Formats.Pbm +{ + /// + /// Pixel encoding methods for the PBM binary encoding. + /// + internal class BinaryEncoder + { + /// + /// Decode pixels into the PBM binary encoding. + /// + /// The type of input pixel. + /// The configuration. + /// The bytestream to write to. + /// The input image. + /// The ColorType to use. + /// The maximum expected pixel value + /// + /// Thrown if an invalid combination of setting is requested. + /// + public static void WritePixels(Configuration configuration, Stream stream, ImageFrame image, PbmColorType colorType, int maxPixelValue) + where TPixel : unmanaged, IPixel + { + if (colorType == PbmColorType.Grayscale) + { + if (maxPixelValue < 256) + { + WriteGrayscale(configuration, stream, image); + } + else + { + WriteWideGrayscale(configuration, stream, image); + } + } + else if (colorType == PbmColorType.Rgb) + { + if (maxPixelValue < 256) + { + WriteRgb(configuration, stream, image); + } + else + { + WriteWideRgb(configuration, stream, image); + } + } + else + { + WriteBlackAndWhite(configuration, stream, image); + } + } + + private static void WriteGrayscale(Configuration configuration, Stream stream, ImageFrame image) + where TPixel : unmanaged, IPixel + { + int width = image.Size().Width; + int height = image.Size().Height; + MemoryAllocator allocator = configuration.MemoryAllocator; + using IMemoryOwner row = allocator.Allocate(width); + Span rowSpan = row.GetSpan(); + + for (int y = 0; y < height; y++) + { + Span pixelSpan = image.GetPixelRowSpan(y); + + PixelOperations.Instance.ToL8Bytes( + configuration, + pixelSpan, + rowSpan, + width); + + stream.Write(rowSpan); + } + } + + private static void WriteWideGrayscale(Configuration configuration, Stream stream, ImageFrame image) + where TPixel : unmanaged, IPixel + { + int width = image.Size().Width; + int height = image.Size().Height; + int bytesPerPixel = 2; + MemoryAllocator allocator = configuration.MemoryAllocator; + using IMemoryOwner row = allocator.Allocate(width * bytesPerPixel); + Span rowSpan = row.GetSpan(); + + for (int y = 0; y < height; y++) + { + Span pixelSpan = image.GetPixelRowSpan(y); + + PixelOperations.Instance.ToL16Bytes( + configuration, + pixelSpan, + rowSpan, + width); + + stream.Write(rowSpan); + } + } + + private static void WriteRgb(Configuration configuration, Stream stream, ImageFrame image) + where TPixel : unmanaged, IPixel + { + int width = image.Size().Width; + int height = image.Size().Height; + int bytesPerPixel = 3; + MemoryAllocator allocator = configuration.MemoryAllocator; + using IMemoryOwner row = allocator.Allocate(width * bytesPerPixel); + Span rowSpan = row.GetSpan(); + + for (int y = 0; y < height; y++) + { + Span pixelSpan = image.GetPixelRowSpan(y); + + PixelOperations.Instance.ToRgb24Bytes( + configuration, + pixelSpan, + rowSpan, + width); + + stream.Write(rowSpan); + } + } + + private static void WriteWideRgb(Configuration configuration, Stream stream, ImageFrame image) + where TPixel : unmanaged, IPixel + { + int width = image.Size().Width; + int height = image.Size().Height; + int bytesPerPixel = 6; + MemoryAllocator allocator = configuration.MemoryAllocator; + using IMemoryOwner row = allocator.Allocate(width * bytesPerPixel); + Span rowSpan = row.GetSpan(); + + for (int y = 0; y < height; y++) + { + Span pixelSpan = image.GetPixelRowSpan(y); + + PixelOperations.Instance.ToRgb48Bytes( + configuration, + pixelSpan, + rowSpan, + width); + + stream.Write(rowSpan); + } + } + + private static void WriteBlackAndWhite(Configuration configuration, Stream stream, ImageFrame image) + where TPixel : unmanaged, IPixel + { + int width = image.Size().Width; + int height = image.Size().Height; + MemoryAllocator allocator = configuration.MemoryAllocator; + using IMemoryOwner row = allocator.Allocate(width); + Span rowSpan = row.GetSpan(); + + int previousValue = 0; + int startBit = 0; + for (int y = 0; y < height; y++) + { + Span pixelSpan = image.GetPixelRowSpan(y); + + PixelOperations.Instance.ToL8( + configuration, + pixelSpan, + rowSpan); + + for (int x = 0; x < width;) + { + int value = previousValue; + for (int i = startBit; i < 8; i++) + { + if (rowSpan[x].PackedValue < 128) + { + value |= 0x80 >> i; + } + + x++; + if (x == width) + { + previousValue = value; + startBit = (i + 1) % 8; + break; + } + } + + if (startBit == 0) + { + stream.WriteByte((byte)value); + previousValue = 0; + } + } + } + } + } +} diff --git a/src/ImageSharp/Formats/Pbm/BufferedReadStreamExtensions.cs b/src/ImageSharp/Formats/Pbm/BufferedReadStreamExtensions.cs new file mode 100644 index 000000000..054731b48 --- /dev/null +++ b/src/ImageSharp/Formats/Pbm/BufferedReadStreamExtensions.cs @@ -0,0 +1,65 @@ +// Copyright (c) Six Labors. +// Licensed under the Apache License, Version 2.0. + +using System.IO; +using SixLabors.ImageSharp.IO; + +namespace SixLabors.ImageSharp.Formats.Pbm +{ + /// + /// Extensions methods for . + /// + internal static class BufferedReadStreamExtensions + { + /// + /// Skip over any whitespace or any comments. + /// + public static void SkipWhitespaceAndComments(this BufferedReadStream stream) + { + bool isWhitespace; + do + { + int val = stream.ReadByte(); + + // Comments start with '#' and end at the next new-line. + if (val == 0x23) + { + int innerValue; + do + { + innerValue = stream.ReadByte(); + } + while (innerValue != 0x0a); + + // Continue searching for whitespace. + val = innerValue; + } + + isWhitespace = val is 0x09 or 0x0a or 0x0d or 0x20; + } + while (isWhitespace); + stream.Seek(-1, SeekOrigin.Current); + } + + /// + /// Read a decimal text value. + /// + /// The integer value of the decimal. + public static int ReadDecimal(this BufferedReadStream stream) + { + int value = 0; + while (true) + { + int current = stream.ReadByte() - 0x30; + if (current < 0 || current > 9) + { + break; + } + + value = (value * 10) + current; + } + + return value; + } + } +} diff --git a/src/ImageSharp/Formats/Pbm/IPbmEncoderOptions.cs b/src/ImageSharp/Formats/Pbm/IPbmEncoderOptions.cs new file mode 100644 index 000000000..c5c409ec8 --- /dev/null +++ b/src/ImageSharp/Formats/Pbm/IPbmEncoderOptions.cs @@ -0,0 +1,26 @@ +// Copyright (c) Six Labors. +// Licensed under the Apache License, Version 2.0. + +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 maximum pixel value, per component. + /// + int? MaxPixelValue { get; } + } +} diff --git a/src/ImageSharp/Formats/Pbm/MetadataExtensions.cs b/src/ImageSharp/Formats/Pbm/MetadataExtensions.cs new file mode 100644 index 000000000..cce8fb318 --- /dev/null +++ b/src/ImageSharp/Formats/Pbm/MetadataExtensions.cs @@ -0,0 +1,21 @@ +// Copyright (c) Six Labors. +// Licensed under the Apache License, Version 2.0. + +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/PbmColorType.cs b/src/ImageSharp/Formats/Pbm/PbmColorType.cs new file mode 100644 index 000000000..827f19344 --- /dev/null +++ b/src/ImageSharp/Formats/Pbm/PbmColorType.cs @@ -0,0 +1,26 @@ +// Copyright (c) Six Labors. +// Licensed under the Apache License, Version 2.0. + +namespace SixLabors.ImageSharp.Formats.Pbm +{ + /// + /// Provides enumeration of available PBM color types. + /// + public enum PbmColorType : byte + { + /// + /// PBM + /// + BlackAndWhite = 0, + + /// + /// PGM - Greyscale. Single component. + /// + Grayscale = 1, + + /// + /// PPM - RGB Color. 3 components. + /// + Rgb = 2, + } +} diff --git a/src/ImageSharp/Formats/Pbm/PbmConfigurationModule.cs b/src/ImageSharp/Formats/Pbm/PbmConfigurationModule.cs new file mode 100644 index 000000000..172bda667 --- /dev/null +++ b/src/ImageSharp/Formats/Pbm/PbmConfigurationModule.cs @@ -0,0 +1,19 @@ +// Copyright (c) Six Labors. +// Licensed under the Apache License, Version 2.0. + +namespace SixLabors.ImageSharp.Formats.Pbm +{ + /// + /// Registers the image encoders, decoders and mime type detectors for the Pbm format. + /// + public sealed class PbmConfigurationModule : IConfigurationModule + { + /// + public void Configure(Configuration configuration) + { + configuration.ImageFormatsManager.SetEncoder(PbmFormat.Instance, new PbmEncoder()); + configuration.ImageFormatsManager.SetDecoder(PbmFormat.Instance, new PbmDecoder()); + configuration.ImageFormatsManager.AddImageFormatDetector(new PbmImageFormatDetector()); + } + } +} diff --git a/src/ImageSharp/Formats/Pbm/PbmConstants.cs b/src/ImageSharp/Formats/Pbm/PbmConstants.cs new file mode 100644 index 000000000..0aa9b706a --- /dev/null +++ b/src/ImageSharp/Formats/Pbm/PbmConstants.cs @@ -0,0 +1,28 @@ +// Copyright (c) Six Labors. +// Licensed under the Apache License, Version 2.0. + +using System.Collections.Generic; + +namespace SixLabors.ImageSharp.Formats.Pbm +{ + /// + /// Contains PBM constant values defined in the specification. + /// + internal static class PbmConstants + { + /// + /// The maximum allowable pixel value of a ppm image. + /// + public const ushort MaxLength = 65535; + + /// + /// The list of mimetypes that equate to a ppm. + /// + public static readonly IEnumerable MimeTypes = new[] { "image/x-portable-pixmap", "image/x-portable-anymap", "image/x-portable-arbitrarymap" }; + + /// + /// The list of file extensions that equate to a ppm. + /// + public static readonly IEnumerable FileExtensions = new[] { "ppm", "pbm", "pgm", "pam" }; + } +} diff --git a/src/ImageSharp/Formats/Pbm/PbmDecoder.cs b/src/ImageSharp/Formats/Pbm/PbmDecoder.cs new file mode 100644 index 000000000..640ec3823 --- /dev/null +++ b/src/ImageSharp/Formats/Pbm/PbmDecoder.cs @@ -0,0 +1,67 @@ +// Copyright (c) Six Labors. +// Licensed under the Apache License, Version 2.0. + +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using SixLabors.ImageSharp.PixelFormats; + +namespace SixLabors.ImageSharp.Formats.Pbm +{ + /// + /// Image decoder for generating an image out of a ppm stream. + /// + public sealed class PbmDecoder : IImageDecoder, IImageInfoDetector + { + /// + public Image Decode(Configuration configuration, Stream stream) + where TPixel : unmanaged, IPixel + { + Guard.NotNull(stream, nameof(stream)); + + var decoder = new PbmDecoderCore(configuration); + return decoder.Decode(configuration, stream); + } + + /// + public Image Decode(Configuration configuration, Stream stream) + => this.Decode(configuration, stream); + + /// + public Task> DecodeAsync(Configuration configuration, Stream stream, CancellationToken cancellationToken) + where TPixel : unmanaged, IPixel + { + Guard.NotNull(stream, nameof(stream)); + + var decoder = new PbmDecoderCore(configuration); + return decoder.DecodeAsync(configuration, stream, cancellationToken); + } + + /// + public async Task DecodeAsync(Configuration configuration, Stream stream, CancellationToken cancellationToken) + => await this.DecodeAsync(configuration, stream, cancellationToken) + .ConfigureAwait(false); + + /// + public IImageInfo Identify(Configuration configuration, Stream stream) + { + Guard.NotNull(stream, nameof(stream)); + + var decoder = new PbmDecoderCore(configuration); + return decoder.Identify(configuration, stream); + } + + /// + public async Task IdentifyAsync(Configuration configuration, Stream stream, CancellationToken cancellationToken) + { + Guard.NotNull(stream, nameof(stream)); + + // The introduction of a local variable that refers to an object the implements + // IDisposable means you must use async/await, where the compiler generates the + // state machine and a continuation. + var decoder = new PbmDecoderCore(configuration); + return await decoder.IdentifyAsync(configuration, stream, cancellationToken) + .ConfigureAwait(false); + } + } +} diff --git a/src/ImageSharp/Formats/Pbm/PbmDecoderCore.cs b/src/ImageSharp/Formats/Pbm/PbmDecoderCore.cs new file mode 100644 index 000000000..31969af47 --- /dev/null +++ b/src/ImageSharp/Formats/Pbm/PbmDecoderCore.cs @@ -0,0 +1,169 @@ +// Copyright (c) Six Labors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Threading; +using SixLabors.ImageSharp.IO; +using SixLabors.ImageSharp.Memory; +using SixLabors.ImageSharp.Metadata; +using SixLabors.ImageSharp.PixelFormats; + +namespace SixLabors.ImageSharp.Formats.Pbm +{ + /// + /// Performs the PBM decoding operation. + /// + internal sealed class PbmDecoderCore : IImageDecoderInternals + { + /// + /// Initializes a new instance of the class. + /// + /// The configuration. + public PbmDecoderCore(Configuration configuration) => this.Configuration = configuration ?? Configuration.Default; + + /// + public Configuration Configuration { get; } + + /// + /// Gets the colortype to use + /// + public PbmColorType ColorType { get; private set; } + + /// + /// Gets the size of the pixel array + /// + public Size PixelSize { get; private set; } + + /// + /// Gets the maximum pixel value + /// + public int MaxPixelValue { get; private set; } + + /// + /// Gets the Encoding of pixels + /// + public PbmEncoding Encoding { get; private set; } + + /// + /// Gets the decoded by this decoder instance. + /// + public ImageMetadata Metadata { get; private set; } + + /// + Size IImageDecoderInternals.Dimensions => this.PixelSize; + + /// + public Image Decode(BufferedReadStream stream, CancellationToken cancellationToken) + where TPixel : unmanaged, IPixel + { + this.ProcessHeader(stream); + + var image = new Image(this.Configuration, this.PixelSize.Width, this.PixelSize.Height, this.Metadata); + + Buffer2D pixels = image.GetRootFramePixelBuffer(); + + this.ProcessPixels(stream, pixels); + + return image; + } + + /// + public IImageInfo Identify(BufferedReadStream stream, CancellationToken cancellationToken) + { + this.ProcessHeader(stream); + + int bitsPerPixel = this.MaxPixelValue > 255 ? 16 : 8; + return new ImageInfo(new PixelTypeInfo(bitsPerPixel), this.PixelSize.Width, this.PixelSize.Height, this.Metadata); + } + + /// + /// Processes the ppm header. + /// + /// The input stream. + private void ProcessHeader(BufferedReadStream stream) + { + byte[] buffer = new byte[2]; + + int bytesRead = stream.Read(buffer, 0, 2); + if (bytesRead != 2 || buffer[0] != 'P') + { + // Empty or not an PPM image. + throw new InvalidImageContentException("TODO"); + } + + switch ((char)buffer[1]) + { + case '1': + // Plain PBM format: 1 component per pixel, boolean value ('0' or '1'). + this.ColorType = PbmColorType.BlackAndWhite; + this.Encoding = PbmEncoding.Plain; + break; + case '2': + // Plain PGM format: 1 component per pixel, in decimal text. + this.ColorType = PbmColorType.Grayscale; + this.Encoding = PbmEncoding.Plain; + break; + case '3': + // Plain PPM format: 3 components per pixel, in decimal text. + this.ColorType = PbmColorType.Rgb; + this.Encoding = PbmEncoding.Plain; + break; + case '4': + // Binary PBM format: 1 component per pixel, 8 picels per byte. + this.ColorType = PbmColorType.BlackAndWhite; + this.Encoding = PbmEncoding.Binary; + break; + case '5': + // Binary PGM format: 1 components per pixel, in binary integers. + this.ColorType = PbmColorType.Grayscale; + this.Encoding = PbmEncoding.Binary; + break; + case '6': + // Binary PPM format: 3 components per pixel, in binary integers. + this.ColorType = PbmColorType.Rgb; + this.Encoding = PbmEncoding.Binary; + break; + case '7': + // PAM image: sequence of images. + // Not implemented yet + default: + throw new NotImplementedException("TODO"); + } + + stream.SkipWhitespaceAndComments(); + int width = stream.ReadDecimal(); + stream.SkipWhitespaceAndComments(); + int height = stream.ReadDecimal(); + stream.SkipWhitespaceAndComments(); + if (this.ColorType != PbmColorType.BlackAndWhite) + { + this.MaxPixelValue = stream.ReadDecimal(); + stream.SkipWhitespaceAndComments(); + } + else + { + this.MaxPixelValue = 1; + } + + this.PixelSize = new Size(width, height); + this.Metadata = new ImageMetadata(); + PbmMetadata meta = this.Metadata.GetPbmMetadata(); + meta.Encoding = this.Encoding; + meta.ColorType = this.ColorType; + meta.MaxPixelValue = this.MaxPixelValue; + } + + private void ProcessPixels(BufferedReadStream stream, Buffer2D pixels) + where TPixel : unmanaged, IPixel + { + if (this.Encoding == PbmEncoding.Binary) + { + BinaryDecoder.Process(this.Configuration, pixels, stream, this.ColorType, this.MaxPixelValue); + } + else + { + PlainDecoder.Process(this.Configuration, pixels, stream, this.ColorType, this.MaxPixelValue); + } + } + } +} diff --git a/src/ImageSharp/Formats/Pbm/PbmEncoder.cs b/src/ImageSharp/Formats/Pbm/PbmEncoder.cs new file mode 100644 index 000000000..21565d161 --- /dev/null +++ b/src/ImageSharp/Formats/Pbm/PbmEncoder.cs @@ -0,0 +1,48 @@ +// Copyright (c) Six Labors. +// Licensed under the Apache License, Version 2.0. + +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using SixLabors.ImageSharp.Advanced; +using SixLabors.ImageSharp.PixelFormats; + +namespace SixLabors.ImageSharp.Formats.Pbm +{ + /// + /// Image encoder for writing an image to a stream as PGM, PBM, PPM or PAM bitmap. + /// + public sealed class PbmEncoder : IImageEncoder, IPbmEncoderOptions + { + /// + /// Gets or sets the Encoding of the pixels. + /// + public PbmEncoding? Encoding { get; set; } + + /// + /// Gets or sets the Color type of the resulting image. + /// + public PbmColorType? ColorType { get; set; } + + /// + /// Gets or sets the maximum pixel value, per component. + /// + public int? MaxPixelValue { get; set; } + + /// + public void Encode(Image image, Stream stream) + where TPixel : unmanaged, IPixel + { + var encoder = new PbmEncoderCore(image.GetConfiguration(), this); + encoder.Encode(image, stream); + } + + /// + public Task EncodeAsync(Image image, Stream stream, CancellationToken cancellationToken) + where TPixel : unmanaged, IPixel + { + var encoder = new PbmEncoderCore(image.GetConfiguration(), this); + return encoder.EncodeAsync(image, stream, cancellationToken); + } + } +} diff --git a/src/ImageSharp/Formats/Pbm/PbmEncoderCore.cs b/src/ImageSharp/Formats/Pbm/PbmEncoderCore.cs new file mode 100644 index 000000000..527ceb8ee --- /dev/null +++ b/src/ImageSharp/Formats/Pbm/PbmEncoderCore.cs @@ -0,0 +1,176 @@ +// Copyright (c) Six Labors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Buffers; +using System.IO; +using System.Text; +using System.Threading; +using SixLabors.ImageSharp.Advanced; +using SixLabors.ImageSharp.Memory; +using SixLabors.ImageSharp.PixelFormats; + +namespace SixLabors.ImageSharp.Formats.Pbm +{ + /// + /// Image encoder for writing an image to a stream as a PGM, PBM, PPM or PAM bitmap. + /// + internal sealed class PbmEncoderCore : IImageEncoderInternals + { + private const char NewLine = '\n'; + + /// + /// The global configuration. + /// + private Configuration configuration; + + /// + /// The encoder options. + /// + private readonly IPbmEncoderOptions options; + + /// + /// The encoding for the pixels. + /// + private PbmEncoding encoding; + + /// + /// Gets the Color type of the resulting image. + /// + private PbmColorType colorType; + + /// + /// Gets the maximum pixel value, per component. + /// + private int maxPixelValue; + + /// + /// Initializes a new instance of the class. + /// + /// The configuration. + /// The encoder options. + public PbmEncoderCore(Configuration configuration, IPbmEncoderOptions options) + { + this.configuration = configuration; + this.options = options; + } + + /// + /// Encodes the image to the specified stream from the . + /// + /// The pixel format. + /// The to encode from. + /// The to encode the image data to. + /// The token to request cancellation. + public void Encode(Image image, Stream stream, CancellationToken cancellationToken) + where TPixel : unmanaged, IPixel + { + Guard.NotNull(image, nameof(image)); + Guard.NotNull(stream, nameof(stream)); + + this.DeduceOptions(image); + + string signature = this.DeduceSignature(); + this.WriteHeader(stream, signature, image.Size()); + + this.WritePixels(stream, image.Frames.RootFrame); + + stream.Flush(); + } + + private void DeduceOptions(Image image) + where TPixel : unmanaged, IPixel + { + this.configuration = image.GetConfiguration(); + PbmMetadata metadata = image.Metadata.GetPbmMetadata(); + this.encoding = this.options.Encoding ?? metadata.Encoding; + this.colorType = this.options.ColorType ?? metadata.ColorType; + if (this.colorType != PbmColorType.BlackAndWhite) + { + this.maxPixelValue = this.options.MaxPixelValue ?? metadata.MaxPixelValue; + } + } + + private string DeduceSignature() + { + string signature; + if (this.colorType == PbmColorType.BlackAndWhite) + { + if (this.encoding == PbmEncoding.Plain) + { + signature = "P1"; + } + else + { + signature = "P4"; + } + } + else if (this.colorType == PbmColorType.Grayscale) + { + if (this.encoding == PbmEncoding.Plain) + { + signature = "P2"; + } + else + { + signature = "P5"; + } + } + else + { + // RGB ColorType + if (this.encoding == PbmEncoding.Plain) + { + signature = "P3"; + } + else + { + signature = "P6"; + } + } + + return signature; + } + + private void WriteHeader(Stream stream, string signature, Size pixelSize) + { + var builder = new StringBuilder(20); + builder.Append(signature); + builder.Append(NewLine); + builder.Append(pixelSize.Width.ToString()); + builder.Append(NewLine); + builder.Append(pixelSize.Height.ToString()); + builder.Append(NewLine); + if (this.colorType != PbmColorType.BlackAndWhite) + { + builder.Append(this.maxPixelValue.ToString()); + builder.Append(NewLine); + } + + string headerStr = builder.ToString(); + byte[] headerBytes = Encoding.ASCII.GetBytes(headerStr); + stream.Write(headerBytes, 0, headerBytes.Length); + } + + /// + /// Writes the pixel data to the binary stream. + /// + /// The pixel format. + /// The to write to. + /// + /// The containing pixel data. + /// + private void WritePixels(Stream stream, ImageFrame image) + where TPixel : unmanaged, IPixel + { + if (this.encoding == PbmEncoding.Plain) + { + PlainEncoder.WritePixels(this.configuration, stream, image, this.colorType, this.maxPixelValue); + } + else + { + BinaryEncoder.WritePixels(this.configuration, stream, image, this.colorType, this.maxPixelValue); + } + } + } +} diff --git a/src/ImageSharp/Formats/Pbm/PbmEncoding.cs b/src/ImageSharp/Formats/Pbm/PbmEncoding.cs new file mode 100644 index 000000000..be7fb909f --- /dev/null +++ b/src/ImageSharp/Formats/Pbm/PbmEncoding.cs @@ -0,0 +1,21 @@ +// Copyright (c) Six Labors. +// Licensed under the Apache License, Version 2.0. + +namespace SixLabors.ImageSharp.Formats.Pbm +{ + /// + /// Provides enumeration of available PBM encodings. + /// + public enum PbmEncoding : byte + { + /// + /// Plain text decimal encoding. + /// + Plain = 0, + + /// + /// Binary integer encoding. + /// + Binary = 1, + } +} diff --git a/src/ImageSharp/Formats/Pbm/PbmFormat.cs b/src/ImageSharp/Formats/Pbm/PbmFormat.cs new file mode 100644 index 000000000..35aa9cf8c --- /dev/null +++ b/src/ImageSharp/Formats/Pbm/PbmFormat.cs @@ -0,0 +1,37 @@ +// Copyright (c) Six Labors. +// Licensed under the Apache License, Version 2.0. + +using System.Collections.Generic; + +namespace SixLabors.ImageSharp.Formats.Pbm +{ + /// + /// Registers the image encoders, decoders and mime type detectors for the PBM format. + /// + public sealed class PbmFormat : IImageFormat + { + private PbmFormat() + { + } + + /// + /// Gets the current instance. + /// + public static PbmFormat Instance { get; } = new PbmFormat(); + + /// + public string Name => "PBM"; + + /// + public string DefaultMimeType => "image/x-portable-pixmap"; + + /// + public IEnumerable MimeTypes => PbmConstants.MimeTypes; + + /// + public IEnumerable FileExtensions => PbmConstants.FileExtensions; + + /// + public PbmMetadata CreateDefaultFormatMetadata() => new(); + } +} diff --git a/src/ImageSharp/Formats/Pbm/PbmImageFormatDetector.cs b/src/ImageSharp/Formats/Pbm/PbmImageFormatDetector.cs new file mode 100644 index 000000000..943424dc9 --- /dev/null +++ b/src/ImageSharp/Formats/Pbm/PbmImageFormatDetector.cs @@ -0,0 +1,33 @@ +// Copyright (c) Six Labors. +// Licensed under the Apache License, Version 2.0. + +using System; + +namespace SixLabors.ImageSharp.Formats.Pbm +{ + /// + /// Detects Pbm file headers. + /// + public sealed class PbmImageFormatDetector : IImageFormatDetector + { + private const byte P = (byte)'P'; + private const byte Zero = (byte)'0'; + private const byte Seven = (byte)'7'; + + /// + public int HeaderSize => 2; + + /// + public IImageFormat DetectFormat(ReadOnlySpan header) => this.IsSupportedFileFormat(header) ? PbmFormat.Instance : null; + + private bool IsSupportedFileFormat(ReadOnlySpan header) + { + if (header.Length >= this.HeaderSize) + { + return header[0] == P && header[1] > Zero && header[1] < Seven; + } + + return false; + } + } +} diff --git a/src/ImageSharp/Formats/Pbm/PbmMetadata.cs b/src/ImageSharp/Formats/Pbm/PbmMetadata.cs new file mode 100644 index 000000000..b29cd27c2 --- /dev/null +++ b/src/ImageSharp/Formats/Pbm/PbmMetadata.cs @@ -0,0 +1,48 @@ +// Copyright (c) Six Labors. +// Licensed under the Apache License, Version 2.0. + +namespace SixLabors.ImageSharp.Formats.Pbm +{ + /// + /// Provides PBM specific metadata information for the image. + /// + public class PbmMetadata : IDeepCloneable + { + /// + /// Initializes a new instance of the class. + /// + public PbmMetadata() + { + this.MaxPixelValue = this.ColorType == PbmColorType.BlackAndWhite ? 1 : 255; + } + + /// + /// Initializes a new instance of the class. + /// + /// The metadata to create an instance from. + private PbmMetadata(PbmMetadata other) + { + this.Encoding = other.Encoding; + this.ColorType = other.ColorType; + this.MaxPixelValue = other.MaxPixelValue; + } + + /// + /// Gets or sets the encoding of the pixels. + /// + public PbmEncoding Encoding { get; set; } = PbmEncoding.Plain; + + /// + /// Gets or sets the color type. + /// + public PbmColorType ColorType { get; set; } = PbmColorType.Grayscale; + + /// + /// Gets or sets the maximum pixel value. + /// + public int MaxPixelValue { get; set; } + + /// + public IDeepCloneable DeepClone() => new PbmMetadata(this); + } +} diff --git a/src/ImageSharp/Formats/Pbm/PlainDecoder.cs b/src/ImageSharp/Formats/Pbm/PlainDecoder.cs new file mode 100644 index 000000000..bf2b10e1d --- /dev/null +++ b/src/ImageSharp/Formats/Pbm/PlainDecoder.cs @@ -0,0 +1,197 @@ +// Copyright (c) Six Labors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Buffers; +using SixLabors.ImageSharp.IO; +using SixLabors.ImageSharp.Memory; +using SixLabors.ImageSharp.PixelFormats; + +namespace SixLabors.ImageSharp.Formats.Pbm +{ + /// + /// Pixel decoding methods for the PBM plain encoding. + /// + internal class PlainDecoder + { + /// + /// Decode the specified pixels. + /// + /// The type of pixel to encode to. + /// The configuration. + /// The pixel array to encode into. + /// The stream to read the data from. + /// The ColorType to decode. + /// The maximum expected pixel value + public static void Process(Configuration configuration, Buffer2D pixels, BufferedReadStream stream, PbmColorType colorType, int maxPixelValue) + where TPixel : unmanaged, IPixel + { + if (colorType == PbmColorType.Grayscale) + { + if (maxPixelValue < 256) + { + ProcessGrayscale(configuration, pixels, stream); + } + else + { + ProcessWideGrayscale(configuration, pixels, stream); + } + } + else if (colorType == PbmColorType.Rgb) + { + if (maxPixelValue < 256) + { + ProcessRgb(configuration, pixels, stream); + } + else + { + ProcessWideRgb(configuration, pixels, stream); + } + } + else + { + ProcessBlackAndWhite(configuration, pixels, stream); + } + } + + private static void ProcessGrayscale(Configuration configuration, Buffer2D pixels, BufferedReadStream stream) + where TPixel : unmanaged, IPixel + { + int width = pixels.Width; + int height = pixels.Height; + MemoryAllocator allocator = configuration.MemoryAllocator; + using IMemoryOwner row = allocator.Allocate(width); + Span rowSpan = row.GetSpan(); + + for (int y = 0; y < height; y++) + { + for (int x = 0; x < width; x++) + { + byte value = (byte)stream.ReadDecimal(); + stream.SkipWhitespaceAndComments(); + rowSpan[x] = new L8(value); + } + + Span pixelSpan = pixels.GetRowSpan(y); + PixelOperations.Instance.FromL8( + configuration, + rowSpan, + pixelSpan); + } + } + + private static void ProcessWideGrayscale(Configuration configuration, Buffer2D pixels, BufferedReadStream stream) + where TPixel : unmanaged, IPixel + { + int width = pixels.Width; + int height = pixels.Height; + MemoryAllocator allocator = configuration.MemoryAllocator; + using IMemoryOwner row = allocator.Allocate(width); + Span rowSpan = row.GetSpan(); + + for (int y = 0; y < height; y++) + { + for (int x = 0; x < width; x++) + { + ushort value = (ushort)stream.ReadDecimal(); + stream.SkipWhitespaceAndComments(); + rowSpan[x] = new L16(value); + } + + Span pixelSpan = pixels.GetRowSpan(y); + PixelOperations.Instance.FromL16( + configuration, + rowSpan, + pixelSpan); + } + } + + private static void ProcessRgb(Configuration configuration, Buffer2D pixels, BufferedReadStream stream) + where TPixel : unmanaged, IPixel + { + int width = pixels.Width; + int height = pixels.Height; + MemoryAllocator allocator = configuration.MemoryAllocator; + using IMemoryOwner row = allocator.Allocate(width); + Span rowSpan = row.GetSpan(); + + for (int y = 0; y < height; y++) + { + for (int x = 0; x < width; x++) + { + byte red = (byte)stream.ReadDecimal(); + stream.SkipWhitespaceAndComments(); + byte green = (byte)stream.ReadDecimal(); + stream.SkipWhitespaceAndComments(); + byte blue = (byte)stream.ReadDecimal(); + stream.SkipWhitespaceAndComments(); + rowSpan[x] = new Rgb24(red, green, blue); + } + + Span pixelSpan = pixels.GetRowSpan(y); + PixelOperations.Instance.FromRgb24( + configuration, + rowSpan, + pixelSpan); + } + } + + private static void ProcessWideRgb(Configuration configuration, Buffer2D pixels, BufferedReadStream stream) + where TPixel : unmanaged, IPixel + { + int width = pixels.Width; + int height = pixels.Height; + MemoryAllocator allocator = configuration.MemoryAllocator; + using IMemoryOwner row = allocator.Allocate(width); + Span rowSpan = row.GetSpan(); + + for (int y = 0; y < height; y++) + { + for (int x = 0; x < width; x++) + { + ushort red = (ushort)stream.ReadDecimal(); + stream.SkipWhitespaceAndComments(); + ushort green = (ushort)stream.ReadDecimal(); + stream.SkipWhitespaceAndComments(); + ushort blue = (ushort)stream.ReadDecimal(); + stream.SkipWhitespaceAndComments(); + rowSpan[x] = new Rgb48(red, green, blue); + } + + Span pixelSpan = pixels.GetRowSpan(y); + PixelOperations.Instance.FromRgb48( + configuration, + rowSpan, + pixelSpan); + } + } + + private static void ProcessBlackAndWhite(Configuration configuration, Buffer2D pixels, BufferedReadStream stream) + where TPixel : unmanaged, IPixel + { + int width = pixels.Width; + int height = pixels.Height; + MemoryAllocator allocator = configuration.MemoryAllocator; + using IMemoryOwner row = allocator.Allocate(width); + Span rowSpan = row.GetSpan(); + var white = new L8(0); + var black = new L8(255); + + for (int y = 0; y < height; y++) + { + for (int x = 0; x < width; x++) + { + int value = stream.ReadDecimal(); + stream.SkipWhitespaceAndComments(); + rowSpan[x] = value == 0 ? white : black; + } + + Span pixelSpan = pixels.GetRowSpan(y); + PixelOperations.Instance.FromL8( + configuration, + rowSpan, + pixelSpan); + } + } + } +} diff --git a/src/ImageSharp/Formats/Pbm/PlainEncoder.cs b/src/ImageSharp/Formats/Pbm/PlainEncoder.cs new file mode 100644 index 000000000..d90eaf73f --- /dev/null +++ b/src/ImageSharp/Formats/Pbm/PlainEncoder.cs @@ -0,0 +1,228 @@ +// Copyright (c) Six Labors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Buffers; +using System.IO; +using SixLabors.ImageSharp.Memory; +using SixLabors.ImageSharp.PixelFormats; + +namespace SixLabors.ImageSharp.Formats.Pbm +{ + /// + /// Pixel encoding methods for the PBM plain encoding. + /// + internal class PlainEncoder + { + private const int MaxLineLength = 70; + private const byte NewLine = 0x0a; + private const byte Space = 0x20; + private const byte Zero = 0x30; + private const byte One = 0x31; + + /// + /// Decode pixels into the PBM plain encoding. + /// + /// The type of input pixel. + /// The configuration. + /// The bytestream to write to. + /// The input image. + /// The ColorType to use. + /// The maximum expected pixel value + public static void WritePixels(Configuration configuration, Stream stream, ImageFrame image, PbmColorType colorType, int maxPixelValue) + where TPixel : unmanaged, IPixel + { + if (colorType == PbmColorType.Grayscale) + { + if (maxPixelValue < 256) + { + WriteGrayscale(configuration, stream, image); + } + else + { + WriteWideGrayscale(configuration, stream, image); + } + } + else if (colorType == PbmColorType.Rgb) + { + if (maxPixelValue < 256) + { + WriteRgb(configuration, stream, image); + } + else + { + WriteWideRgb(configuration, stream, image); + } + } + else + { + WriteBlackAndWhite(configuration, stream, image); + } + } + + private static void WriteGrayscale(Configuration configuration, Stream stream, ImageFrame image) + where TPixel : unmanaged, IPixel + { + int width = image.Size().Width; + int height = image.Size().Height; + int bytesWritten = -1; + MemoryAllocator allocator = configuration.MemoryAllocator; + using IMemoryOwner row = allocator.Allocate(width); + Span rowSpan = row.GetSpan(); + + for (int y = 0; y < height; y++) + { + Span pixelSpan = image.GetPixelRowSpan(y); + PixelOperations.Instance.ToL8( + configuration, + pixelSpan, + rowSpan); + + for (int x = 0; x < width; x++) + { + WriteWhitespace(stream, ref bytesWritten); + bytesWritten += stream.WriteDecimal(rowSpan[x].PackedValue); + } + } + } + + private static void WriteWideGrayscale(Configuration configuration, Stream stream, ImageFrame image) + where TPixel : unmanaged, IPixel + { + int width = image.Size().Width; + int height = image.Size().Height; + int bytesWritten = -1; + MemoryAllocator allocator = configuration.MemoryAllocator; + using IMemoryOwner row = allocator.Allocate(width); + Span rowSpan = row.GetSpan(); + + for (int y = 0; y < height; y++) + { + Span pixelSpan = image.GetPixelRowSpan(y); + PixelOperations.Instance.ToL16( + configuration, + pixelSpan, + rowSpan); + + for (int x = 0; x < width; x++) + { + WriteWhitespace(stream, ref bytesWritten); + bytesWritten += stream.WriteDecimal(rowSpan[x].PackedValue); + } + } + } + + private static void WriteRgb(Configuration configuration, Stream stream, ImageFrame image) + where TPixel : unmanaged, IPixel + { + int width = image.Size().Width; + int height = image.Size().Height; + int bytesWritten = -1; + MemoryAllocator allocator = configuration.MemoryAllocator; + using IMemoryOwner row = allocator.Allocate(width); + Span rowSpan = row.GetSpan(); + + for (int y = 0; y < height; y++) + { + Span pixelSpan = image.GetPixelRowSpan(y); + PixelOperations.Instance.ToRgb24( + configuration, + pixelSpan, + rowSpan); + + for (int x = 0; x < width; x++) + { + WriteWhitespace(stream, ref bytesWritten); + bytesWritten += stream.WriteDecimal(rowSpan[x].R); + WriteWhitespace(stream, ref bytesWritten); + bytesWritten += stream.WriteDecimal(rowSpan[x].G); + WriteWhitespace(stream, ref bytesWritten); + bytesWritten += stream.WriteDecimal(rowSpan[x].B); + } + } + } + + private static void WriteWideRgb(Configuration configuration, Stream stream, ImageFrame image) + where TPixel : unmanaged, IPixel + { + int width = image.Size().Width; + int height = image.Size().Height; + int bytesWritten = -1; + MemoryAllocator allocator = configuration.MemoryAllocator; + using IMemoryOwner row = allocator.Allocate(width); + Span rowSpan = row.GetSpan(); + + for (int y = 0; y < height; y++) + { + Span pixelSpan = image.GetPixelRowSpan(y); + PixelOperations.Instance.ToRgb48( + configuration, + pixelSpan, + rowSpan); + + for (int x = 0; x < width; x++) + { + WriteWhitespace(stream, ref bytesWritten); + bytesWritten += stream.WriteDecimal(rowSpan[x].R); + WriteWhitespace(stream, ref bytesWritten); + bytesWritten += stream.WriteDecimal(rowSpan[x].G); + WriteWhitespace(stream, ref bytesWritten); + bytesWritten += stream.WriteDecimal(rowSpan[x].B); + } + } + } + + private static void WriteBlackAndWhite(Configuration configuration, Stream stream, ImageFrame image) + where TPixel : unmanaged, IPixel + { + int width = image.Size().Width; + int height = image.Size().Height; + int bytesWritten = -1; + MemoryAllocator allocator = configuration.MemoryAllocator; + using IMemoryOwner row = allocator.Allocate(width); + Span rowSpan = row.GetSpan(); + + for (int y = 0; y < height; y++) + { + Span pixelSpan = image.GetPixelRowSpan(y); + PixelOperations.Instance.ToL8( + configuration, + pixelSpan, + rowSpan); + + for (int x = 0; x < width; x++) + { + WriteWhitespace(stream, ref bytesWritten); + if (rowSpan[x].PackedValue > 127) + { + stream.WriteByte(Zero); + } + else + { + stream.WriteByte(One); + } + + bytesWritten++; + } + } + } + + private static void WriteWhitespace(Stream stream, ref int bytesWritten) + { + if (bytesWritten > MaxLineLength) + { + stream.WriteByte(NewLine); + bytesWritten = 1; + } + else if (bytesWritten == -1) + { + bytesWritten = 0; + } + else + { + stream.WriteByte(Space); + bytesWritten++; + } + } + } +} diff --git a/src/ImageSharp/Formats/Pbm/StreamExtensions.cs b/src/ImageSharp/Formats/Pbm/StreamExtensions.cs new file mode 100644 index 000000000..9851afee0 --- /dev/null +++ b/src/ImageSharp/Formats/Pbm/StreamExtensions.cs @@ -0,0 +1,19 @@ +// Copyright (c) Six Labors. +// Licensed under the Apache License, Version 2.0. + +using System.IO; +using System.Text; + +namespace SixLabors.ImageSharp.Formats.Pbm +{ + internal static class StreamExtensions + { + public static int WriteDecimal(this Stream stream, int value) + { + string str = value.ToString(); + byte[] bytes = Encoding.ASCII.GetBytes(str); + stream.Write(bytes); + return bytes.Length; + } + } +} diff --git a/src/ImageSharp/ImageSharp.csproj b/src/ImageSharp/ImageSharp.csproj index 800b69326..a0a45e8aa 100644 --- a/src/ImageSharp/ImageSharp.csproj +++ b/src/ImageSharp/ImageSharp.csproj @@ -10,7 +10,7 @@ Apache-2.0 https://github.com/SixLabors/ImageSharp/ $(RepositoryUrl) - Image Resize Crop Gif Jpg Jpeg Bitmap Png Tga NetCore + Image Resize Crop Gif Jpg Jpeg Bitmap Pbm Png Tga NetCore A new, fully featured, fully managed, cross-platform, 2D graphics API for .NET Debug;Release;Debug-InnerLoop;Release-InnerLoop diff --git a/tests/ImageSharp.Tests/ConfigurationTests.cs b/tests/ImageSharp.Tests/ConfigurationTests.cs index 803babdfa..104f07c40 100644 --- a/tests/ImageSharp.Tests/ConfigurationTests.cs +++ b/tests/ImageSharp.Tests/ConfigurationTests.cs @@ -21,7 +21,7 @@ namespace SixLabors.ImageSharp.Tests public Configuration DefaultConfiguration { get; } - private readonly int expectedDefaultConfigurationCount = 7; + private readonly int expectedDefaultConfigurationCount = 8; public ConfigurationTests() { diff --git a/tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs b/tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs index bf13a9097..eeb77da67 100644 --- a/tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs +++ b/tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs @@ -136,6 +136,11 @@ namespace SixLabors.ImageSharp.Tests.Formats image.SaveAsJpeg(output); } + using (FileStream output = File.OpenWrite(Path.Combine(path, $"{file.FileNameWithoutExtension}.pbm"))) + { + image.SaveAsPbm(output); + } + using (FileStream output = File.OpenWrite(Path.Combine(path, $"{file.FileNameWithoutExtension}.png"))) { image.SaveAsPng(output); @@ -183,6 +188,10 @@ namespace SixLabors.ImageSharp.Tests.Formats } [Theory] + [InlineData(10, 10, "pbm")] + [InlineData(100, 100, "pbm")] + [InlineData(100, 10, "pbm")] + [InlineData(10, 100, "pbm")] [InlineData(10, 10, "png")] [InlineData(100, 100, "png")] [InlineData(100, 10, "png")] diff --git a/tests/ImageSharp.Tests/Formats/ImageFormatManagerTests.cs b/tests/ImageSharp.Tests/Formats/ImageFormatManagerTests.cs index 5cd70b100..05a7a3be8 100644 --- a/tests/ImageSharp.Tests/Formats/ImageFormatManagerTests.cs +++ b/tests/ImageSharp.Tests/Formats/ImageFormatManagerTests.cs @@ -9,6 +9,7 @@ using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.Formats.Bmp; using SixLabors.ImageSharp.Formats.Gif; using SixLabors.ImageSharp.Formats.Jpeg; +using SixLabors.ImageSharp.Formats.Pbm; using SixLabors.ImageSharp.Formats.Png; using SixLabors.ImageSharp.Formats.Tga; using SixLabors.ImageSharp.Formats.Tiff; @@ -33,6 +34,7 @@ namespace SixLabors.ImageSharp.Tests.Formats [Fact] public void IfAutoLoadWellKnownFormatsIsTrueAllFormatsAreLoaded() { + Assert.Equal(1, this.DefaultFormatsManager.ImageEncoders.Select(item => item.Value).OfType().Count()); Assert.Equal(1, this.DefaultFormatsManager.ImageEncoders.Select(item => item.Value).OfType().Count()); Assert.Equal(1, this.DefaultFormatsManager.ImageEncoders.Select(item => item.Value).OfType().Count()); Assert.Equal(1, this.DefaultFormatsManager.ImageEncoders.Select(item => item.Value).OfType().Count()); @@ -41,6 +43,7 @@ namespace SixLabors.ImageSharp.Tests.Formats Assert.Equal(1, this.DefaultFormatsManager.ImageEncoders.Select(item => item.Value).OfType().Count()); Assert.Equal(1, this.DefaultFormatsManager.ImageEncoders.Select(item => item.Value).OfType().Count()); + Assert.Equal(1, this.DefaultFormatsManager.ImageDecoders.Select(item => item.Value).OfType().Count()); Assert.Equal(1, this.DefaultFormatsManager.ImageDecoders.Select(item => item.Value).OfType().Count()); Assert.Equal(1, this.DefaultFormatsManager.ImageDecoders.Select(item => item.Value).OfType().Count()); Assert.Equal(1, this.DefaultFormatsManager.ImageDecoders.Select(item => item.Value).OfType().Count()); diff --git a/tests/ImageSharp.Tests/Formats/Pbm/ImageExtensionsTest.cs b/tests/ImageSharp.Tests/Formats/Pbm/ImageExtensionsTest.cs new file mode 100644 index 000000000..6ab0cf22f --- /dev/null +++ b/tests/ImageSharp.Tests/Formats/Pbm/ImageExtensionsTest.cs @@ -0,0 +1,155 @@ +// Copyright (c) Six Labors. +// Licensed under the Apache License, Version 2.0. + +using System.IO; +using System.Threading.Tasks; +using SixLabors.ImageSharp.Formats; +using SixLabors.ImageSharp.Formats.Pbm; +using SixLabors.ImageSharp.PixelFormats; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Formats.Pbm +{ + public class ImageExtensionsTest + { + [Fact] + public void SaveAsPbm_Path() + { + string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageExtensionsTest)); + string file = Path.Combine(dir, "SaveAsPbm_Path.pbm"); + + using (var image = new Image(10, 10)) + { + image.SaveAsPbm(file); + } + + using (Image.Load(file, out IImageFormat mime)) + { + Assert.Equal("image/x-portable-pixmap", mime.DefaultMimeType); + } + } + + [Fact] + public async Task SaveAsPbmAsync_Path() + { + string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageExtensionsTest)); + string file = Path.Combine(dir, "SaveAsPbmAsync_Path.pbm"); + + using (var image = new Image(10, 10)) + { + await image.SaveAsPbmAsync(file); + } + + using (Image.Load(file, out IImageFormat mime)) + { + Assert.Equal("image/x-portable-pixmap", mime.DefaultMimeType); + } + } + + [Fact] + public void SaveAsPbm_Path_Encoder() + { + string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageExtensions)); + string file = Path.Combine(dir, "SaveAsPbm_Path_Encoder.pbm"); + + using (var image = new Image(10, 10)) + { + image.SaveAsPbm(file, new PbmEncoder()); + } + + using (Image.Load(file, out IImageFormat mime)) + { + Assert.Equal("image/x-portable-pixmap", mime.DefaultMimeType); + } + } + + [Fact] + public async Task SaveAsPbmAsync_Path_Encoder() + { + string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageExtensions)); + string file = Path.Combine(dir, "SaveAsPbmAsync_Path_Encoder.pbm"); + + using (var image = new Image(10, 10)) + { + await image.SaveAsPbmAsync(file, new PbmEncoder()); + } + + using (Image.Load(file, out IImageFormat mime)) + { + Assert.Equal("image/x-portable-pixmap", mime.DefaultMimeType); + } + } + + [Fact] + public void SaveAsPbm_Stream() + { + using var memoryStream = new MemoryStream(); + + using (var image = new Image(10, 10)) + { + image.SaveAsPbm(memoryStream); + } + + memoryStream.Position = 0; + + using (Image.Load(memoryStream, out IImageFormat mime)) + { + Assert.Equal("image/x-portable-pixmap", mime.DefaultMimeType); + } + } + + [Fact] + public async Task SaveAsPbmAsync_StreamAsync() + { + using var memoryStream = new MemoryStream(); + + using (var image = new Image(10, 10)) + { + await image.SaveAsPbmAsync(memoryStream); + } + + memoryStream.Position = 0; + + using (Image.Load(memoryStream, out IImageFormat mime)) + { + Assert.Equal("image/x-portable-pixmap", mime.DefaultMimeType); + } + } + + [Fact] + public void SaveAsPbm_Stream_Encoder() + { + using var memoryStream = new MemoryStream(); + + using (var image = new Image(10, 10)) + { + image.SaveAsPbm(memoryStream, new PbmEncoder()); + } + + memoryStream.Position = 0; + + using (Image.Load(memoryStream, out IImageFormat mime)) + { + Assert.Equal("image/x-portable-pixmap", mime.DefaultMimeType); + } + } + + [Fact] + public async Task SaveAsPbmAsync_Stream_Encoder() + { + using var memoryStream = new MemoryStream(); + + using (var image = new Image(10, 10)) + { + await image.SaveAsPbmAsync(memoryStream, new PbmEncoder()); + } + + memoryStream.Position = 0; + + using (Image.Load(memoryStream, out IImageFormat mime)) + { + Assert.Equal("image/x-portable-pixmap", mime.DefaultMimeType); + } + } + } +} diff --git a/tests/ImageSharp.Tests/Formats/Pbm/PbmDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Pbm/PbmDecoderTests.cs new file mode 100644 index 000000000..4ff359387 --- /dev/null +++ b/tests/ImageSharp.Tests/Formats/Pbm/PbmDecoderTests.cs @@ -0,0 +1,40 @@ +// Copyright (c) Six Labors. +// Licensed under the Apache License, Version 2.0. + +using System.IO; +using SixLabors.ImageSharp.Formats.Pbm; + +using Xunit; +using static SixLabors.ImageSharp.Tests.TestImages.Pbm; + +// ReSharper disable InconsistentNaming +namespace SixLabors.ImageSharp.Tests.Formats.Pbm +{ + [Trait("Format", "Pbm")] + public class PbmDecoderTests + { + [Theory] + [InlineData(BlackAndWhitePlain, PbmColorType.BlackAndWhite)] + [InlineData(BlackAndWhiteBinary, PbmColorType.BlackAndWhite)] + [InlineData(GrayscalePlain, PbmColorType.Grayscale)] + [InlineData(GrayscaleBinary, PbmColorType.Grayscale)] + [InlineData(GrayscaleBinaryWide, PbmColorType.Grayscale)] + [InlineData(RgbPlain, PbmColorType.Rgb)] + [InlineData(RgbBinary, PbmColorType.Rgb)] + public void PpmDecoder_CanDecode(string imagePath, PbmColorType expectedColorType) + { + // Arrange + var testFile = TestFile.Create(imagePath); + using var stream = new MemoryStream(testFile.Bytes, false); + + // Act + using var image = Image.Load(stream); + + // Assert + Assert.NotNull(image); + PbmMetadata bitmapMetadata = image.Metadata.GetPbmMetadata(); + Assert.NotNull(bitmapMetadata); + Assert.Equal(expectedColorType, bitmapMetadata.ColorType); + } + } +} diff --git a/tests/ImageSharp.Tests/Formats/Pbm/PbmEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Pbm/PbmEncoderTests.cs new file mode 100644 index 000000000..339cc4a5c --- /dev/null +++ b/tests/ImageSharp.Tests/Formats/Pbm/PbmEncoderTests.cs @@ -0,0 +1,144 @@ +// Copyright (c) Six Labors. +// Licensed under the Apache License, Version 2.0. + +using System.IO; +using SixLabors.ImageSharp.Formats.Pbm; +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Tests.Formats.Tga; + +using Xunit; +using static SixLabors.ImageSharp.Tests.TestImages.Pbm; + +// ReSharper disable InconsistentNaming +namespace SixLabors.ImageSharp.Tests.Formats.Pbm +{ + [Collection("RunSerial")] + [Trait("Format", "Pbm")] + public class PbmEncoderTests + { + public static readonly TheoryData ColorType = + new TheoryData + { + PbmColorType.BlackAndWhite, + PbmColorType.Grayscale, + PbmColorType.Rgb + }; + + public static readonly TheoryData PbmColorTypeFiles = + new TheoryData + { + { BlackAndWhiteBinary, PbmColorType.BlackAndWhite }, + { BlackAndWhitePlain, PbmColorType.BlackAndWhite }, + { GrayscaleBinary, PbmColorType.Grayscale }, + { GrayscaleBinaryWide, PbmColorType.Grayscale }, + { GrayscalePlain, PbmColorType.Grayscale }, + { RgbBinary, PbmColorType.Rgb }, + { RgbPlain, PbmColorType.Rgb }, + }; + + [Theory] + [MemberData(nameof(PbmColorTypeFiles))] + public void PbmEncoder_PreserveColorType(string imagePath, PbmColorType pbmColorType) + { + var options = new PbmEncoder(); + + var testFile = TestFile.Create(imagePath); + using (Image input = testFile.CreateRgba32Image()) + { + using (var memStream = new MemoryStream()) + { + input.Save(memStream, options); + memStream.Position = 0; + using (var output = Image.Load(memStream)) + { + PbmMetadata meta = output.Metadata.GetPbmMetadata(); + Assert.Equal(pbmColorType, meta.ColorType); + } + } + } + } + + [Theory] + [MemberData(nameof(PbmColorTypeFiles))] + public void PbmEncoder_WithPlainEncoding_PreserveBitsPerPixel(string imagePath, PbmColorType pbmColorType) + { + var options = new PbmEncoder() + { + Encoding = PbmEncoding.Plain + }; + + TestFile testFile = TestFile.Create(imagePath); + using (Image input = testFile.CreateRgba32Image()) + { + using (var memStream = new MemoryStream()) + { + input.Save(memStream, options); + memStream.Position = 0; + using (var output = Image.Load(memStream)) + { + PbmMetadata meta = output.Metadata.GetPbmMetadata(); + Assert.Equal(pbmColorType, meta.ColorType); + } + } + } + } + + [Theory] + [WithFile(BlackAndWhitePlain, PixelTypes.Rgb24)] + public void PbmEncoder_P1_Works(TestImageProvider provider) + where TPixel : unmanaged, IPixel => TestPbmEncoderCore(provider, PbmColorType.BlackAndWhite, PbmEncoding.Plain); + + [Theory] + [WithFile(BlackAndWhiteBinary, PixelTypes.Rgb24)] + public void PbmEncoder_P4_Works(TestImageProvider provider) + where TPixel : unmanaged, IPixel => TestPbmEncoderCore(provider, PbmColorType.BlackAndWhite, PbmEncoding.Binary); + + /* Disabled as Magick throws an error reading the input image + [Theory] + [WithFile(GrayscalePlain, PixelTypes.Rgb24)] + public void PbmEncoder_P2_Works(TestImageProvider provider) + where TPixel : unmanaged, IPixel => TestPbmEncoderCore(provider, PbmColorType.Grayscale, PbmEncoding.Plain); + */ + + [Theory] + [WithFile(GrayscaleBinary, PixelTypes.Rgb24)] + public void PbmEncoder_P5_Works(TestImageProvider provider) + where TPixel : unmanaged, IPixel => TestPbmEncoderCore(provider, PbmColorType.Grayscale, PbmEncoding.Binary); + + /* Disabled as Magick throws an error reading the input image + [Theory] + [WithFile(RgbPlain, PixelTypes.Rgb24)] + public void PbmEncoder_P3_Works(TestImageProvider provider) + where TPixel : unmanaged, IPixel => TestPbmEncoderCore(provider, PbmColorType.Rgb, PbmEncoding.Plain); + */ + + [Theory] + [WithFile(RgbBinary, PixelTypes.Rgb24)] + public void PbmEncoder_P6_Works(TestImageProvider provider) + where TPixel : unmanaged, IPixel => TestPbmEncoderCore(provider, PbmColorType.Rgb, PbmEncoding.Binary); + + private static void TestPbmEncoderCore( + TestImageProvider provider, + PbmColorType colorType, + PbmEncoding encoding, + bool useExactComparer = true, + float compareTolerance = 0.01f) + where TPixel : unmanaged, IPixel + { + using (Image image = provider.GetImage()) + { + var encoder = new PbmEncoder { ColorType = colorType, Encoding = encoding }; + + using (var memStream = new MemoryStream()) + { + image.Save(memStream, encoder); + memStream.Position = 0; + using (var encodedImage = (Image)Image.Load(memStream)) + { + TgaTestUtils.CompareWithReferenceDecoder(provider, encodedImage, useExactComparer, compareTolerance); + } + } + } + } + } +} diff --git a/tests/ImageSharp.Tests/Formats/Pbm/PbmMetadataTests.cs b/tests/ImageSharp.Tests/Formats/Pbm/PbmMetadataTests.cs new file mode 100644 index 000000000..00b4f443d --- /dev/null +++ b/tests/ImageSharp.Tests/Formats/Pbm/PbmMetadataTests.cs @@ -0,0 +1,84 @@ +// Copyright (c) Six Labors. +// Licensed under the Apache License, Version 2.0. + +using System.IO; +using SixLabors.ImageSharp.Formats.Pbm; + +using Xunit; +using static SixLabors.ImageSharp.Tests.TestImages.Pbm; + +// ReSharper disable InconsistentNaming +namespace SixLabors.ImageSharp.Tests.Formats.Pbm +{ + [Trait("Format", "Pbm")] + public class PbmMetadataTests + { + [Fact] + public void CloneIsDeep() + { + var meta = new PbmMetadata { ColorType = PbmColorType.Grayscale }; + var clone = (PbmMetadata)meta.DeepClone(); + + clone.ColorType = PbmColorType.Rgb; + + Assert.False(meta.ColorType.Equals(clone.ColorType)); + } + + [Theory] + [InlineData(BlackAndWhitePlain, PbmEncoding.Plain)] + [InlineData(BlackAndWhiteBinary, PbmEncoding.Binary)] + [InlineData(GrayscaleBinary, PbmEncoding.Binary)] + [InlineData(GrayscaleBinaryWide, PbmEncoding.Binary)] + [InlineData(GrayscalePlain, PbmEncoding.Plain)] + [InlineData(RgbBinary, PbmEncoding.Binary)] + [InlineData(RgbPlain, PbmEncoding.Plain)] + public void Identify_DetectsCorrectEncoding(string imagePath, PbmEncoding expectedEncoding) + { + var testFile = TestFile.Create(imagePath); + using var stream = new MemoryStream(testFile.Bytes, false); + IImageInfo imageInfo = Image.Identify(stream); + Assert.NotNull(imageInfo); + PbmMetadata bitmapMetadata = imageInfo.Metadata.GetPbmMetadata(); + Assert.NotNull(bitmapMetadata); + Assert.Equal(expectedEncoding, bitmapMetadata.Encoding); + } + + [Theory] + [InlineData(BlackAndWhitePlain, PbmColorType.BlackAndWhite)] + [InlineData(BlackAndWhiteBinary, PbmColorType.BlackAndWhite)] + [InlineData(GrayscaleBinary, PbmColorType.Grayscale)] + [InlineData(GrayscaleBinaryWide, PbmColorType.Grayscale)] + [InlineData(GrayscalePlain, PbmColorType.Grayscale)] + [InlineData(RgbBinary, PbmColorType.Rgb)] + [InlineData(RgbPlain, PbmColorType.Rgb)] + public void Identify_DetectsCorrectColorType(string imagePath, PbmColorType expectedColorType) + { + var testFile = TestFile.Create(imagePath); + using var stream = new MemoryStream(testFile.Bytes, false); + IImageInfo imageInfo = Image.Identify(stream); + Assert.NotNull(imageInfo); + PbmMetadata bitmapMetadata = imageInfo.Metadata.GetPbmMetadata(); + Assert.NotNull(bitmapMetadata); + Assert.Equal(expectedColorType, bitmapMetadata.ColorType); + } + + [Theory] + [InlineData(BlackAndWhitePlain, 1)] + [InlineData(BlackAndWhiteBinary, 1)] + [InlineData(GrayscaleBinary, 255)] + [InlineData(GrayscaleBinaryWide, 65535)] + [InlineData(GrayscalePlain, 15)] + [InlineData(RgbBinary, 255)] + [InlineData(RgbPlain, 15)] + public void Identify_DetectsCorrectMaxPixelValue(string imagePath, int expectedMaxPixelValue) + { + var testFile = TestFile.Create(imagePath); + using var stream = new MemoryStream(testFile.Bytes, false); + IImageInfo imageInfo = Image.Identify(stream); + Assert.NotNull(imageInfo); + PbmMetadata bitmapMetadata = imageInfo.Metadata.GetPbmMetadata(); + Assert.NotNull(bitmapMetadata); + Assert.Equal(expectedMaxPixelValue, bitmapMetadata.MaxPixelValue); + } + } +} diff --git a/tests/ImageSharp.Tests/Formats/Pbm/PbmTestUtils.cs b/tests/ImageSharp.Tests/Formats/Pbm/PbmTestUtils.cs new file mode 100644 index 000000000..7b701fe3d --- /dev/null +++ b/tests/ImageSharp.Tests/Formats/Pbm/PbmTestUtils.cs @@ -0,0 +1,65 @@ +// Copyright (c) Six Labors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.IO; +using ImageMagick; +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Formats.Pbm +{ + public static class PbmTestUtils + { + public static void CompareWithReferenceDecoder( + TestImageProvider provider, + Image image, + bool useExactComparer = true, + float compareTolerance = 0.01f) + where TPixel : unmanaged, ImageSharp.PixelFormats.IPixel + { + string path = TestImageProvider.GetFilePathOrNull(provider); + if (path == null) + { + throw new InvalidOperationException("CompareToOriginal() works only with file providers!"); + } + + var testFile = TestFile.Create(path); + Image magickImage = DecodeWithMagick(Configuration.Default, new FileInfo(testFile.FullPath)); + if (useExactComparer) + { + ImageComparer.Exact.VerifySimilarity(magickImage, image); + } + else + { + ImageComparer.Tolerant(compareTolerance).VerifySimilarity(magickImage, image); + } + } + + public static Image DecodeWithMagick(Configuration configuration, FileInfo fileInfo) + where TPixel : unmanaged, ImageSharp.PixelFormats.IPixel + { + using (var magickImage = new MagickImage(fileInfo)) + { + magickImage.AutoOrient(); + var result = new Image(configuration, magickImage.Width, magickImage.Height); + + Assert.True(result.TryGetSinglePixelSpan(out Span resultPixels)); + + using (IUnsafePixelCollection pixels = magickImage.GetPixelsUnsafe()) + { + byte[] data = pixels.ToByteArray(PixelMapping.RGBA); + + PixelOperations.Instance.FromRgba32Bytes( + configuration, + data, + resultPixels, + resultPixels.Length); + } + + return result; + } + } + } +} diff --git a/tests/ImageSharp.Tests/Formats/Pbm/RoundTripTests.cs b/tests/ImageSharp.Tests/Formats/Pbm/RoundTripTests.cs new file mode 100644 index 000000000..391e8c054 --- /dev/null +++ b/tests/ImageSharp.Tests/Formats/Pbm/RoundTripTests.cs @@ -0,0 +1,44 @@ +// Copyright (c) Six Labors. +// Licensed under the Apache License, Version 2.0. + +using System.IO; +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison; +using Xunit; +using static SixLabors.ImageSharp.Tests.TestImages.Pbm; + +// ReSharper disable InconsistentNaming +namespace SixLabors.ImageSharp.Tests.Formats.Pbm +{ + [Trait("Format", "Pbm")] + public class RoundTripTests + { + [Theory] + [InlineData(RgbPlain)] + [InlineData(RgbBinary)] + public void PbmColorImageCanRoundTrip(string imagePath) + { + // Arrange + var testFile = TestFile.Create(imagePath); + using var stream = new MemoryStream(testFile.Bytes, false); + + // Act + using var originalImage = Image.Load(stream); + using Image encodedImage = this.RoundTrip(originalImage); + + // Assert + Assert.NotNull(encodedImage); + ImageComparer.Exact.VerifySimilarity(originalImage, encodedImage); + } + + private Image RoundTrip(Image originalImage) + where TPixel : unmanaged, IPixel + { + using var decodedStream = new MemoryStream(); + originalImage.SaveAsPbm(decodedStream); + decodedStream.Seek(0, SeekOrigin.Begin); + var encodedImage = (Image)Image.Load(decodedStream); + return encodedImage; + } + } +} diff --git a/tests/ImageSharp.Tests/Image/ImageTests.SaveAsync.cs b/tests/ImageSharp.Tests/Image/ImageTests.SaveAsync.cs index 8bb121349..f21f2c916 100644 --- a/tests/ImageSharp.Tests/Image/ImageTests.SaveAsync.cs +++ b/tests/ImageSharp.Tests/Image/ImageTests.SaveAsync.cs @@ -71,6 +71,7 @@ namespace SixLabors.ImageSharp.Tests } [Theory] + [InlineData("test.pbm", "image/x-portable-pixmap")] [InlineData("test.png", "image/png")] [InlineData("test.tga", "image/tga")] [InlineData("test.bmp", "image/bmp")] @@ -114,6 +115,7 @@ namespace SixLabors.ImageSharp.Tests } [Theory] + [InlineData("test.pbm")] [InlineData("test.png")] [InlineData("test.tga")] [InlineData("test.bmp")] diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index e00364913..67f947ff5 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -866,5 +866,16 @@ namespace SixLabors.ImageSharp.Tests public static readonly string[] Metadata = { SampleMetadata }; } + + public static class Pbm + { + public const string BlackAndWhitePlain = "Pbm/blackandwhite_plain.pbm"; + public const string BlackAndWhiteBinary = "Pbm/blackandwhite_binary.pbm"; + public const string GrayscaleBinary = "Pbm/rings.pgm"; + public const string GrayscaleBinaryWide = "Pbm/Gene-UP WebSocket RunImageMask.pgm"; + public const string GrayscalePlain = "Pbm/grayscale_plain.pgm"; + public const string RgbBinary = "Pbm/00000_00000.ppm"; + public const string RgbPlain = "Pbm/rgb_plain.ppm"; + } } } diff --git a/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.Formats.cs b/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.Formats.cs index 4b374b21f..fe512f9dc 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.Formats.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.Formats.cs @@ -7,6 +7,7 @@ using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.Formats.Bmp; using SixLabors.ImageSharp.Formats.Gif; using SixLabors.ImageSharp.Formats.Jpeg; +using SixLabors.ImageSharp.Formats.Pbm; using SixLabors.ImageSharp.Formats.Png; using SixLabors.ImageSharp.Formats.Tga; using SixLabors.ImageSharp.Formats.Tiff; @@ -57,6 +58,7 @@ namespace SixLabors.ImageSharp.Tests var cfg = new Configuration( new JpegConfigurationModule(), new GifConfigurationModule(), + new PbmConfigurationModule(), new TgaConfigurationModule(), new WebpConfigurationModule(), new TiffConfigurationModule()); diff --git a/tests/Images/Input/Pbm/00000_00000.ppm b/tests/Images/Input/Pbm/00000_00000.ppm new file mode 100644 index 000000000..321188762 --- /dev/null +++ b/tests/Images/Input/Pbm/00000_00000.ppm @@ -0,0 +1,4 @@ +P6 +29 30 +255 +KNPJLNVWTl^UtrnryysɻܫmpCARVbmY[aKOPDKKAEDBCBSTVPPRZYTk_{YQUZϧ~ѰɊʇR?NQ[ug\kTQVIMNLNKPPNNNPVUV]Z[xzkfD6ڹŕyݩbkbhberZ[^SSHJHIJENNJJKM[SSn\duQP[G㾵ؐFOL9oc}`ZKHBIJCIOJGJG`QHb`swIHrkϸدңΘˎy^mJH6"RHnnULJIKHP]\EJBxfTuaXA@Y_Ӂtujk``XVPNLJHED@A=?;>:y=9m=8x>7?1S=LDfkSPRJJJiknempmlB6A=@DAECGEJHOHNHNKNOOUW[_clky]`rkrlsorjqf}KHw_cHJJLIFh__{lmgrtw{}ɉ؎䐟쟵Ս|lalVPcQOZML_KJeJKTGKEEDJHBPLJo|xeq_kxbo}tttt``LLMPOTdkyiqgo```YYPWWRXVTRNNIFHIGGHGDJJHȻіoq\fJ\|f_ryXt]S^J;A9HGONIHCwvޮڳًaCBC}Pqe_nTSQOSQSURLLHNMGZWRţ~|kMWWJ[|T^xla~LVldŎ˱խýzy}сMQPZyhl]WW\a`Y[YPOLVSO[VQǎwWJJ:z`deuPOMRԝmwPmǟ}hڝYaG:qkvabkpp^a_QRPSSQ\[VaVUGvmslt@>gk٣ƺvWp^kf©zo|?9UTkmbhhY]\RUTRTT`b`r^daTwut@<ʁȾǕy˶nvճ۠@AWYmq]abX[ZUXXSUVZ\\|sqvpm}~|~x~}@<̔vq~~wǭƘ}AAZ[orX[[WZVUXTTWS[^Zlrthjndciffnhjfw}sD@pv󚗳lurxѵϑ?>^_jmVVTYZSVYQZ]T^aXlgHHX[él[[}Ĉuk۽ʺkl>4RNfg[YWZZUZ]W]`Y^aZĭëcgAAtq֨t~wjµļEOS?yor]\_\Z[[XWYUZ[V]]X­nvkxqyYOF8ɉt̰⡰_gckhplfjYTU^Z[a`bUWWUURXUQlvSk]n^q][BE*ʆhcK]cyX|YThTRV^^cWX_SUXOQPSUR|Y}}db|gI`Oj{Jm^OS?fOy_\K@7RTdrkhӇ裷Ähk]hkSeTOYPPSZ^bNQWLORHMNIQOU?OduOlKp`J_Fsw]d`lNRMI}MFQGVNoisjzcVWOKLRRT[_cMOUSTXJNQNUToĮX^:DO4mNveFlNNrUYx]b|l|jdhaztz~lkz[Y`NKPOORTXZLNOOOOMPPNTRLyWgnUW]M\|je^c}]h~bngmuy}}}{|wljy\[iMLUJJOPRRQRNRRNRSOQTPo|qkshjkdz}y}yziprnnhuoqup{okvjiuRS[FFJJJJOOKMNJNNI[[Wzpy|suvvruoothmrdkq`inbhmcgfekcKTKdla}[cinmasmugcm]Z`JHKKIIUTP^^Yab[cgc[_c[bgJUYDHKMJLTLM^QU]W^Z[`__bXVXJMNIRQLUQXaipmfumphah]V[PKOLHH]ZWge_nqh`hbUTW_ek=JOAGLEDESOMc[^ZW`RSXZZ\cbhQR]LPVNTVT_jfkhnnmb^ce^cWRWIGHQPMff_cfZZaY \ No newline at end of file diff --git a/tests/Images/Input/Pbm/Gene-UP WebSocket RunImageMask.pgm b/tests/Images/Input/Pbm/Gene-UP WebSocket RunImageMask.pgm new file mode 100644 index 0000000000000000000000000000000000000000..8265eaa50621a9a5455776fbe2c5faeb5933b862 GIT binary patch literal 614417 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 UfB_6(00S7n00uCCfxLnL0M1c2-v9sr literal 0 HcmV?d00001 diff --git a/tests/Images/Input/Pbm/blackandwhite_binary.pbm b/tests/Images/Input/Pbm/blackandwhite_binary.pbm new file mode 100644 index 000000000..a25b1d350 --- /dev/null +++ b/tests/Images/Input/Pbm/blackandwhite_binary.pbm @@ -0,0 +1,3 @@ +P4 +# CREATOR: bitmap2pbm Version 1.0.0 +8 4 @0@0 diff --git a/tests/Images/Input/Pbm/blackandwhite_plain.pbm b/tests/Images/Input/Pbm/blackandwhite_plain.pbm new file mode 100644 index 000000000..fea8cafd0 --- /dev/null +++ b/tests/Images/Input/Pbm/blackandwhite_plain.pbm @@ -0,0 +1,10 @@ +P1 +# PBM example +24 7 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 1 1 1 1 0 0 1 1 1 1 0 0 1 1 1 1 0 0 1 1 1 1 0 +0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 1 0 +0 1 1 1 0 0 0 1 1 1 0 0 0 1 1 1 0 0 0 1 1 1 1 0 +0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 +0 1 0 0 0 0 0 1 1 1 1 0 0 1 1 1 1 0 0 1 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 \ No newline at end of file diff --git a/tests/Images/Input/Pbm/grayscale_plain.pgm b/tests/Images/Input/Pbm/grayscale_plain.pgm new file mode 100644 index 000000000..ba4757248 --- /dev/null +++ b/tests/Images/Input/Pbm/grayscale_plain.pgm @@ -0,0 +1,10 @@ +P2 +24 7 +15 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 3 3 3 3 0 0 7 7 7 7 0 0 11 11 11 11 0 0 15 15 15 15 0 +0 3 0 0 0 0 0 7 0 0 0 0 0 11 0 0 0 0 0 15 0 0 15 0 +0 3 3 3 0 0 0 7 7 7 0 0 0 11 11 11 0 0 0 15 15 15 15 0 +0 3 0 0 0 0 0 7 0 0 0 0 0 11 0 0 0 0 0 15 0 0 0 0 +0 3 0 0 0 0 0 7 7 7 7 0 0 11 11 11 11 0 0 15 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 \ No newline at end of file diff --git a/tests/Images/Input/Pbm/rgb_plain.ppm b/tests/Images/Input/Pbm/rgb_plain.ppm new file mode 100644 index 000000000..ecd1b915c --- /dev/null +++ b/tests/Images/Input/Pbm/rgb_plain.ppm @@ -0,0 +1,8 @@ +P3 +# example from the man page +4 4 +15 + 0 0 0 0 0 0 0 0 0 15 0 15 + 0 0 0 0 15 7 0 0 0 0 0 0 + 0 0 0 0 0 0 0 15 7 0 0 0 +15 0 15 0 0 0 0 0 0 0 0 0 \ No newline at end of file diff --git a/tests/Images/Input/Pbm/rings.pgm b/tests/Images/Input/Pbm/rings.pgm new file mode 100644 index 0000000000000000000000000000000000000000..e0d4b4ed4d4cfc4da44b131a68f60824957428b6 GIT binary patch literal 40038 zcmZ_02{=^!|Nno^nbnMK#@b{j6(QM)P>9@ADBUD2QWBMt3T;Y@O55E+w~8bcMbwR? zP+3AMV+oTrgE0%Uo;l}#bl>;q^ZovRzu#P!>!RkGIZfyNem`H&=i_O$9mUvS`M#*l z`=hoQY&m4$yKnpExOF?D4pNpZUTlDUQI^=*QHD-v3ZsoAQM%J9ihWOkhof@?tv`T)BrgKl;umW(eMjJy2bB^>O4bd8q&Dkzw@_CdA zj${#a@9Q)w?5()EdzBSK5f1_oflO6YQlydz5CGy88CI)yU#;jBqSIgRMOlz=CQ;8P zk*>2gkVbR^(syJIA*2zlb_Z58$nWXUuF0!RRqvwL$sWURd)*BJicrU6|~&mYD~%|#CSSm-MRrNqs0_(eaA30i3D?l0Kq7huNJF-gs|R$wWXZ&aMnVR6?lzfuh}>+G zSX)yZZi)EWBWuj0duW3NK>nD%m+TC9SGZiGdC*d~Wza_C32F$ib&P~PkX1oiRaAg^9_ zFn9zmRB|0{(X||G)>tmQ3!agA>5t_D1%tFbQnNLPy&qy3E*5UGM7&(l6^_UT1O7R} zhZcoB$U1ua7mXD&kBA$k`D8y%^Sn7PWhpq%F8&_8-8k`9L_wH`stUu0UPA5X()`W{8(Ny3_;pvy|>t>3ZAo%G{%gcfU6YHz%1vN}lIF36bHK zM|}-QfP$V&*pXW$A3BF71tN)5CY6W;lS7>!N^TtqbJ0@(NCv(~Uk)R}Pv<<9AhV=q zc=Db*UULr$}C*b;(g(@>kwCox|NIGj#!|6<#!sjuh>*Q~=eSW3t|lNKhH4x8cRz zi>Z5eY~C2Qar2J7sTc3QXz1n0P|3*qtQcoCP{DF%(Fi(T6s`p>NM)kkhjnn?ujE}( zWZmoH?)9K&oA@}%u624lutQX-Y1#AL%%G#&z-F=pe*jsh-uDXpgEMy{;^dBcJEN|C za!H6iy3`wWaYt9r7ak+Gz9$}r{k6KAR0AY;anW!#Ay`nWr(YvZ0R35$+ab3`ILCk- z`$KZi0&p%6a&wmA=;7r8S!iTK@21;`>(eG2#5xsJjd5y%e<%i84o4c%UxJ(Un%RcvaRj z;1>638eZH^*|=1n0uc3lQp$$p zqLz&1%Fu$uMwpZ9iPwnhKSZh6rp3MkmJDdGmM7z$aGi9%bH zWZ9^dN#lS>-d7jG5#hI$!0HZZwjnX%EArYOubuD>?Mbr$)z%e^qU;xYY^Z>$?Y8SR z140z$|7fYmzji7qE_&;ht^B!wEW=1sBoa>`ZiltfNHbn1sfeLSf>VBr1hZR z614IDuaU12M8j-p$7*2ZH{lV2%U50`5GO5Dvtf0b&g=fB2mEX}_)b?83C9ZCS+;%1EoeK# zX=A`LgN1&-=t3qe-d{0+@*1v1SgC?Ix|vVZ$v6ys_&hwpJg$N-Z$D-Z&fW7F?cA$I zj%Y{99RdF~*-cH&JID)tjY1@Y;LH9zPrqfvmhrjQ&~EB6bVBB3IPoV?&Lp4aYQ+oZ z?&Z@mo)QMnsc?>|vM&+8l>@my8EcU^^1FUL7hW+jTy~ETGW}Y6!6#k>5XJ5C0=JEg z#}Q5QU}hv~&hZgh*(#z+ScOPfwbKw(^*Y})jUCe$f48DRprV0e(C$;WpH$R;YVTln zw129vcyjyH?jT14MG&G{{eBTU_@|rBd#QqkJFA4EiZB)8sxsNg@j0YOCY)zVj2j=@ z26}aIqkstBrv=)tr$Y$$WZ}eOo{L`pJ8~Sdmhm$eDE~&h#8y4VQ8_nA02&Jj{eO^I zcW|whK<{ABK8SQO8l@OO@)zzR4t@tBG0sp>ZUhB*mVH= z(KO&99IV>ft`dpCb;jy~R^(F+oX;d*AW!-Qm zQ3IcgcsaI!)m_oZ0VT}~!td(Fsy*P;{f# z&p)C1TJTvb`1}LVFiOmC0bjibO4{*PCm6q@>$C@6;*KEU)Hgq^^}qI8GU|D2ac7VM zHIvuy1x1r$^yOk)SSS2w3E=!#JaKI?sJE{P=9Wb20;hhflkZ()!RFD?AW#Hjw4^@Gpa=~K*Ut{a%dN4C<3yt zMBjJ-wvVKvrwl>+n{4@~L{pF+aJvTSnf_ToycmyrS{?;~!15yL&V1L&Y>;wL%#rafqQYE=5j7Vvn3R@y@mL!4dE^6se! zAVyTpnEz$OQN5OJr_UxE#4Vhn6Ag-Gn!}EgU3B#oFxjCViFjE`cWLtutMm8h%j8~|dS3@yV2aCD7N_$4C6pm{H5z`c5Fx(^ zB%$ZQD9H;o^H%;AAe=oI0t9r5FKVcyOz<-ealWtM(TkRV&hC1NuqI& zwu0nf8wLde@KiM&lSS5c_IB2bOmx(!cmSd>Y=V;u+AuZQnHOb7AS_C#5lZTJ>j0J) zN8wk#IKxc-M2d>WMR8{U5HiRP2e$BA&DCB=qQLWL5^zx-q40Xx$W@#Hz5K2cC$q)W ztp&Ueo1nZ7>B`nwBmOq>-wmfvklWwlPD@-(ewGnp(Ienxc`SGqJ&y~SYO_+pG@Fjv zE&2PU;My@Es^*|m?=yd2qzvNKE&O(--+$HEImn(8 zOwUXUrr3j>jj!&f@AR`!$Aij?e$RYAg>tG7*$|12=ep3r%q5`V@j>{7JFvJ={$(w= z^u7F+nhvH-m8{yPLU8BNvtX?JGI#`yC6xU%ah06Ly=^C-m^S=fZsU(wuaoKG2hPxW z2ekOfDkE9YyH?T>nTOF&Oyi@waSz174|y?XQYl6cYG%iP$+l`v7r7MGYgHRnh5%O+RG_xAo38Z0OPry+45d z%==A|xIB+1dg2b6T;WfiR98958{P)FG)s;XojW+8V6r?{!I%4n=E*A|Z9@;@%Z7FQ zkr>tf$G~4LxZG}hUOQMlPQLpEENKFtFo_qY^n%fF^}g4H1L$UQ#f1Ib); zguF=8;HCVkivA>dcGZrg#3*!MEQ%k74slH0MGNmSTTc*uW&3Ivih zOdVH+?@Bsx_QItLXHO*U3SZ@DszC-Jl?DEX3Oj`8WX&-*CD3sDOM&ctECaN=Jtcf# z2RIbVzl1<`Rp=vqm8s-aH+6x?d;&I= zfM4#CEw&0ZQYTf9a_K9Yv_X0gM7wf+1g z1>;=!>ju1GCU^QzTfiu_3uR@xkVp>4K1?ISrAhAEI7rPZC@HI=eV8vnP!xf&ISQWr zM#3L%ugFRYvQmR^+U`lE!^rf9V-6&eOC}5LN;Lv(|D5J#8say6g>#J+lKA~=fiO19 z8=r>cD=r=WYGTsaZDci8Mc#(SDm1iH_rWf9@D6S6QPs&*4dK@L$nq74O~CA+8)C@2 zhG`C%One;Mp6on$(v~y`eh}F)h`e!>Ks$ zzR9hi*B8k}b^0mZ#4!zp&24B~j5^*edkpC~>qN$z?7NrqCR{}-f@OQiMkD39E zGlRtY9k{%1(ghA991YNCKLjp|J?D0}YA)keD0@yc8W?^MYyx&pe|E+v3cd#e?)7My zBjEM|W*uhWmgP>#YIo@a+My2ykm<%tLB=FN*(~tjo$AhU(X12^3Amg|4p$(W6)B?e z&gwe{1I?5Hl5x^$ zW{IRF!&eJbSQwg7$r57rRd;RS)zsMV)jl4sOIvGyxr0G->%mHu$S2dtDevo1M2weTU3c>Y{ALz(~4LYEr{obd&5`_D; z=yasJsTz59Nhm0(($(myN(!@!g{)@k9(lUxD;JUUKHY1t2nR5k!6Lq71QB-?9`rGy05}yRr!_lLF6BIaQCa<_ zy7I;2oJ%P?);Jld-~ft|&%wejF)~sTZ$ThAocfB4=Xen4(Jg5EHmX`On}0@~eqP+M z5{MjU`9eozFEq@*jkwUNxSsTn112`y0`R=p(NdUBXsHGtcM`I{@Ckj; zF>4%dOfUh}*4*ipi`s64Eu;Vxla=w;U$&1-!zc<%gaRIqClE?zf0!O=e|bHAr3v<& zg<&_^MDpG{Yt%rKghqHg%MsK+F)V%JFuNII|K(u=+&G*&le-y+7S`y@`#kDGe>>sG z==iGXD?JMqk1()n)#sn0u(Am~S>(~9i!gH(u?&{mc%y;yrql8DUzDQI?Fw&(7nlz< zYT1u`HrD^h-vAzv)S4+~!gY4Is3E~=b)|$sX`vHfdUgnDiq``SVk-Ia-kdOF%mwi| zRM^ge5#dOCRsQ9p@mn{n4g4)|?S`%KM=$4BwT}o9nA2W($Om&)jKgwz<^0MR13)jn z2^l(T3OE%?2NRUkPYZ^kaCUWYrlMJ`M7J#8 z3UDowurFHz28k_lPEq(=fbMhdBM;@Z-i=>wNChD(!@?tY`+*Y~S8v?BaW&(_f$hN_ z77Qu`QVo~K-)+U7`SF|&9he(l#F4io8UU7;*^(kxz$#zX9f7mJ-p7=BPF6FYmWQ0j z2Tpy|G4Ev>T8_L^43($iUJNnTq8qi@f8blofZ9r+xsc%D56{~!(u(+H2JC*WfQ=L)ns+nFQR@Ptr^^_46~sdll7^24rQv1hwt&VNStn zRnTNd$ryHNnd=r%0J5HIA z1XNvJz=7XyS0nhA$p(_t6!#9#oL5)Nlzv)@OPFa{f{mgV@oV@s8umXws4bt)hmw&H zwVrC+x#)EGE4TP{^Y?KPg3Peq-i%qQ2@y;-WHDu;hLpuP<+Viu(Q`k7 zW@0~#3F+mvXvreNUM_15uw{zrsBjA#_BqD)G zQczOYUFaORGyUO*LG17QN>jbHL5f{cjR5|VW(}!DzJ-5gn1XK4;qI+Oqa3)^3kV&Y z*bJ;6?{QJcMoxm!m?yXiz6zwtLsi;Z6=RT9M!XE-m(tlwfAxm3-jo#EHT8>Oub@n){esP zVCew|DrmU1WJ=ziG9McNdXe{`B&}m?!3Axl6yD%Q(7Tf#3$7jOaa7Ec9{`SEacwFZ zhcDt-TJf`if>Esq#B&K8X(--qBnx)9tH4gtoKDc3K##uc_J_X?nFHVXcx#KiS@}eOw=o9kX3b%P^Y7gGIRk#;iJI-7}E0Ju5uE}@e?u)!NJ3c9GK_k?# z$f>Z8dV;5wFs+%wR#46C#TB-KPreeak7-09-X>Ey!0j1l16Bjgd%A?`%dKV1Z<$&T z?iDrJkdBHv`~jb4K`0kZ%qgBdj9FPTy*p)X5cZlR*40VeFz$RyOByS(E2IT z>;w3Bh>ntMnnZiS^;0eL8MRzrYRR-Wt$}6WJaZe!nKJQ4qBO>?6TUtHTMKc$nWl)B zCu--9x?q}1pPLE2?xuyK@x+&GE0ey@I#w*E8KY)q3lJ-8TC9*RZE^*}`-PY0P-1%F z5)a7WSRdM+WCAd@U}MB!!M24YP;1$qdrf0fR5IRGS9JSKQtXzn_3PG$ZHY}fbGxXn zYg~d#$C~c#S*8V&7H%sT#0Hlw48SC*9ql`20C|+ay)l$ImxTS{plg#fU14#PFc#P{ zQ^PQ0vaEDI_nBC+UlQZda9a0kD3hy?XYNNd=d2!X7C{9Gv-heC&qWV zyc|xTcD(?eeIwjvk+Qm=GPzM4pMHFjc4S&V4DnhxeE}*T)bWyB1jM zZp}oeGbtT@XGKcl4{pJm6~J9l6t#pNb&p!weHM~82^;^|vIB0ULe zl&CJazzn}-ke@`ddIzVIoI5Ah;Lf3$xJYR(eyjW(a8=@^GguB?m|p0Ggy~Nop-mpA z^W%)JDf9N|iMQ(u570*MfK^PzUDz?hY*tw-`vXkG%=$R^0d*;B&>MeLT4zO0o#_by zonNE1KA?G)fR}9t>S3cbJ1>w1>PI~2howD*`#p7t0GVO4IyOD0w6?8_H8lEjbcof} zR$H2r9=qCxK?aCAp8E@Xq;UU(2z`(in8(J3d_B-En)#`N__ywVG%|m_=jw*N;4BXsCOwctH3*>v;#u@?P9$>JZ0LYK73&t^!OX$8e4N4 z;$y3l4u7%=0u#qnse2|GKAk#m33s}ip7Q+%47l#2jOr8 zva*KZ;uRZ@WL5R>5!rC{xitnjqIql?2l<}qLQo2MDdF72lA(ObKs<$URnoZz_^pS( z8}uI<^de-UmvCX?rwYN694HChMtR>!i$K>g#&6;ptAVn{SwYhB%Wq%*zy0>5M#EJK zoBrdsm#QslWI zZ1>Cev0p4qBeqomPdo5AzkHt+zVi87#RgGQvjEiJRB!=T*{iWueiX``@uJs{IjL6* zf-%9Hqh!@A#C(`0*;Nhtndy=J%CrM4_?17AzO_y^RTxAEjiQQ2Q9R=1T-^nV4j4$zeM zk4>Yh0BzVLp?v*-9w~le@u!YIUcvdb-z4E_77BR-?BPcR^t4j|P}YqYT7b=gWP8 zriX<7>*OEV__hilZ&))7-K6rRMP)W`KZPcMXVBAN#7wP`_H*PC)$BF$Cqw1*^l%(S z>m*y4YX{6b#X`TOnt}8+cYh%K`qL|C^V(&*ZoK}^g|WPLob|1#_Vr({{(4>8^o=!+ z<+U*P`|BIKmd)n1D^J(+kso*0&_T1*Zz${3Jisnj$Udn>i5s3it-|;dd2L3$ggnD6CO6XBW9b$y0Id|jdCYPI9{pq z4L(I4sQ%@vwi~aEx{6<=Zrwe+oOl6wI%iG+T4YQ~;f=&8FfzEjE2f~+J)XFHy((_W z$u^m&F@1$PK(*L-xn@v|O2<2@^DiEXUhlu$)ydJxb-Dlg=tCFtt2@S}sCcmE@XS}7_pgaZtrc)^%c65?&G!(_^iZ`1f)up)ZTjU=%h|D4k5TG1@JxnGF!ISb0)T#+b ztp>K6Qju&guvPHMnvwz6E+NEEjPIu~E(s>mb@6`X((zkPI9h1&6w-6!H%&mCO1bjS$)<7(iHl?CZhY~i#bW+#;L(U?B;tWlN*J?i3U)X744Et4cbZW#Boi9O)co>SPh(O z)=z|a&V`IOizynEOTHH;`_IFCY9)O;|E)>qZ|6TNuc)jjf0lpye9~5bJAEb0r=I7Z zT>M=kA1sP7!;@XkF_E8Ht~ia@&uGgg1mRqbvoLrHJIqbW@qcKBw@f9Fb zwqD_dz>oSw8Vw}D&$SFI;jQdmjLw(!F4RpvAZQg@2Y?~=kj*+H6s?)ECt zOz9d0rHBUf%N7OgbRPQv#V{YKG^d<}D-E@t!%0B2^a<5Z@Iqm|EEBjQb~hY*1l(oM zi9lSPkhK=_)%K_(;qgbH?iEn~8hFMe9~W6UOHblnjGEYSpAk31H=u3OLPghsemBxZ zq(o0G3#qZiZD9$o=#n;lLF?9$RW{eb6ZcnA@z%-jXXLEHT{g;qg0XKx)|(!V6q}o- zCx-jGnH|jT{^5yfY_5`WdfsFu_!=t!$~L4wecBzfz0gp#@eBqPegXv{jZ7egx_F*TLB3U9BI@#@kOAvGi0)B09t|@+f z3tAUMRF7@L5HM`N3A{Imaw-lwVXDb8{6aXl=3T#GpE~Wj)?B7jE+d0=oqXIFIhhP%u$e zq~bK(ZfM48(^@wD06Yo%>Wn@H@+0k|Sf}Kbg3K4*cz5)x9!%Tk$E} zt3f??;h*3k^f0#2PXIe5Wtyh%MSG!@J-mGct5@hNJJ7ElZCFRt*w=w}95Dg(VqQ&#;0aUB4w;RXh2(RbOy|kTcmn}BY(WI-YsM0lcOcpO&yEEblDn~v?kk$8fqHXaEa1q9l@&1a#=mgX7TeBS5z}xJ^AbW%V z3rA*PAC#E=c3_qxyA^JV5fE{I@i2~T5y*&dLp%4WlOsMO2}0vwbd?G38dyAP z=q9=ioIql57&D6j4VMXiKYQH?$D|+a2zxoBJBjn|N&8}zRAM{OmKY73!(|pal(SkL z(C|H5&q0OV&(lI}=a4~=MAI{K@bFs`vMywepNE5)9*qQoFy+8d3moc0HV~KGw$O+)K$jxxH z7`(rue7nAH zYWXbRejel77anYaC+~aUHR3zax;3+WJL|uE`(sU`w}12Pgx@8(fAj79C6@e~vwZs= zsiiOK`8VILae9z=kBQ6eA!TsphM|Fa>;fQDyqwY1rs+0Ssp2u-WMJ@K5DDxMv^(Pu z2zo<+WpyZa3%i!WtRoDZ+kH%{#u@-x>+^nKz+q;v2?gVd9YW8NbUo`!lel_pc^oHQyc53J~*?vwlK3|0_h z(F0JnES!)7#{-FQk=p$C;v}4Fn>bxb=Z@^#dYoz2%tVF>=#V`rdl$_B45G_9=*Y7; zTO~lzEac?V&uj@QpJDg5zI$2pF!z4$!=jh(T6@_ua#X_p{PbjqnIfQM8~1Dk<&;Mo z0F3B&vdL@*&?IAGCd(AJ{+sNMj#9d~%@vmSK;scuk)aFkV3MJCYZFXC?dUpq?D8UD$$in! zWSVN~)Yxu<)obLYs!5eB1zO8#nWxt{?nPASHyS=g-=bGxoPf$23Wx13*fc( z=vfy2Ni$g92o`*&921(m!-=H&E{)%?^FJNg1^s~}V2pf$vUNLeD-bfw#weV6q|gi( z`WdOhT(e^=qzOY@79=%F#f@ppQ~;XGzJhOjRK{*Axq2XMh0Q#MnlhE5K%pwDG3ME< z2s?1Kq>U{@`QHlmxzGTWWoeCKX=Bm?47O=PSjRADuL}7biZd%j>M^p2JsbjT<+WQY z7hqk11mq8B7m|+YrQbBV>Pd;PySeZf<$D3xSPnKn!Lz!qDorJ62@=&NE)v_Tz#Cjs zH_16LPvD}%?9jLT@zunjiL)A)CV$RgJVo;u^h{|-5V!=R(6>`nW7^S5`pGHoIbD3m2;f5n@1efDrdq$Y}TKnTZ-JI={!JcoWM10NT~~8 zeQ%nV;{<6%*Ggw9V@x1L=j19jBI+(mU2RUo0Ytj7olj`={*<({=gy|3?2iuhu`{L< z0UXVIb!t(!2w_(xJ1asaF_kmY+Gs7vDTgG@hnBdX>;#0p_rE1CRt_ z^?;$nR4F-B@_@94|8}lP12&XJa=!b5n?^VZWTU&Xo^52!A6`GUBhXG4^HS7oHeG!`iSj?D zdnkh@yKBV4^7TsO)qlZ*$(rPCJ+iw-(E;7`Sds$-??LBb;gR zuRe}=nlpm+ak5f2x*GiI<0Q}aaau2|_@|GP=ZRO3`-Z*``lpYxs0@9gPrHRYo$cf7 z!1kIuSRdyB*2g&p-sjsa;@t*{S*mfe#XjhAXVh~!Vr~-8RXI08$zap=i_N`|DAk^7 z!XYG7>BA3G^MMu}i{9QP^b%PTxMp-P5QrEZk0mTBMjC&E%(7=VSIhwO^FL5#nl(<* zBPCI909 zR`q~|QzL!M_STlxc4ptmlo0z9!NAA-lpu2@fMOn*(9e8UXDJPqg{aBq}nmZe8@TScrXLmh0C9I(`8|wG`!qYaGuaw0la8|iar5v z%1C3$+QOZBqCFZDnfRvn_|sxXGfn|^TWuy4Px~sCh{B+AXcooc8+RMFfp8OuX3x<2 z6@Yya%sQw=@O>tneio#Hvr7Ibg1fTA<`E$cmmN21`msSuG|}5q{VXr*+NFz^u4Uyt zt8VF?z;fs5{+b&*Tr?o!ys+#pSoAU33a1kEY+Crtm!Nf!1sB-^E9%i_X2b+8wmoj+ zesiE?q3575QHi4ObTMf&c4HNA%pAq1@$Z}PnG+g&M0z`g+R0-UsOzf#!Iu#J;Y(`% zzsr@Bc4f5~m9o?5g^I@g-X}tPS`rVC{x2|1Z9zYL@|^8~0zn zWWVx%`4XjtzxWc~M+4)wfBBM{fA|u@|KLkjxuQ`5+Sy@+t3%W@o=!O8Yr?$^k4$}fR?ksJ76-bWMdQh7Sbu1R`E$skYOxDs$Ek$3GopT{IveEu>m&;XC07x{1q zWj_j`LAII0^7?S9%C0VXi36~*QJ!a@bVk}_M@pBMYMXrI1>)XJJ?G zLgSuxZFk`vAXDUIF35!5eZpTGQ%&Kj9UZ6Mp5AJX_&TFLzxsn0@pbLgSgb$T+M(?s zc#8E03n@Mmzxsp6@yj{{`~U3^cEbPk2cP^$UqKa zRpYyqrG29T;GXGkp5W$T?jb7U^32avIyOcrg@1C?A3y&RFthTdG; z;c1NVdpL@^zM1V(Pj4S@&!x6z`sx^ug;O#1+;Q#AkW4=E@{o%XsJE$T68U!A4A93a z$Bp3%>d8N6E;FcyxWk)4&u`Ovz<|-drIfo^>G~j&ff*+IaD`m!MclhU-WXOM^0Ja` z(-XxQNJDLf^s_^xtX|^vQPl$yD>pbnp}9?YBXS7J75XVxaP3$O-Q>2MYrZbz7_HT ztYo(EWG6a$f3+IG2)fZOLdNT^ZE@5lVurM_gMVbgiA%Tc<~_)}d+XAPgh+n}W6ZuL zYCCSZRyU4_+HV9g0JYWkN72rc3$g0kfV{#Nns-YyxQk@+5UE~FOc6I(V+Zg}^75bU zCPrUbW+r`~)cj=_2RdQoEsvoM=7RM#09NjLTMkt~T{jg*E>Z^W;2PgSe@q#B!O8gY zp9`$Us}uu;MU<7C21C8KqF7-4*uYv~9gCk#)wv=55vNE?=tbU!QWXN8@?{?r&2bc` zlo}4oZ^_=_tW5w&S{B}$4rcuM^sl!cnwpzFy#4FxpBV=?d0S|a0D`vjj_ejb%Be|l zqTtLEKg#$|0~DyCZ;{>vnqu4!@eLhnGM}{$SUWJb9*7ma)iZ41tfUkP0~M>rtrq+& z$0x&H##4Vl?;3G;1}GOt6mE7wS5fj}Gn-U`WY@ui=xJ;) zen53)4SLOT0G6{HKrra?8hz)DaRAf2Y+F!2@iW5C#W(q`NTT7Y8uccJ=Nv zcVE=Cb^jQ~IDp|F-EDO*?w;Ab+IH?Q4j`ehTLSmzZ!*9*fLu26IZ+?9&E`#G9Dw&b z^tB5ZJj(%C&T;@=gDh8!1BeGsqX)t3vLKZvrg|_EtJqNmW{=YM3-zNUdhtA!-KKIs ztiin$4Kx!cD)y9vS7vN1rV6oqHy*kpi^N^W8sCvKA57IAp!YNwc}Ud~+{W+HocYkI zH%L$79LOb`EpJP;#8F+-K29TJRcQg32~C=7zwW@*r?p>yu(>lLi9{lr;j({xt$lj+ zz&iW6m@i};kXAK@On*#srQ$48+vMzQ7idmm5AtReG(SiBeIss36_Ur$xQ9MaGyO0V ziM8Rc<055upm;0~FPyTlnYjX%_b4Wc%>rkCC4-Bf+;o*EVi6{rw-Lr9aIgXQI{0FM z;RmOKS>oT6t2yo}FNNXIN#r4IVZ9`kXj3Q8VkjTujwjQUc4O}vL{<)aEfJK2VebFN zhXaW4bJpg?Dj-42c3sk~vgW>Vf#e@R5rHLw@xJD=TS@C|wFscf;>}r~g~-6ejacFk zRw9tR4pSxvVV}%yC0g=0_n0yxOI~L~OqJ9xq&-AVLgB)fD(;+W<=@0vU^?u_7g;2@gC>I1j_zwXZa zD~fZC<1@3JmB7-aV-Ezx2rCv45m1rP#1@J~!5+#*j6o4a5DS8eNC_$tf>==mL=cP= z4JCjGEM26tv@Nj9wwe1bn&h0E`w!gtanE7*%rGqP^FHtQ`Fvh9_H#fM0|RFtQg8+W zDtHm6zwt$Cn42jBA`g`=2s|nZM3VUNInfw@QCCQaH))c7uG! zdhCg@XeQlesA<8HjyA&;>|*Kx?2tljqrx$X)hcO#HZOuPc~Vp0ryVg$OYJ75eWIV^ z8*RgOY7IO?VkKMEn^?Ncu?p4ILrqJyUkgF%f2!RMIXczvgRBC1XIseffp{p|5MGta zmeqxUIY`%EI;FyRTnT$g=^ho!B-b{yF-mG*WjeZ8TzD3Jb}r24y_q_8{X&>3U;cGIW=_a>-!1qKohW z)qVPvx@q&6D-tfQ{6-;G)MyX6Hc7LM5$6i5`4EHR@?0=e;H3^PJeWU@jlYVt*Fp#y ztM*)YT-OgaAgFkTGd4WXKQKJTnUTli`2BT{FYH;RK|r+ZBVU1cAm%3TMPPTiWCb**A(}6~3tyha;|I&8F(FrroIzgf5EZgG*L&??TBud-#sXdfInpH+x7}1%QMwNX?OMk^LdcM66c>XDtf@cGnj~C_jR$F zKQyzt`q=VmDG8^iBI76LB?{0y^8?x4QepKOOOk^9ZMN)>00zb5ceHgMRXcvBe?QS2 z%vP)GK0&Y3)^rVSP{@`ZL=t5Iq(?lf1%pMzNQsTfObn$N?Eb3Z{C7}gE?l06v}KUm zvypcdNZPobJ9?O2)2hBzlmdr?PD=!Kjo`_t`&uO%OH*F(9J_BsKRGq_vl8RPfcWux zL_fR@>%O>>ptvciT`H)*<^kG-YD~Yl{ALi~Lq(k7?&i9;73CFg>zccVIp9V_W6k+- zeoQscc=WhdFOaq;ZBitxyx5Jkh3g~hABzW0FqD2Cn>tB1x{p0ypqz$ft9)I@@g!Ws zB0v`^98M8!Rd21KA4c8v#?z3BcSv?SDWeU^D~H}^PzK`ZgEz=6&!I=3RQ6)KRNMZT z=Z(gI>gp(*05A>vXG`^Ti=-E*<`uGJb=51v-UAff%ahaT=8*A~0kq-xVn}1xy&-I> zEYeOLCL1`0-mV1wPfW}k?rf+kEzEnCS6Eur&^gQ#W1wGJc{|k6fDEhKMV3urL-%%R zK#PwzpaWNoA@lU<$;-Nw1HHm4s_MzI3UlfOX_2m8>Fj<0W=MdKf(k1J^`7@fo9ZrX zuga%K(DN4ZjX`?+043u+(sgaFPaX56PaPt2((NxHAHk0Q-KP$d=Bh2NngwYn@HhLF zZu(rGI_-b;se?eDnr`eF^|6=qoYCA{na@e(noueqw|(cSdqo5|^S9~D(K_i@A^VAAn2!OwyL zQ%&|}^~k2*9Qztp^?D)X=WHP8Mh=Rzm&4Ar=>5gilhf^+;iLS96^fZ43%*bEkme@L zAs)g`5OUdzY{aL@byb9v5ypw>`5}DO=s_ww{NMTZZ|3std;ZS1$ANtN>VN0kpZ=3? zcc06*&&u=d3+M9fsc%00oo~Mj^6haT-+uS+eEX+2sdM@Eh4Os+>|DOx{hxgM(|_mN zSA%?e+~4{3J#+c?Z~mQc4`H7VC>#UhhY2f+uu^Ntx=_{;s6ufs5^?TrrIVP^4PsH#4G#kXLB}p6OCw(M%G3>phOB$ep4R z*dZ$fpIwR-tsop89{{A0v99%$>sTVmgI}V&fm5WgTY3??!(U-OlYo>pQDV8;2gHkh z5b1?Z&f^5l@k{pU@z2q~(MTfS)Kbnbk;wTa)+%LOS8}qPU-A)@p5AhP2^f8S3HT+& zDC@8?ZTl7a#7ANNpR6chTB+IW?tNZ_5g@D?wWiDbaS6N+#|)(kN>$eUJ$2dF0G}|9Pds@ zN_Wtd4z;2sc90c#;!MPUbi@bRG16;Kx`L&UzvI4ET{lrWZ<{0m#95i&@RHz{EZSMV z{$9y4FNskg7cb8PFW(Qm{J+A>`hl1A953}1Ug}-E>_70bAH>W4954M6y!5Z|(oe)o ze-|(PcD$T_;N?6DFXw}JIj_ab`8i(l40y?x;3e;am;4o8@^E;`C*mb9ikJK@Uh>p< z$+zQW-T*K2A9$I^!OMIUUgp*CGCzoyc}~2{*WzW~887qac;Nxyh0lN&UIt$HC3xY< z;Dzsl7v2(H_*Z!0k^NOC{=f6#@WSiE3qKJrJWIUrMe)LW#S4EIFFa(t@Tu{_3&#t; z9WOk6y!Z|9;+w#W{{t^R7QFaz@Zu}Ni$4l4J}9P77r!%JeA{^OpX0?x?;=Bb5qwT_6*98f>CzC1Wiv_ZG0TG?56kGy*} zSJ8T)lL@4ZcNhx`(Tw?wIAQl5;-WOc=s8`2L#~jQvxP>nx!#F#%YL>}gcz%jX4H*K z(V4#5XUUO=cRATG%}u{CHD}s5?K&Kp{H(Tb29=K2WgK12fE2BMF5{w|*KH`YEjc`4 zt^+~$+^8UJ5phqqFpe=l11((0xC2y_%+3L8#oXE52E7YupJ}lKP1Bf=?sg8}v zk;wsHgjs^U-T+zL7Z1l6!ORr4?9bzXQ{7C>fwx1e?*-u`>P>$=vcjPGqnUOU*Mo2Y%~4%cD!npqQ7-nvoZ!_az5gw==Hcx4 z4RcukKebX$9?w6b$+8V5dP(Hq_zLihs|${&puoOeS2Tp=0z}nf#oimcSTydNHqt&K=9yJ zX`6j)Hdrz8n(mFBB)sU;+5zB#$A!Cs-bt!;D)DgMHO;;MAHY`rPlR^ zau@*qeiORTp9{7Vldwy~t;4;JNa!?c6SSjCa79BgY)F^^tW|fo!e_2@ifwW)#?B2` zLL@EPd9`v>Dw}F8Oggr6y@{R*olHbv7)FR>x{993`klv;3R|aS($UJRI~S3NO9FD) zSZ}f|h3@)H$h`y1S{cHjFhz|kg03CVCf0N);@CU9m3RqDB5oHvr@IJ$131LPls8>! zyD%Tkk=saB1^l!De)bNkhH7$1A8%57ZxI?wpv)o7?=e56rUqqCX*?8-9RtFNSj1<# za)IVk^eX*pz(CSgislanDQHBog;`7h+53pKMw-AXZg+Z7{@d6sa$k|n;hV2I0d7e; zGybWyuClE7WpP<$UF)ZD;46}FI$zy9Y$Nv-ZHax$M|-Hr*cD+k{|ZH=1?Y7(m=S?OTGD#lvDGV z)PG57@{BS&f!tCEWsYcjpn=r#kNRu5xnytP_S`;Qs3(p7IFex`OKu!rG8RR9D^64BM8#uoTmZ- z&~4z&kVGL5r!0-S-)ma{Z^q)!-i!z82KneM4UH5D@Mc&QqD{V3)sQyqeXtH}0=yZ# z;y@D;aj|!b+?&x~o_^eOmC^t3W*DvVJf2?OFZX7ocrPZBOahB}z?)$L>jb~Y+Co&R zzD;PM74T+AQZzJfq4@^t4?cS{76WgFh4%YyBg?6WNR$M4Gj0RD67@VsGf1El!ehkE z;{?y~Wc>Ab=cp|uNFv|NLe7(s%6T$2DrG!Z@=ZBUre_pTYUDf_i&t1N;K{s1Sx1y< zo+aYREICi+f}AIF)fHHq^&G-7Ylde5du*_|;(1m|eC)Zi=VIeivYuBo4+2Kn>~KwH zn1dcLLAzd+^JFf_c`{j(;u24q@(~vL67Xb-u~!yyo(v%IjP}TRGB?StyfPIVIZp=o zxqg|pFykj8B`wr*JU#z8o=h+&LPxyY40T&B^VR2_CpT0Pqr|pGLodk(0r=_)8Vs=M z2}Jja58u+0(5D8B8`2tE$fZ&C!~(K@Dj7V#5HbTwn6CJ>RFe6z;&F^yeZzOTGE7i0 z-V|`|cK*AT-jN9|pU>w`jP$m=%fEdtV3V;50ajk_d!w3*jTav?CsEhNcL6z#8MN^H zpya7FWbs7S=mOc+NN+FPCu9p`wj!&SGAxteR!37>hd+JN_}{h9Ylplh4E9=laFJjZ)={D=2S zr)+uhh4(6B{l$9?n{KfoMa}VE#~c+N0^aKrzO5Fk9`Ig|(3>g<33I&H&Dd%u)YxB7 z;%EwE5(xyeou9&uLdwsb6B($>3DwLlyQ`Ei@ql1>U*HbZW$;&daj zZ!=ozOw~n?`qHEumUO=TfxUmu!?SZgqn;w+K#>);4qf zpg?hf>dM}>C5t;+bXRj85l+e6v_RQ$i>>J|vv81Kyp_8I%;VStBIHJF^Kwa$GLYM* za!ptAG66yI05J>j+tUHR{eYa`{s>EB7(B!ZOuz8kJ*u$QKy{*B<`;hZ#<+Spzdd4( z-)^wZCn62-+Xp8BaZnVd6TmB$x; zyJ-RT(14MKJ(Ba=4*-69I^efw0e*WVoXJ~h%1s5zVC5jm^3B*rK;yJWO+?$7*g8jS ztu5xZRB(pc@Rl4db=K^tRdx|&5P*}0OCU1h$(qNU50E;5*}LI-qY5@Yd( zfcT93+sN2!K)q%}6k{)t{^ICS=R1N{oV zCkeQE2pJ+5<=PHSXK6V3Z3Fd;V5u8syB2d?hcUM=kO7%HP%zo9MtyW9Z^A`AYCF&{ zV&23`!;V%%K~-#^`8NjW>)Xb11?m`&272DHnH90|Gr{>wVO4A%610!*7v z4w=zl)isBIc{?P+B$M6M`5E!2Lk|AniNW56JBR$Y-+(!pi9_UmoMfKa3hrk=&Rvlg@v|SNe1XP;fBZNf z<$fHuN{kh(LA3pKLRxpi82E86$^AGlBDWX<4yyiIual{H@BZb-d6$=Z(rc|g;HVmI ziF_gV<6HuM9ODyp(urSfi5kHytkO;H$NBh=ALoI_g7VLP9HN)#?q@#^cZC@*S?wNd&>J zofk~BEJyDzCH>GLeaM8qz0I4s??6`ccr+zrC2UlJw6so`g5S{Q3D6b1vo>nQN6C;Os{^}TJeGOB<#uVc0dBTJ=-9MI@vvA!nPXh zk6l#8fjYGRDwC+_l-`SSUZ1jNfP#G2#lm*33>A#BD)Ta~MTdt51qOwNM_03=}wA7=GA_*?f`?j>kq7E8^QRVtj+=2*24`%9J<+_@JZ1PCsjoneE6Kdu?8>Kb7$5^)AMB=Z*i6hlilTS$; z^!m!E`_O2hKR*suo*N`*Hft5_Dq67Ms{~2C1GJ?UeQpI=Jrs>zUJ4nX@5Xu)Z54TXmlU7tWVED Wa*AACLyF_*_)AQ-%Z&HTYW)|`Dr-*w literal 0 HcmV?d00001 From b87362d91f209689e21e5b3de897fc79bae0670b Mon Sep 17 00:00:00 2001 From: Ynse Hoornenborg Date: Thu, 25 Nov 2021 21:40:51 +0100 Subject: [PATCH 04/65] Fix style warning in BinaryDecoder --- src/ImageSharp/Formats/Pbm/BinaryDecoder.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ImageSharp/Formats/Pbm/BinaryDecoder.cs b/src/ImageSharp/Formats/Pbm/BinaryDecoder.cs index 1c86b2bd8..c7a09a613 100644 --- a/src/ImageSharp/Formats/Pbm/BinaryDecoder.cs +++ b/src/ImageSharp/Formats/Pbm/BinaryDecoder.cs @@ -176,6 +176,7 @@ namespace SixLabors.ImageSharp.Formats.Pbm { stream.Seek(-1, System.IO.SeekOrigin.Current); } + break; } } From 5939bf8ab1dd01d37c80c22fdb39b1036df1af68 Mon Sep 17 00:00:00 2001 From: Ynse Hoornenborg Date: Thu, 25 Nov 2021 21:44:01 +0100 Subject: [PATCH 05/65] Restore LangVersion --- src/ImageSharp/ImageSharp.csproj | 1 - tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj | 1 - .../ImageSharp.Tests.ProfilingSandbox.csproj | 1 - tests/ImageSharp.Tests/ImageSharp.Tests.csproj | 1 - 4 files changed, 4 deletions(-) diff --git a/src/ImageSharp/ImageSharp.csproj b/src/ImageSharp/ImageSharp.csproj index a0a45e8aa..6eed09b39 100644 --- a/src/ImageSharp/ImageSharp.csproj +++ b/src/ImageSharp/ImageSharp.csproj @@ -39,7 +39,6 @@ netcoreapp3.1;netcoreapp2.1;netstandard2.1;netstandard2.0;netstandard1.3;net472 - 9.0 diff --git a/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj b/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj index 4d7af89a5..8f0b4a86f 100644 --- a/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj +++ b/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj @@ -28,7 +28,6 @@ net5.0;netcoreapp3.1;netcoreapp2.1;net472 - 9.0 diff --git a/tests/ImageSharp.Tests.ProfilingSandbox/ImageSharp.Tests.ProfilingSandbox.csproj b/tests/ImageSharp.Tests.ProfilingSandbox/ImageSharp.Tests.ProfilingSandbox.csproj index a141a58b0..1a470fa31 100644 --- a/tests/ImageSharp.Tests.ProfilingSandbox/ImageSharp.Tests.ProfilingSandbox.csproj +++ b/tests/ImageSharp.Tests.ProfilingSandbox/ImageSharp.Tests.ProfilingSandbox.csproj @@ -30,7 +30,6 @@ net5.0;netcoreapp3.1;netcoreapp2.1;net472 - 9.0 diff --git a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj index c560b1b78..471287006 100644 --- a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj +++ b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj @@ -23,7 +23,6 @@ net5.0;netcoreapp3.1;netcoreapp2.1;net472 - 9.0 From 0c8c892647d2d4ba2535e9a9ac6bd4ac2213d34b Mon Sep 17 00:00:00 2001 From: Ynse Hoornenborg Date: Sat, 27 Nov 2021 22:23:47 +0100 Subject: [PATCH 06/65] Process first round of review comments --- src/ImageSharp/Formats/Pbm/BinaryDecoder.cs | 2 +- src/ImageSharp/Formats/Pbm/BinaryEncoder.cs | 22 +-- .../Pbm/BufferedReadStreamExtensions.cs | 2 +- src/ImageSharp/Formats/Pbm/PbmConstants.cs | 4 +- src/ImageSharp/Formats/Pbm/PbmDecoder.cs | 18 ++- src/ImageSharp/Formats/Pbm/PbmDecoderCore.cs | 4 +- src/ImageSharp/Formats/Pbm/PbmEncoder.cs | 23 +++- src/ImageSharp/Formats/Pbm/PbmEncoderCore.cs | 58 ++++---- .../Formats/Pbm/PbmImageFormatDetector.cs | 7 +- src/ImageSharp/Formats/Pbm/PlainEncoder.cs | 129 ++++++++++-------- .../Formats/Pbm/StreamExtensions.cs | 19 --- .../Formats/Pbm/PbmDecoderTests.cs | 55 +++++++- tests/ImageSharp.Tests/TestImages.cs | 2 + ...age_L16_Gene-UP WebSocket RunImageMask.png | 3 + ...ReferenceImage_L8_blackandwhite_binary.png | 3 + ...eReferenceImage_L8_blackandwhite_plain.png | 3 + ...nceImage_L8_grayscale_plain_normalized.png | 3 + .../DecodeReferenceImage_L8_rings.png | 3 + ...DecodeReferenceImage_Rgb24_00000_00000.png | 3 + ...erenceImage_Rgb24_rgb_plain_normalized.png | 3 + .../Input/Pbm/grayscale_plain_normalized.pgm | 10 ++ .../Images/Input/Pbm/rgb_plain_normalized.ppm | 8 ++ 22 files changed, 257 insertions(+), 127 deletions(-) delete mode 100644 src/ImageSharp/Formats/Pbm/StreamExtensions.cs create mode 100644 tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L16_Gene-UP WebSocket RunImageMask.png create mode 100644 tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L8_blackandwhite_binary.png create mode 100644 tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L8_blackandwhite_plain.png create mode 100644 tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L8_grayscale_plain_normalized.png create mode 100644 tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L8_rings.png create mode 100644 tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_Rgb24_00000_00000.png create mode 100644 tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_Rgb24_rgb_plain_normalized.png create mode 100644 tests/Images/Input/Pbm/grayscale_plain_normalized.pgm create mode 100644 tests/Images/Input/Pbm/rgb_plain_normalized.ppm diff --git a/src/ImageSharp/Formats/Pbm/BinaryDecoder.cs b/src/ImageSharp/Formats/Pbm/BinaryDecoder.cs index c7a09a613..8b6df295b 100644 --- a/src/ImageSharp/Formats/Pbm/BinaryDecoder.cs +++ b/src/ImageSharp/Formats/Pbm/BinaryDecoder.cs @@ -171,7 +171,7 @@ namespace SixLabors.ImageSharp.Formats.Pbm x++; if (x == width) { - startBit = (bit + 1) % 8; + startBit = (bit + 1) & 7; // Round off to below 8. if (startBit != 0) { stream.Seek(-1, System.IO.SeekOrigin.Current); diff --git a/src/ImageSharp/Formats/Pbm/BinaryEncoder.cs b/src/ImageSharp/Formats/Pbm/BinaryEncoder.cs index 1233c87fc..2bcbaeef7 100644 --- a/src/ImageSharp/Formats/Pbm/BinaryEncoder.cs +++ b/src/ImageSharp/Formats/Pbm/BinaryEncoder.cs @@ -60,8 +60,8 @@ namespace SixLabors.ImageSharp.Formats.Pbm private static void WriteGrayscale(Configuration configuration, Stream stream, ImageFrame image) where TPixel : unmanaged, IPixel { - int width = image.Size().Width; - int height = image.Size().Height; + int width = image.Width; + int height = image.Height; MemoryAllocator allocator = configuration.MemoryAllocator; using IMemoryOwner row = allocator.Allocate(width); Span rowSpan = row.GetSpan(); @@ -83,8 +83,8 @@ namespace SixLabors.ImageSharp.Formats.Pbm private static void WriteWideGrayscale(Configuration configuration, Stream stream, ImageFrame image) where TPixel : unmanaged, IPixel { - int width = image.Size().Width; - int height = image.Size().Height; + int width = image.Width; + int height = image.Height; int bytesPerPixel = 2; MemoryAllocator allocator = configuration.MemoryAllocator; using IMemoryOwner row = allocator.Allocate(width * bytesPerPixel); @@ -107,8 +107,8 @@ namespace SixLabors.ImageSharp.Formats.Pbm private static void WriteRgb(Configuration configuration, Stream stream, ImageFrame image) where TPixel : unmanaged, IPixel { - int width = image.Size().Width; - int height = image.Size().Height; + int width = image.Width; + int height = image.Height; int bytesPerPixel = 3; MemoryAllocator allocator = configuration.MemoryAllocator; using IMemoryOwner row = allocator.Allocate(width * bytesPerPixel); @@ -131,8 +131,8 @@ namespace SixLabors.ImageSharp.Formats.Pbm private static void WriteWideRgb(Configuration configuration, Stream stream, ImageFrame image) where TPixel : unmanaged, IPixel { - int width = image.Size().Width; - int height = image.Size().Height; + int width = image.Width; + int height = image.Height; int bytesPerPixel = 6; MemoryAllocator allocator = configuration.MemoryAllocator; using IMemoryOwner row = allocator.Allocate(width * bytesPerPixel); @@ -155,8 +155,8 @@ namespace SixLabors.ImageSharp.Formats.Pbm private static void WriteBlackAndWhite(Configuration configuration, Stream stream, ImageFrame image) where TPixel : unmanaged, IPixel { - int width = image.Size().Width; - int height = image.Size().Height; + int width = image.Width; + int height = image.Height; MemoryAllocator allocator = configuration.MemoryAllocator; using IMemoryOwner row = allocator.Allocate(width); Span rowSpan = row.GetSpan(); @@ -186,7 +186,7 @@ namespace SixLabors.ImageSharp.Formats.Pbm if (x == width) { previousValue = value; - startBit = (i + 1) % 8; + startBit = (i + 1) & 7; // Round off to below 8. break; } } diff --git a/src/ImageSharp/Formats/Pbm/BufferedReadStreamExtensions.cs b/src/ImageSharp/Formats/Pbm/BufferedReadStreamExtensions.cs index 054731b48..581d3e592 100644 --- a/src/ImageSharp/Formats/Pbm/BufferedReadStreamExtensions.cs +++ b/src/ImageSharp/Formats/Pbm/BufferedReadStreamExtensions.cs @@ -51,7 +51,7 @@ namespace SixLabors.ImageSharp.Formats.Pbm while (true) { int current = stream.ReadByte() - 0x30; - if (current < 0 || current > 9) + if ((uint)current > 9) { break; } diff --git a/src/ImageSharp/Formats/Pbm/PbmConstants.cs b/src/ImageSharp/Formats/Pbm/PbmConstants.cs index 0aa9b706a..912ffaf85 100644 --- a/src/ImageSharp/Formats/Pbm/PbmConstants.cs +++ b/src/ImageSharp/Formats/Pbm/PbmConstants.cs @@ -18,11 +18,11 @@ namespace SixLabors.ImageSharp.Formats.Pbm /// /// The list of mimetypes that equate to a ppm. /// - public static readonly IEnumerable MimeTypes = new[] { "image/x-portable-pixmap", "image/x-portable-anymap", "image/x-portable-arbitrarymap" }; + public static readonly IEnumerable MimeTypes = new[] { "image/x-portable-pixmap", "image/x-portable-anymap" }; /// /// The list of file extensions that equate to a ppm. /// - public static readonly IEnumerable FileExtensions = new[] { "ppm", "pbm", "pgm", "pam" }; + public static readonly IEnumerable FileExtensions = new[] { "ppm", "pbm", "pgm" }; } } diff --git a/src/ImageSharp/Formats/Pbm/PbmDecoder.cs b/src/ImageSharp/Formats/Pbm/PbmDecoder.cs index 640ec3823..62cef176d 100644 --- a/src/ImageSharp/Formats/Pbm/PbmDecoder.cs +++ b/src/ImageSharp/Formats/Pbm/PbmDecoder.cs @@ -9,7 +9,23 @@ using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Formats.Pbm { /// - /// Image decoder for generating an image out of a ppm stream. + /// Image decoder for reading PGM, PBM or PPM bitmaps from a stream. These images are from + /// the family of PNM images. + /// + /// + /// PBM + /// Black and white images. + /// + /// + /// PGM + /// Grayscale images. + /// + /// + /// PPM + /// Color images, with RGB pixels. + /// + /// + /// The specification of these images is found at . /// public sealed class PbmDecoder : IImageDecoder, IImageInfoDetector { diff --git a/src/ImageSharp/Formats/Pbm/PbmDecoderCore.cs b/src/ImageSharp/Formats/Pbm/PbmDecoderCore.cs index 31969af47..bd99a578a 100644 --- a/src/ImageSharp/Formats/Pbm/PbmDecoderCore.cs +++ b/src/ImageSharp/Formats/Pbm/PbmDecoderCore.cs @@ -82,9 +82,9 @@ namespace SixLabors.ImageSharp.Formats.Pbm /// The input stream. private void ProcessHeader(BufferedReadStream stream) { - byte[] buffer = new byte[2]; + Span buffer = stackalloc byte[2]; - int bytesRead = stream.Read(buffer, 0, 2); + int bytesRead = stream.Read(buffer); if (bytesRead != 2 || buffer[0] != 'P') { // Empty or not an PPM image. diff --git a/src/ImageSharp/Formats/Pbm/PbmEncoder.cs b/src/ImageSharp/Formats/Pbm/PbmEncoder.cs index 21565d161..fe0f7f9f1 100644 --- a/src/ImageSharp/Formats/Pbm/PbmEncoder.cs +++ b/src/ImageSharp/Formats/Pbm/PbmEncoder.cs @@ -10,7 +10,28 @@ using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Formats.Pbm { /// - /// Image encoder for writing an image to a stream as PGM, PBM, PPM or PAM bitmap. + /// Image encoder for writing an image to a stream as PGM, PBM or PPM bitmap. These images are from + /// the family of PNM images. + /// + /// The PNM formats are a faily simple image format. They share a plain text header, consisting of: + /// signature, width, height and max_pixel_value only. The pixels follow thereafter and can be in + /// plain text decimals seperated by spaces, or binary encoded. + /// + /// + /// PBM + /// Black and white images, with 1 representing black and 0 representing white. + /// + /// + /// PGM + /// Grayscale images, scaling from 0 to max_pixel_value, 0 representing black and max_pixel_value representing white. + /// + /// + /// PPM + /// Color images, with RGB pixels (in that order), with 0 representing black and 2 representing full color. + /// + /// + /// + /// The specification of these images is found at . /// public sealed class PbmEncoder : IImageEncoder, IPbmEncoderOptions { diff --git a/src/ImageSharp/Formats/Pbm/PbmEncoderCore.cs b/src/ImageSharp/Formats/Pbm/PbmEncoderCore.cs index 527ceb8ee..eb1ba8140 100644 --- a/src/ImageSharp/Formats/Pbm/PbmEncoderCore.cs +++ b/src/ImageSharp/Formats/Pbm/PbmEncoderCore.cs @@ -2,12 +2,10 @@ // Licensed under the Apache License, Version 2.0. using System; -using System.Buffers; +using System.Buffers.Text; using System.IO; -using System.Text; using System.Threading; using SixLabors.ImageSharp.Advanced; -using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Formats.Pbm @@ -17,7 +15,9 @@ namespace SixLabors.ImageSharp.Formats.Pbm /// internal sealed class PbmEncoderCore : IImageEncoderInternals { - private const char NewLine = '\n'; + private const byte NewLine = (byte)'\n'; + private const byte Space = (byte)' '; + private const byte P = (byte)'P'; /// /// The global configuration. @@ -70,7 +70,7 @@ namespace SixLabors.ImageSharp.Formats.Pbm this.DeduceOptions(image); - string signature = this.DeduceSignature(); + byte signature = this.DeduceSignature(); this.WriteHeader(stream, signature, image.Size()); this.WritePixels(stream, image.Frames.RootFrame); @@ -91,29 +91,29 @@ namespace SixLabors.ImageSharp.Formats.Pbm } } - private string DeduceSignature() + private byte DeduceSignature() { - string signature; + byte signature; if (this.colorType == PbmColorType.BlackAndWhite) { if (this.encoding == PbmEncoding.Plain) { - signature = "P1"; + signature = (byte)'1'; } else { - signature = "P4"; + signature = (byte)'4'; } } else if (this.colorType == PbmColorType.Grayscale) { if (this.encoding == PbmEncoding.Plain) { - signature = "P2"; + signature = (byte)'2'; } else { - signature = "P5"; + signature = (byte)'5'; } } else @@ -121,35 +121,41 @@ namespace SixLabors.ImageSharp.Formats.Pbm // RGB ColorType if (this.encoding == PbmEncoding.Plain) { - signature = "P3"; + signature = (byte)'3'; } else { - signature = "P6"; + signature = (byte)'6'; } } return signature; } - private void WriteHeader(Stream stream, string signature, Size pixelSize) + private void WriteHeader(Stream stream, byte signature, Size pixelSize) { - var builder = new StringBuilder(20); - builder.Append(signature); - builder.Append(NewLine); - builder.Append(pixelSize.Width.ToString()); - builder.Append(NewLine); - builder.Append(pixelSize.Height.ToString()); - builder.Append(NewLine); + Span buffer = stackalloc byte[128]; + + int written = 3; + buffer[0] = P; + buffer[1] = signature; + buffer[2] = NewLine; + + Utf8Formatter.TryFormat(pixelSize.Width, buffer.Slice(written), out int bytesWritten); + written += bytesWritten; + buffer[written++] = Space; + Utf8Formatter.TryFormat(pixelSize.Height, buffer.Slice(written), out bytesWritten); + written += bytesWritten; + buffer[written++] = NewLine; + if (this.colorType != PbmColorType.BlackAndWhite) { - builder.Append(this.maxPixelValue.ToString()); - builder.Append(NewLine); + Utf8Formatter.TryFormat(this.maxPixelValue, buffer.Slice(written), out bytesWritten); + written += bytesWritten; + buffer[written++] = NewLine; } - string headerStr = builder.ToString(); - byte[] headerBytes = Encoding.ASCII.GetBytes(headerStr); - stream.Write(headerBytes, 0, headerBytes.Length); + stream.Write(buffer, 0, written); } /// diff --git a/src/ImageSharp/Formats/Pbm/PbmImageFormatDetector.cs b/src/ImageSharp/Formats/Pbm/PbmImageFormatDetector.cs index 943424dc9..15bacc4de 100644 --- a/src/ImageSharp/Formats/Pbm/PbmImageFormatDetector.cs +++ b/src/ImageSharp/Formats/Pbm/PbmImageFormatDetector.cs @@ -22,9 +22,12 @@ namespace SixLabors.ImageSharp.Formats.Pbm private bool IsSupportedFileFormat(ReadOnlySpan header) { - if (header.Length >= this.HeaderSize) +#pragma warning disable SA1131 // Use readable conditions + if (1 < (uint)header.Length) +#pragma warning restore SA1131 // Use readable conditions { - return header[0] == P && header[1] > Zero && header[1] < Seven; + // Signature should be between P1 and P6. + return header[0] == P && (uint)(header[1] - Zero - 1) < (Seven - Zero - 1); } return false; diff --git a/src/ImageSharp/Formats/Pbm/PlainEncoder.cs b/src/ImageSharp/Formats/Pbm/PlainEncoder.cs index d90eaf73f..e362f8680 100644 --- a/src/ImageSharp/Formats/Pbm/PlainEncoder.cs +++ b/src/ImageSharp/Formats/Pbm/PlainEncoder.cs @@ -3,6 +3,7 @@ using System; using System.Buffers; +using System.Buffers.Text; using System.IO; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; @@ -20,6 +21,14 @@ namespace SixLabors.ImageSharp.Formats.Pbm private const byte Zero = 0x30; private const byte One = 0x31; + private const int MaxCharsPerPixelBlackAndWhite = 2; + private const int MaxCharsPerPixelGrayscale = 4; + private const int MaxCharsPerPixelGrayscaleWide = 6; + private const int MaxCharsPerPixelRgb = 4 * 3; + private const int MaxCharsPerPixelRgbWide = 6 * 3; + + private static readonly StandardFormat DecimalFormat = StandardFormat.Parse("D"); + /// /// Decode pixels into the PBM plain encoding. /// @@ -63,12 +72,12 @@ namespace SixLabors.ImageSharp.Formats.Pbm private static void WriteGrayscale(Configuration configuration, Stream stream, ImageFrame image) where TPixel : unmanaged, IPixel { - int width = image.Size().Width; - int height = image.Size().Height; - int bytesWritten = -1; + int width = image.Width; + int height = image.Height; MemoryAllocator allocator = configuration.MemoryAllocator; using IMemoryOwner row = allocator.Allocate(width); Span rowSpan = row.GetSpan(); + Span plainSpan = stackalloc byte[width * MaxCharsPerPixelGrayscale]; for (int y = 0; y < height; y++) { @@ -78,23 +87,28 @@ namespace SixLabors.ImageSharp.Formats.Pbm pixelSpan, rowSpan); + int written = 0; for (int x = 0; x < width; x++) { - WriteWhitespace(stream, ref bytesWritten); - bytesWritten += stream.WriteDecimal(rowSpan[x].PackedValue); + Utf8Formatter.TryFormat(rowSpan[x].PackedValue, plainSpan.Slice(written), out int bytesWritten, DecimalFormat); + written += bytesWritten; + plainSpan[written++] = Space; } + + plainSpan[written - 1] = NewLine; + stream.Write(plainSpan, 0, written); } } private static void WriteWideGrayscale(Configuration configuration, Stream stream, ImageFrame image) where TPixel : unmanaged, IPixel { - int width = image.Size().Width; - int height = image.Size().Height; - int bytesWritten = -1; + int width = image.Width; + int height = image.Height; MemoryAllocator allocator = configuration.MemoryAllocator; using IMemoryOwner row = allocator.Allocate(width); Span rowSpan = row.GetSpan(); + Span plainSpan = stackalloc byte[width * MaxCharsPerPixelGrayscaleWide]; for (int y = 0; y < height; y++) { @@ -104,23 +118,28 @@ namespace SixLabors.ImageSharp.Formats.Pbm pixelSpan, rowSpan); + int written = 0; for (int x = 0; x < width; x++) { - WriteWhitespace(stream, ref bytesWritten); - bytesWritten += stream.WriteDecimal(rowSpan[x].PackedValue); + Utf8Formatter.TryFormat(rowSpan[x].PackedValue, plainSpan.Slice(written), out int bytesWritten, DecimalFormat); + written += bytesWritten; + plainSpan[written++] = Space; } + + plainSpan[written - 1] = NewLine; + stream.Write(plainSpan, 0, written); } } private static void WriteRgb(Configuration configuration, Stream stream, ImageFrame image) where TPixel : unmanaged, IPixel { - int width = image.Size().Width; - int height = image.Size().Height; - int bytesWritten = -1; + int width = image.Width; + int height = image.Height; MemoryAllocator allocator = configuration.MemoryAllocator; using IMemoryOwner row = allocator.Allocate(width); Span rowSpan = row.GetSpan(); + Span plainSpan = stackalloc byte[width * MaxCharsPerPixelRgb]; for (int y = 0; y < height; y++) { @@ -130,27 +149,34 @@ namespace SixLabors.ImageSharp.Formats.Pbm pixelSpan, rowSpan); + int written = 0; for (int x = 0; x < width; x++) { - WriteWhitespace(stream, ref bytesWritten); - bytesWritten += stream.WriteDecimal(rowSpan[x].R); - WriteWhitespace(stream, ref bytesWritten); - bytesWritten += stream.WriteDecimal(rowSpan[x].G); - WriteWhitespace(stream, ref bytesWritten); - bytesWritten += stream.WriteDecimal(rowSpan[x].B); + Utf8Formatter.TryFormat(rowSpan[x].R, plainSpan.Slice(written), out int bytesWritten, DecimalFormat); + written += bytesWritten; + plainSpan[written++] = Space; + Utf8Formatter.TryFormat(rowSpan[x].G, plainSpan.Slice(written), out bytesWritten, DecimalFormat); + written += bytesWritten; + plainSpan[written++] = Space; + Utf8Formatter.TryFormat(rowSpan[x].B, plainSpan.Slice(written), out bytesWritten, DecimalFormat); + written += bytesWritten; + plainSpan[written++] = Space; } + + plainSpan[written - 1] = NewLine; + stream.Write(plainSpan, 0, written); } } private static void WriteWideRgb(Configuration configuration, Stream stream, ImageFrame image) where TPixel : unmanaged, IPixel { - int width = image.Size().Width; - int height = image.Size().Height; - int bytesWritten = -1; + int width = image.Width; + int height = image.Height; MemoryAllocator allocator = configuration.MemoryAllocator; using IMemoryOwner row = allocator.Allocate(width); Span rowSpan = row.GetSpan(); + Span plainSpan = stackalloc byte[width * MaxCharsPerPixelRgbWide]; for (int y = 0; y < height; y++) { @@ -160,27 +186,34 @@ namespace SixLabors.ImageSharp.Formats.Pbm pixelSpan, rowSpan); + int written = 0; for (int x = 0; x < width; x++) { - WriteWhitespace(stream, ref bytesWritten); - bytesWritten += stream.WriteDecimal(rowSpan[x].R); - WriteWhitespace(stream, ref bytesWritten); - bytesWritten += stream.WriteDecimal(rowSpan[x].G); - WriteWhitespace(stream, ref bytesWritten); - bytesWritten += stream.WriteDecimal(rowSpan[x].B); + Utf8Formatter.TryFormat(rowSpan[x].R, plainSpan.Slice(written), out int bytesWritten, DecimalFormat); + written += bytesWritten; + plainSpan[written++] = Space; + Utf8Formatter.TryFormat(rowSpan[x].G, plainSpan.Slice(written), out bytesWritten, DecimalFormat); + written += bytesWritten; + plainSpan[written++] = Space; + Utf8Formatter.TryFormat(rowSpan[x].B, plainSpan.Slice(written), out bytesWritten, DecimalFormat); + written += bytesWritten; + plainSpan[written++] = Space; } + + plainSpan[written - 1] = NewLine; + stream.Write(plainSpan, 0, written); } } private static void WriteBlackAndWhite(Configuration configuration, Stream stream, ImageFrame image) where TPixel : unmanaged, IPixel { - int width = image.Size().Width; - int height = image.Size().Height; - int bytesWritten = -1; + int width = image.Width; + int height = image.Height; MemoryAllocator allocator = configuration.MemoryAllocator; using IMemoryOwner row = allocator.Allocate(width); Span rowSpan = row.GetSpan(); + Span plainSpan = stackalloc byte[width * MaxCharsPerPixelBlackAndWhite]; for (int y = 0; y < height; y++) { @@ -190,38 +223,16 @@ namespace SixLabors.ImageSharp.Formats.Pbm pixelSpan, rowSpan); + int written = 0; for (int x = 0; x < width; x++) { - WriteWhitespace(stream, ref bytesWritten); - if (rowSpan[x].PackedValue > 127) - { - stream.WriteByte(Zero); - } - else - { - stream.WriteByte(One); - } - - bytesWritten++; + byte value = (rowSpan[x].PackedValue > 127) ? Zero : One; + plainSpan[written++] = value; + plainSpan[written++] = Space; } - } - } - private static void WriteWhitespace(Stream stream, ref int bytesWritten) - { - if (bytesWritten > MaxLineLength) - { - stream.WriteByte(NewLine); - bytesWritten = 1; - } - else if (bytesWritten == -1) - { - bytesWritten = 0; - } - else - { - stream.WriteByte(Space); - bytesWritten++; + plainSpan[written - 1] = NewLine; + stream.Write(plainSpan, 0, written); } } } diff --git a/src/ImageSharp/Formats/Pbm/StreamExtensions.cs b/src/ImageSharp/Formats/Pbm/StreamExtensions.cs deleted file mode 100644 index 9851afee0..000000000 --- a/src/ImageSharp/Formats/Pbm/StreamExtensions.cs +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Apache License, Version 2.0. - -using System.IO; -using System.Text; - -namespace SixLabors.ImageSharp.Formats.Pbm -{ - internal static class StreamExtensions - { - public static int WriteDecimal(this Stream stream, int value) - { - string str = value.ToString(); - byte[] bytes = Encoding.ASCII.GetBytes(str); - stream.Write(bytes); - return bytes.Length; - } - } -} diff --git a/tests/ImageSharp.Tests/Formats/Pbm/PbmDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Pbm/PbmDecoderTests.cs index 4ff359387..6c84fba9e 100644 --- a/tests/ImageSharp.Tests/Formats/Pbm/PbmDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Pbm/PbmDecoderTests.cs @@ -3,7 +3,8 @@ using System.IO; using SixLabors.ImageSharp.Formats.Pbm; - +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Processing; using Xunit; using static SixLabors.ImageSharp.Tests.TestImages.Pbm; @@ -21,7 +22,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Pbm [InlineData(GrayscaleBinaryWide, PbmColorType.Grayscale)] [InlineData(RgbPlain, PbmColorType.Rgb)] [InlineData(RgbBinary, PbmColorType.Rgb)] - public void PpmDecoder_CanDecode(string imagePath, PbmColorType expectedColorType) + public void ImageLoadCanDecode(string imagePath, PbmColorType expectedColorType) { // Arrange var testFile = TestFile.Create(imagePath); @@ -36,5 +37,55 @@ namespace SixLabors.ImageSharp.Tests.Formats.Pbm Assert.NotNull(bitmapMetadata); Assert.Equal(expectedColorType, bitmapMetadata.ColorType); } + + [Theory] + [InlineData(BlackAndWhitePlain)] + [InlineData(BlackAndWhiteBinary)] + [InlineData(GrayscalePlain)] + [InlineData(GrayscaleBinary)] + [InlineData(GrayscaleBinaryWide)] + public void ImageLoadL8CanDecode(string imagePath) + { + // Arrange + var testFile = TestFile.Create(imagePath); + using var stream = new MemoryStream(testFile.Bytes, false); + + // Act + using var image = Image.Load(stream); + + // Assert + Assert.NotNull(image); + } + + [Theory] + [InlineData(RgbPlain)] + [InlineData(RgbBinary)] + public void ImageLoadRgb24CanDecode(string imagePath) + { + // Arrange + var testFile = TestFile.Create(imagePath); + using var stream = new MemoryStream(testFile.Bytes, false); + + // Act + using var image = Image.Load(stream); + + // Assert + Assert.NotNull(image); + } + + [Theory] + [WithFile(BlackAndWhiteBinary, PixelTypes.L8, true)] + [WithFile(GrayscalePlainNormalized, PixelTypes.L8, true)] + [WithFile(GrayscaleBinary, PixelTypes.L8, true)] + [WithFile(GrayscaleBinaryWide, PixelTypes.L16, true)] + [WithFile(RgbPlainNormalized, PixelTypes.Rgb24, false)] + [WithFile(RgbBinary, PixelTypes.Rgb24, false)] + public void DecodeReferenceImage(TestImageProvider provider, bool isGrayscale) + where TPixel : unmanaged, IPixel + { + using Image image = provider.GetImage(); + + image.CompareToReferenceOutput(provider, grayscale: isGrayscale); + } } } diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index 67f947ff5..444be63a2 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -874,8 +874,10 @@ namespace SixLabors.ImageSharp.Tests public const string GrayscaleBinary = "Pbm/rings.pgm"; public const string GrayscaleBinaryWide = "Pbm/Gene-UP WebSocket RunImageMask.pgm"; public const string GrayscalePlain = "Pbm/grayscale_plain.pgm"; + public const string GrayscalePlainNormalized = "Pbm/grayscale_plain_normalized.pgm"; public const string RgbBinary = "Pbm/00000_00000.ppm"; public const string RgbPlain = "Pbm/rgb_plain.ppm"; + public const string RgbPlainNormalized = "Pbm/rgb_plain_normalized.ppm"; } } } diff --git a/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L16_Gene-UP WebSocket RunImageMask.png b/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L16_Gene-UP WebSocket RunImageMask.png new file mode 100644 index 000000000..09bb074a3 --- /dev/null +++ b/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L16_Gene-UP WebSocket RunImageMask.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:78fc668be9f82c01c277cb2560253b04a1ff74a5af4daaf19327591420a71fec +size 4521 diff --git a/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L8_blackandwhite_binary.png b/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L8_blackandwhite_binary.png new file mode 100644 index 000000000..d1f1515bb --- /dev/null +++ b/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L8_blackandwhite_binary.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1339a8170408a7bcde261617cc599587c8f25c4dc94f780976ee1638879888e9 +size 147 diff --git a/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L8_blackandwhite_plain.png b/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L8_blackandwhite_plain.png new file mode 100644 index 000000000..372261923 --- /dev/null +++ b/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L8_blackandwhite_plain.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:82d0397f38971cf90d7c064db332093e686196e244ece1196cca2071d27f0a6f +size 147 diff --git a/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L8_grayscale_plain_normalized.png b/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L8_grayscale_plain_normalized.png new file mode 100644 index 000000000..9c86c2fc1 --- /dev/null +++ b/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L8_grayscale_plain_normalized.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f8e8b8a1a05e76b1eeb577373c3a6f492e356f0dd58489afded248415cec4a07 +size 145 diff --git a/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L8_rings.png b/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L8_rings.png new file mode 100644 index 000000000..acf751c28 --- /dev/null +++ b/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L8_rings.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:388c86b3dd472ef17fb911ae424b81baeeeff74c4161cf5825eab50698d54348 +size 27884 diff --git a/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_Rgb24_00000_00000.png b/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_Rgb24_00000_00000.png new file mode 100644 index 000000000..49cc74f3f --- /dev/null +++ b/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_Rgb24_00000_00000.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2e3fc46b9f0546941ef95be7b750fb29376a679a921f2581403882b0e76e9caf +size 2250 diff --git a/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_Rgb24_rgb_plain_normalized.png b/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_Rgb24_rgb_plain_normalized.png new file mode 100644 index 000000000..421a59849 --- /dev/null +++ b/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_Rgb24_rgb_plain_normalized.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c44322c4bf461acea27053057f5241afb029d9a1e66e94dcf1be6f86f7f97727 +size 152 diff --git a/tests/Images/Input/Pbm/grayscale_plain_normalized.pgm b/tests/Images/Input/Pbm/grayscale_plain_normalized.pgm new file mode 100644 index 000000000..fe0329629 --- /dev/null +++ b/tests/Images/Input/Pbm/grayscale_plain_normalized.pgm @@ -0,0 +1,10 @@ +P2 +24 7 +255 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 51 51 51 51 0 0 119 119 119 119 0 0 187 187 187 187 0 0 255 255 255 255 0 +0 51 0 0 0 0 0 119 0 0 0 0 0 187 0 0 0 0 0 255 0 0 255 0 +0 51 51 51 0 0 0 119 119 119 0 0 0 187 187 187 0 0 0 255 255 255 255 0 +0 51 0 0 0 0 0 119 0 0 0 0 0 187 0 0 0 0 0 255 0 0 0 0 +0 51 0 0 0 0 0 119 119 119 119 0 0 187 187 187 187 0 0 255 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 \ No newline at end of file diff --git a/tests/Images/Input/Pbm/rgb_plain_normalized.ppm b/tests/Images/Input/Pbm/rgb_plain_normalized.ppm new file mode 100644 index 000000000..628931579 --- /dev/null +++ b/tests/Images/Input/Pbm/rgb_plain_normalized.ppm @@ -0,0 +1,8 @@ +P3 +# example from the man page +4 4 +255 + 0 0 0 0 0 0 0 0 0 255 0 255 + 0 0 0 0 255 119 0 0 0 0 0 0 + 0 0 0 0 0 0 0 255 119 0 0 0 +255 0 255 0 0 0 0 0 0 0 0 0 \ No newline at end of file From 0e984cf1b4dbadc5bda7175d88e01aa78b0023bf Mon Sep 17 00:00:00 2001 From: Ynse Hoornenborg Date: Sun, 28 Nov 2021 11:17:37 +0100 Subject: [PATCH 07/65] Remove non existing LFS objects --- ...DecodeReferenceImage_L16_Gene-UP WebSocket RunImageMask.png | 3 --- .../DecodeReferenceImage_L8_blackandwhite_binary.png | 3 --- .../DecodeReferenceImage_L8_blackandwhite_plain.png | 3 --- .../DecodeReferenceImage_L8_grayscale_plain_normalized.png | 3 --- .../PbmDecoderTests/DecodeReferenceImage_L8_rings.png | 3 --- .../PbmDecoderTests/DecodeReferenceImage_Rgb24_00000_00000.png | 3 --- .../DecodeReferenceImage_Rgb24_rgb_plain_normalized.png | 3 --- 7 files changed, 21 deletions(-) delete mode 100644 tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L16_Gene-UP WebSocket RunImageMask.png delete mode 100644 tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L8_blackandwhite_binary.png delete mode 100644 tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L8_blackandwhite_plain.png delete mode 100644 tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L8_grayscale_plain_normalized.png delete mode 100644 tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L8_rings.png delete mode 100644 tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_Rgb24_00000_00000.png delete mode 100644 tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_Rgb24_rgb_plain_normalized.png diff --git a/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L16_Gene-UP WebSocket RunImageMask.png b/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L16_Gene-UP WebSocket RunImageMask.png deleted file mode 100644 index 09bb074a3..000000000 --- a/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L16_Gene-UP WebSocket RunImageMask.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:78fc668be9f82c01c277cb2560253b04a1ff74a5af4daaf19327591420a71fec -size 4521 diff --git a/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L8_blackandwhite_binary.png b/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L8_blackandwhite_binary.png deleted file mode 100644 index d1f1515bb..000000000 --- a/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L8_blackandwhite_binary.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:1339a8170408a7bcde261617cc599587c8f25c4dc94f780976ee1638879888e9 -size 147 diff --git a/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L8_blackandwhite_plain.png b/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L8_blackandwhite_plain.png deleted file mode 100644 index 372261923..000000000 --- a/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L8_blackandwhite_plain.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:82d0397f38971cf90d7c064db332093e686196e244ece1196cca2071d27f0a6f -size 147 diff --git a/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L8_grayscale_plain_normalized.png b/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L8_grayscale_plain_normalized.png deleted file mode 100644 index 9c86c2fc1..000000000 --- a/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L8_grayscale_plain_normalized.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f8e8b8a1a05e76b1eeb577373c3a6f492e356f0dd58489afded248415cec4a07 -size 145 diff --git a/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L8_rings.png b/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L8_rings.png deleted file mode 100644 index acf751c28..000000000 --- a/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L8_rings.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:388c86b3dd472ef17fb911ae424b81baeeeff74c4161cf5825eab50698d54348 -size 27884 diff --git a/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_Rgb24_00000_00000.png b/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_Rgb24_00000_00000.png deleted file mode 100644 index 49cc74f3f..000000000 --- a/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_Rgb24_00000_00000.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:2e3fc46b9f0546941ef95be7b750fb29376a679a921f2581403882b0e76e9caf -size 2250 diff --git a/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_Rgb24_rgb_plain_normalized.png b/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_Rgb24_rgb_plain_normalized.png deleted file mode 100644 index 421a59849..000000000 --- a/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_Rgb24_rgb_plain_normalized.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c44322c4bf461acea27053057f5241afb029d9a1e66e94dcf1be6f86f7f97727 -size 152 From e21d2c31a25089c0b492e9daec260f30b0199648 Mon Sep 17 00:00:00 2001 From: Ynse Hoornenborg Date: Sun, 28 Nov 2021 11:18:35 +0100 Subject: [PATCH 08/65] Put back missing LFS objects --- ...DecodeReferenceImage_L16_Gene-UP WebSocket RunImageMask.png | 3 +++ .../DecodeReferenceImage_L8_blackandwhite_binary.png | 3 +++ .../DecodeReferenceImage_L8_blackandwhite_plain.png | 3 +++ .../DecodeReferenceImage_L8_grayscale_plain_normalized.png | 3 +++ .../PbmDecoderTests/DecodeReferenceImage_L8_rings.png | 3 +++ .../PbmDecoderTests/DecodeReferenceImage_Rgb24_00000_00000.png | 3 +++ .../DecodeReferenceImage_Rgb24_rgb_plain_normalized.png | 3 +++ 7 files changed, 21 insertions(+) create mode 100644 tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L16_Gene-UP WebSocket RunImageMask.png create mode 100644 tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L8_blackandwhite_binary.png create mode 100644 tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L8_blackandwhite_plain.png create mode 100644 tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L8_grayscale_plain_normalized.png create mode 100644 tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L8_rings.png create mode 100644 tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_Rgb24_00000_00000.png create mode 100644 tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_Rgb24_rgb_plain_normalized.png diff --git a/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L16_Gene-UP WebSocket RunImageMask.png b/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L16_Gene-UP WebSocket RunImageMask.png new file mode 100644 index 000000000..09bb074a3 --- /dev/null +++ b/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L16_Gene-UP WebSocket RunImageMask.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:78fc668be9f82c01c277cb2560253b04a1ff74a5af4daaf19327591420a71fec +size 4521 diff --git a/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L8_blackandwhite_binary.png b/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L8_blackandwhite_binary.png new file mode 100644 index 000000000..d1f1515bb --- /dev/null +++ b/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L8_blackandwhite_binary.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1339a8170408a7bcde261617cc599587c8f25c4dc94f780976ee1638879888e9 +size 147 diff --git a/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L8_blackandwhite_plain.png b/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L8_blackandwhite_plain.png new file mode 100644 index 000000000..372261923 --- /dev/null +++ b/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L8_blackandwhite_plain.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:82d0397f38971cf90d7c064db332093e686196e244ece1196cca2071d27f0a6f +size 147 diff --git a/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L8_grayscale_plain_normalized.png b/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L8_grayscale_plain_normalized.png new file mode 100644 index 000000000..9c86c2fc1 --- /dev/null +++ b/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L8_grayscale_plain_normalized.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f8e8b8a1a05e76b1eeb577373c3a6f492e356f0dd58489afded248415cec4a07 +size 145 diff --git a/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L8_rings.png b/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L8_rings.png new file mode 100644 index 000000000..acf751c28 --- /dev/null +++ b/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L8_rings.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:388c86b3dd472ef17fb911ae424b81baeeeff74c4161cf5825eab50698d54348 +size 27884 diff --git a/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_Rgb24_00000_00000.png b/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_Rgb24_00000_00000.png new file mode 100644 index 000000000..49cc74f3f --- /dev/null +++ b/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_Rgb24_00000_00000.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2e3fc46b9f0546941ef95be7b750fb29376a679a921f2581403882b0e76e9caf +size 2250 diff --git a/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_Rgb24_rgb_plain_normalized.png b/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_Rgb24_rgb_plain_normalized.png new file mode 100644 index 000000000..421a59849 --- /dev/null +++ b/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_Rgb24_rgb_plain_normalized.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c44322c4bf461acea27053057f5241afb029d9a1e66e94dcf1be6f86f7f97727 +size 152 From 7d1c3b579677ec4160689bb50e2b1fae86d76fab Mon Sep 17 00:00:00 2001 From: Ynse Hoornenborg Date: Mon, 29 Nov 2021 19:50:56 +0100 Subject: [PATCH 09/65] Remove test images, so they can be moved to LFS --- ...mage_L16_Gene-UP WebSocket RunImageMask.png | 3 --- ...eReferenceImage_L8_blackandwhite_binary.png | 3 --- ...deReferenceImage_L8_blackandwhite_plain.png | 3 --- ...enceImage_L8_grayscale_plain_normalized.png | 3 --- .../DecodeReferenceImage_L8_rings.png | 3 --- .../DecodeReferenceImage_Rgb24_00000_00000.png | 3 --- ...ferenceImage_Rgb24_rgb_plain_normalized.png | 3 --- tests/Images/Input/Pbm/00000_00000.ppm | 4 ---- .../Pbm/Gene-UP WebSocket RunImageMask.pgm | Bin 614417 -> 0 bytes .../Images/Input/Pbm/blackandwhite_binary.pbm | 3 --- tests/Images/Input/Pbm/blackandwhite_plain.pbm | 10 ---------- tests/Images/Input/Pbm/grayscale_plain.pgm | 10 ---------- .../Input/Pbm/grayscale_plain_normalized.pgm | 10 ---------- tests/Images/Input/Pbm/rgb_plain.ppm | 8 -------- .../Images/Input/Pbm/rgb_plain_normalized.ppm | 8 -------- tests/Images/Input/Pbm/rings.pgm | Bin 40038 -> 0 bytes 16 files changed, 74 deletions(-) delete mode 100644 tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L16_Gene-UP WebSocket RunImageMask.png delete mode 100644 tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L8_blackandwhite_binary.png delete mode 100644 tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L8_blackandwhite_plain.png delete mode 100644 tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L8_grayscale_plain_normalized.png delete mode 100644 tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L8_rings.png delete mode 100644 tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_Rgb24_00000_00000.png delete mode 100644 tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_Rgb24_rgb_plain_normalized.png delete mode 100644 tests/Images/Input/Pbm/00000_00000.ppm delete mode 100644 tests/Images/Input/Pbm/Gene-UP WebSocket RunImageMask.pgm delete mode 100644 tests/Images/Input/Pbm/blackandwhite_binary.pbm delete mode 100644 tests/Images/Input/Pbm/blackandwhite_plain.pbm delete mode 100644 tests/Images/Input/Pbm/grayscale_plain.pgm delete mode 100644 tests/Images/Input/Pbm/grayscale_plain_normalized.pgm delete mode 100644 tests/Images/Input/Pbm/rgb_plain.ppm delete mode 100644 tests/Images/Input/Pbm/rgb_plain_normalized.ppm delete mode 100644 tests/Images/Input/Pbm/rings.pgm diff --git a/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L16_Gene-UP WebSocket RunImageMask.png b/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L16_Gene-UP WebSocket RunImageMask.png deleted file mode 100644 index 09bb074a3..000000000 --- a/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L16_Gene-UP WebSocket RunImageMask.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:78fc668be9f82c01c277cb2560253b04a1ff74a5af4daaf19327591420a71fec -size 4521 diff --git a/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L8_blackandwhite_binary.png b/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L8_blackandwhite_binary.png deleted file mode 100644 index d1f1515bb..000000000 --- a/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L8_blackandwhite_binary.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:1339a8170408a7bcde261617cc599587c8f25c4dc94f780976ee1638879888e9 -size 147 diff --git a/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L8_blackandwhite_plain.png b/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L8_blackandwhite_plain.png deleted file mode 100644 index 372261923..000000000 --- a/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L8_blackandwhite_plain.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:82d0397f38971cf90d7c064db332093e686196e244ece1196cca2071d27f0a6f -size 147 diff --git a/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L8_grayscale_plain_normalized.png b/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L8_grayscale_plain_normalized.png deleted file mode 100644 index 9c86c2fc1..000000000 --- a/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L8_grayscale_plain_normalized.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f8e8b8a1a05e76b1eeb577373c3a6f492e356f0dd58489afded248415cec4a07 -size 145 diff --git a/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L8_rings.png b/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L8_rings.png deleted file mode 100644 index acf751c28..000000000 --- a/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L8_rings.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:388c86b3dd472ef17fb911ae424b81baeeeff74c4161cf5825eab50698d54348 -size 27884 diff --git a/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_Rgb24_00000_00000.png b/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_Rgb24_00000_00000.png deleted file mode 100644 index 49cc74f3f..000000000 --- a/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_Rgb24_00000_00000.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:2e3fc46b9f0546941ef95be7b750fb29376a679a921f2581403882b0e76e9caf -size 2250 diff --git a/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_Rgb24_rgb_plain_normalized.png b/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_Rgb24_rgb_plain_normalized.png deleted file mode 100644 index 421a59849..000000000 --- a/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_Rgb24_rgb_plain_normalized.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c44322c4bf461acea27053057f5241afb029d9a1e66e94dcf1be6f86f7f97727 -size 152 diff --git a/tests/Images/Input/Pbm/00000_00000.ppm b/tests/Images/Input/Pbm/00000_00000.ppm deleted file mode 100644 index 321188762..000000000 --- a/tests/Images/Input/Pbm/00000_00000.ppm +++ /dev/null @@ -1,4 +0,0 @@ -P6 -29 30 -255 -KNPJLNVWTl^UtrnryysɻܫmpCARVbmY[aKOPDKKAEDBCBSTVPPRZYTk_{YQUZϧ~ѰɊʇR?NQ[ug\kTQVIMNLNKPPNNNPVUV]Z[xzkfD6ڹŕyݩbkbhberZ[^SSHJHIJENNJJKM[SSn\duQP[G㾵ؐFOL9oc}`ZKHBIJCIOJGJG`QHb`swIHrkϸدңΘˎy^mJH6"RHnnULJIKHP]\EJBxfTuaXA@Y_Ӂtujk``XVPNLJHED@A=?;>:y=9m=8x>7?1S=LDfkSPRJJJiknempmlB6A=@DAECGEJHOHNHNKNOOUW[_clky]`rkrlsorjqf}KHw_cHJJLIFh__{lmgrtw{}ɉ؎䐟쟵Ս|lalVPcQOZML_KJeJKTGKEEDJHBPLJo|xeq_kxbo}tttt``LLMPOTdkyiqgo```YYPWWRXVTRNNIFHIGGHGDJJHȻіoq\fJ\|f_ryXt]S^J;A9HGONIHCwvޮڳًaCBC}Pqe_nTSQOSQSURLLHNMGZWRţ~|kMWWJ[|T^xla~LVldŎ˱խýzy}сMQPZyhl]WW\a`Y[YPOLVSO[VQǎwWJJ:z`deuPOMRԝmwPmǟ}hڝYaG:qkvabkpp^a_QRPSSQ\[VaVUGvmslt@>gk٣ƺvWp^kf©zo|?9UTkmbhhY]\RUTRTT`b`r^daTwut@<ʁȾǕy˶nvճ۠@AWYmq]abX[ZUXXSUVZ\\|sqvpm}~|~x~}@<̔vq~~wǭƘ}AAZ[orX[[WZVUXTTWS[^Zlrthjndciffnhjfw}sD@pv󚗳lurxѵϑ?>^_jmVVTYZSVYQZ]T^aXlgHHX[él[[}Ĉuk۽ʺkl>4RNfg[YWZZUZ]W]`Y^aZĭëcgAAtq֨t~wjµļEOS?yor]\_\Z[[XWYUZ[V]]X­nvkxqyYOF8ɉt̰⡰_gckhplfjYTU^Z[a`bUWWUURXUQlvSk]n^q][BE*ʆhcK]cyX|YThTRV^^cWX_SUXOQPSUR|Y}}db|gI`Oj{Jm^OS?fOy_\K@7RTdrkhӇ裷Ähk]hkSeTOYPPSZ^bNQWLORHMNIQOU?OduOlKp`J_Fsw]d`lNRMI}MFQGVNoisjzcVWOKLRRT[_cMOUSTXJNQNUToĮX^:DO4mNveFlNNrUYx]b|l|jdhaztz~lkz[Y`NKPOORTXZLNOOOOMPPNTRLyWgnUW]M\|je^c}]h~bngmuy}}}{|wljy\[iMLUJJOPRRQRNRRNRSOQTPo|qkshjkdz}y}yziprnnhuoqup{okvjiuRS[FFJJJJOOKMNJNNI[[Wzpy|suvvruoothmrdkq`inbhmcgfekcKTKdla}[cinmasmugcm]Z`JHKKIIUTP^^Yab[cgc[_c[bgJUYDHKMJLTLM^QU]W^Z[`__bXVXJMNIRQLUQXaipmfumphah]V[PKOLHH]ZWge_nqh`hbUTW_ek=JOAGLEDESOMc[^ZW`RSXZZ\cbhQR]LPVNTVT_jfkhnnmb^ce^cWRWIGHQPMff_cfZZaY \ No newline at end of file diff --git a/tests/Images/Input/Pbm/Gene-UP WebSocket RunImageMask.pgm b/tests/Images/Input/Pbm/Gene-UP WebSocket RunImageMask.pgm deleted file mode 100644 index 8265eaa50621a9a5455776fbe2c5faeb5933b862..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 614417 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 UfB_6(00S7n00uCCfxLnL0M1c2-v9sr diff --git a/tests/Images/Input/Pbm/blackandwhite_binary.pbm b/tests/Images/Input/Pbm/blackandwhite_binary.pbm deleted file mode 100644 index a25b1d350..000000000 --- a/tests/Images/Input/Pbm/blackandwhite_binary.pbm +++ /dev/null @@ -1,3 +0,0 @@ -P4 -# CREATOR: bitmap2pbm Version 1.0.0 -8 4 @0@0 diff --git a/tests/Images/Input/Pbm/blackandwhite_plain.pbm b/tests/Images/Input/Pbm/blackandwhite_plain.pbm deleted file mode 100644 index fea8cafd0..000000000 --- a/tests/Images/Input/Pbm/blackandwhite_plain.pbm +++ /dev/null @@ -1,10 +0,0 @@ -P1 -# PBM example -24 7 -0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0 1 1 1 1 0 0 1 1 1 1 0 0 1 1 1 1 0 0 1 1 1 1 0 -0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 1 0 -0 1 1 1 0 0 0 1 1 1 0 0 0 1 1 1 0 0 0 1 1 1 1 0 -0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 -0 1 0 0 0 0 0 1 1 1 1 0 0 1 1 1 1 0 0 1 0 0 0 0 -0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 \ No newline at end of file diff --git a/tests/Images/Input/Pbm/grayscale_plain.pgm b/tests/Images/Input/Pbm/grayscale_plain.pgm deleted file mode 100644 index ba4757248..000000000 --- a/tests/Images/Input/Pbm/grayscale_plain.pgm +++ /dev/null @@ -1,10 +0,0 @@ -P2 -24 7 -15 -0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0 3 3 3 3 0 0 7 7 7 7 0 0 11 11 11 11 0 0 15 15 15 15 0 -0 3 0 0 0 0 0 7 0 0 0 0 0 11 0 0 0 0 0 15 0 0 15 0 -0 3 3 3 0 0 0 7 7 7 0 0 0 11 11 11 0 0 0 15 15 15 15 0 -0 3 0 0 0 0 0 7 0 0 0 0 0 11 0 0 0 0 0 15 0 0 0 0 -0 3 0 0 0 0 0 7 7 7 7 0 0 11 11 11 11 0 0 15 0 0 0 0 -0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 \ No newline at end of file diff --git a/tests/Images/Input/Pbm/grayscale_plain_normalized.pgm b/tests/Images/Input/Pbm/grayscale_plain_normalized.pgm deleted file mode 100644 index fe0329629..000000000 --- a/tests/Images/Input/Pbm/grayscale_plain_normalized.pgm +++ /dev/null @@ -1,10 +0,0 @@ -P2 -24 7 -255 -0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0 51 51 51 51 0 0 119 119 119 119 0 0 187 187 187 187 0 0 255 255 255 255 0 -0 51 0 0 0 0 0 119 0 0 0 0 0 187 0 0 0 0 0 255 0 0 255 0 -0 51 51 51 0 0 0 119 119 119 0 0 0 187 187 187 0 0 0 255 255 255 255 0 -0 51 0 0 0 0 0 119 0 0 0 0 0 187 0 0 0 0 0 255 0 0 0 0 -0 51 0 0 0 0 0 119 119 119 119 0 0 187 187 187 187 0 0 255 0 0 0 0 -0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 \ No newline at end of file diff --git a/tests/Images/Input/Pbm/rgb_plain.ppm b/tests/Images/Input/Pbm/rgb_plain.ppm deleted file mode 100644 index ecd1b915c..000000000 --- a/tests/Images/Input/Pbm/rgb_plain.ppm +++ /dev/null @@ -1,8 +0,0 @@ -P3 -# example from the man page -4 4 -15 - 0 0 0 0 0 0 0 0 0 15 0 15 - 0 0 0 0 15 7 0 0 0 0 0 0 - 0 0 0 0 0 0 0 15 7 0 0 0 -15 0 15 0 0 0 0 0 0 0 0 0 \ No newline at end of file diff --git a/tests/Images/Input/Pbm/rgb_plain_normalized.ppm b/tests/Images/Input/Pbm/rgb_plain_normalized.ppm deleted file mode 100644 index 628931579..000000000 --- a/tests/Images/Input/Pbm/rgb_plain_normalized.ppm +++ /dev/null @@ -1,8 +0,0 @@ -P3 -# example from the man page -4 4 -255 - 0 0 0 0 0 0 0 0 0 255 0 255 - 0 0 0 0 255 119 0 0 0 0 0 0 - 0 0 0 0 0 0 0 255 119 0 0 0 -255 0 255 0 0 0 0 0 0 0 0 0 \ No newline at end of file diff --git a/tests/Images/Input/Pbm/rings.pgm b/tests/Images/Input/Pbm/rings.pgm deleted file mode 100644 index e0d4b4ed4d4cfc4da44b131a68f60824957428b6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 40038 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 Wa*AACLyF_*_)AQ-%Z&HTYW)|`Dr-*w From 2b00a22768ba81c709ecfec765e6374ca4c42349 Mon Sep 17 00:00:00 2001 From: Ynse Hoornenborg Date: Mon, 29 Nov 2021 20:12:52 +0100 Subject: [PATCH 10/65] Put the test images back into LFS --- ...mage_L16_Gene-UP WebSocket RunImageMask.png | 3 +++ ...eReferenceImage_L8_blackandwhite_binary.png | 3 +++ ...deReferenceImage_L8_blackandwhite_plain.png | 3 +++ ...enceImage_L8_grayscale_plain_normalized.png | 3 +++ .../DecodeReferenceImage_L8_rings.png | 3 +++ .../DecodeReferenceImage_Rgb24_00000_00000.png | 3 +++ ...ferenceImage_Rgb24_rgb_plain_normalized.png | 3 +++ tests/Images/Input/Pbm/00000_00000.ppm | 4 ++++ .../Pbm/Gene-UP WebSocket RunImageMask.pgm | Bin 0 -> 614417 bytes .../Images/Input/Pbm/blackandwhite_binary.pbm | 3 +++ tests/Images/Input/Pbm/blackandwhite_plain.pbm | 10 ++++++++++ tests/Images/Input/Pbm/grayscale_plain.pgm | 10 ++++++++++ .../Input/Pbm/grayscale_plain_normalized.pgm | 10 ++++++++++ tests/Images/Input/Pbm/rgb_plain.ppm | 8 ++++++++ .../Images/Input/Pbm/rgb_plain_normalized.ppm | 8 ++++++++ tests/Images/Input/Pbm/rings.pgm | Bin 0 -> 40038 bytes 16 files changed, 74 insertions(+) create mode 100644 tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L16_Gene-UP WebSocket RunImageMask.png create mode 100644 tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L8_blackandwhite_binary.png create mode 100644 tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L8_blackandwhite_plain.png create mode 100644 tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L8_grayscale_plain_normalized.png create mode 100644 tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L8_rings.png create mode 100644 tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_Rgb24_00000_00000.png create mode 100644 tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_Rgb24_rgb_plain_normalized.png create mode 100644 tests/Images/Input/Pbm/00000_00000.ppm create mode 100644 tests/Images/Input/Pbm/Gene-UP WebSocket RunImageMask.pgm create mode 100644 tests/Images/Input/Pbm/blackandwhite_binary.pbm create mode 100644 tests/Images/Input/Pbm/blackandwhite_plain.pbm create mode 100644 tests/Images/Input/Pbm/grayscale_plain.pgm create mode 100644 tests/Images/Input/Pbm/grayscale_plain_normalized.pgm create mode 100644 tests/Images/Input/Pbm/rgb_plain.ppm create mode 100644 tests/Images/Input/Pbm/rgb_plain_normalized.ppm create mode 100644 tests/Images/Input/Pbm/rings.pgm diff --git a/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L16_Gene-UP WebSocket RunImageMask.png b/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L16_Gene-UP WebSocket RunImageMask.png new file mode 100644 index 000000000..09bb074a3 --- /dev/null +++ b/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L16_Gene-UP WebSocket RunImageMask.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:78fc668be9f82c01c277cb2560253b04a1ff74a5af4daaf19327591420a71fec +size 4521 diff --git a/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L8_blackandwhite_binary.png b/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L8_blackandwhite_binary.png new file mode 100644 index 000000000..d1f1515bb --- /dev/null +++ b/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L8_blackandwhite_binary.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1339a8170408a7bcde261617cc599587c8f25c4dc94f780976ee1638879888e9 +size 147 diff --git a/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L8_blackandwhite_plain.png b/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L8_blackandwhite_plain.png new file mode 100644 index 000000000..372261923 --- /dev/null +++ b/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L8_blackandwhite_plain.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:82d0397f38971cf90d7c064db332093e686196e244ece1196cca2071d27f0a6f +size 147 diff --git a/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L8_grayscale_plain_normalized.png b/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L8_grayscale_plain_normalized.png new file mode 100644 index 000000000..9c86c2fc1 --- /dev/null +++ b/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L8_grayscale_plain_normalized.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f8e8b8a1a05e76b1eeb577373c3a6f492e356f0dd58489afded248415cec4a07 +size 145 diff --git a/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L8_rings.png b/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L8_rings.png new file mode 100644 index 000000000..acf751c28 --- /dev/null +++ b/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L8_rings.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:388c86b3dd472ef17fb911ae424b81baeeeff74c4161cf5825eab50698d54348 +size 27884 diff --git a/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_Rgb24_00000_00000.png b/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_Rgb24_00000_00000.png new file mode 100644 index 000000000..49cc74f3f --- /dev/null +++ b/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_Rgb24_00000_00000.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2e3fc46b9f0546941ef95be7b750fb29376a679a921f2581403882b0e76e9caf +size 2250 diff --git a/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_Rgb24_rgb_plain_normalized.png b/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_Rgb24_rgb_plain_normalized.png new file mode 100644 index 000000000..421a59849 --- /dev/null +++ b/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_Rgb24_rgb_plain_normalized.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c44322c4bf461acea27053057f5241afb029d9a1e66e94dcf1be6f86f7f97727 +size 152 diff --git a/tests/Images/Input/Pbm/00000_00000.ppm b/tests/Images/Input/Pbm/00000_00000.ppm new file mode 100644 index 000000000..321188762 --- /dev/null +++ b/tests/Images/Input/Pbm/00000_00000.ppm @@ -0,0 +1,4 @@ +P6 +29 30 +255 +KNPJLNVWTl^UtrnryysɻܫmpCARVbmY[aKOPDKKAEDBCBSTVPPRZYTk_{YQUZϧ~ѰɊʇR?NQ[ug\kTQVIMNLNKPPNNNPVUV]Z[xzkfD6ڹŕyݩbkbhberZ[^SSHJHIJENNJJKM[SSn\duQP[G㾵ؐFOL9oc}`ZKHBIJCIOJGJG`QHb`swIHrkϸدңΘˎy^mJH6"RHnnULJIKHP]\EJBxfTuaXA@Y_Ӂtujk``XVPNLJHED@A=?;>:y=9m=8x>7?1S=LDfkSPRJJJiknempmlB6A=@DAECGEJHOHNHNKNOOUW[_clky]`rkrlsorjqf}KHw_cHJJLIFh__{lmgrtw{}ɉ؎䐟쟵Ս|lalVPcQOZML_KJeJKTGKEEDJHBPLJo|xeq_kxbo}tttt``LLMPOTdkyiqgo```YYPWWRXVTRNNIFHIGGHGDJJHȻіoq\fJ\|f_ryXt]S^J;A9HGONIHCwvޮڳًaCBC}Pqe_nTSQOSQSURLLHNMGZWRţ~|kMWWJ[|T^xla~LVldŎ˱խýzy}сMQPZyhl]WW\a`Y[YPOLVSO[VQǎwWJJ:z`deuPOMRԝmwPmǟ}hڝYaG:qkvabkpp^a_QRPSSQ\[VaVUGvmslt@>gk٣ƺvWp^kf©zo|?9UTkmbhhY]\RUTRTT`b`r^daTwut@<ʁȾǕy˶nvճ۠@AWYmq]abX[ZUXXSUVZ\\|sqvpm}~|~x~}@<̔vq~~wǭƘ}AAZ[orX[[WZVUXTTWS[^Zlrthjndciffnhjfw}sD@pv󚗳lurxѵϑ?>^_jmVVTYZSVYQZ]T^aXlgHHX[él[[}Ĉuk۽ʺkl>4RNfg[YWZZUZ]W]`Y^aZĭëcgAAtq֨t~wjµļEOS?yor]\_\Z[[XWYUZ[V]]X­nvkxqyYOF8ɉt̰⡰_gckhplfjYTU^Z[a`bUWWUURXUQlvSk]n^q][BE*ʆhcK]cyX|YThTRV^^cWX_SUXOQPSUR|Y}}db|gI`Oj{Jm^OS?fOy_\K@7RTdrkhӇ裷Ähk]hkSeTOYPPSZ^bNQWLORHMNIQOU?OduOlKp`J_Fsw]d`lNRMI}MFQGVNoisjzcVWOKLRRT[_cMOUSTXJNQNUToĮX^:DO4mNveFlNNrUYx]b|l|jdhaztz~lkz[Y`NKPOORTXZLNOOOOMPPNTRLyWgnUW]M\|je^c}]h~bngmuy}}}{|wljy\[iMLUJJOPRRQRNRRNRSOQTPo|qkshjkdz}y}yziprnnhuoqup{okvjiuRS[FFJJJJOOKMNJNNI[[Wzpy|suvvruoothmrdkq`inbhmcgfekcKTKdla}[cinmasmugcm]Z`JHKKIIUTP^^Yab[cgc[_c[bgJUYDHKMJLTLM^QU]W^Z[`__bXVXJMNIRQLUQXaipmfumphah]V[PKOLHH]ZWge_nqh`hbUTW_ek=JOAGLEDESOMc[^ZW`RSXZZ\cbhQR]LPVNTVT_jfkhnnmb^ce^cWRWIGHQPMff_cfZZaY \ No newline at end of file diff --git a/tests/Images/Input/Pbm/Gene-UP WebSocket RunImageMask.pgm b/tests/Images/Input/Pbm/Gene-UP WebSocket RunImageMask.pgm new file mode 100644 index 0000000000000000000000000000000000000000..8265eaa50621a9a5455776fbe2c5faeb5933b862 GIT binary patch literal 614417 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 UfB_6(00S7n00uCCfxLnL0M1c2-v9sr literal 0 HcmV?d00001 diff --git a/tests/Images/Input/Pbm/blackandwhite_binary.pbm b/tests/Images/Input/Pbm/blackandwhite_binary.pbm new file mode 100644 index 000000000..a25b1d350 --- /dev/null +++ b/tests/Images/Input/Pbm/blackandwhite_binary.pbm @@ -0,0 +1,3 @@ +P4 +# CREATOR: bitmap2pbm Version 1.0.0 +8 4 @0@0 diff --git a/tests/Images/Input/Pbm/blackandwhite_plain.pbm b/tests/Images/Input/Pbm/blackandwhite_plain.pbm new file mode 100644 index 000000000..fea8cafd0 --- /dev/null +++ b/tests/Images/Input/Pbm/blackandwhite_plain.pbm @@ -0,0 +1,10 @@ +P1 +# PBM example +24 7 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 1 1 1 1 0 0 1 1 1 1 0 0 1 1 1 1 0 0 1 1 1 1 0 +0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 1 0 +0 1 1 1 0 0 0 1 1 1 0 0 0 1 1 1 0 0 0 1 1 1 1 0 +0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 +0 1 0 0 0 0 0 1 1 1 1 0 0 1 1 1 1 0 0 1 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 \ No newline at end of file diff --git a/tests/Images/Input/Pbm/grayscale_plain.pgm b/tests/Images/Input/Pbm/grayscale_plain.pgm new file mode 100644 index 000000000..ba4757248 --- /dev/null +++ b/tests/Images/Input/Pbm/grayscale_plain.pgm @@ -0,0 +1,10 @@ +P2 +24 7 +15 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 3 3 3 3 0 0 7 7 7 7 0 0 11 11 11 11 0 0 15 15 15 15 0 +0 3 0 0 0 0 0 7 0 0 0 0 0 11 0 0 0 0 0 15 0 0 15 0 +0 3 3 3 0 0 0 7 7 7 0 0 0 11 11 11 0 0 0 15 15 15 15 0 +0 3 0 0 0 0 0 7 0 0 0 0 0 11 0 0 0 0 0 15 0 0 0 0 +0 3 0 0 0 0 0 7 7 7 7 0 0 11 11 11 11 0 0 15 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 \ No newline at end of file diff --git a/tests/Images/Input/Pbm/grayscale_plain_normalized.pgm b/tests/Images/Input/Pbm/grayscale_plain_normalized.pgm new file mode 100644 index 000000000..fe0329629 --- /dev/null +++ b/tests/Images/Input/Pbm/grayscale_plain_normalized.pgm @@ -0,0 +1,10 @@ +P2 +24 7 +255 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 51 51 51 51 0 0 119 119 119 119 0 0 187 187 187 187 0 0 255 255 255 255 0 +0 51 0 0 0 0 0 119 0 0 0 0 0 187 0 0 0 0 0 255 0 0 255 0 +0 51 51 51 0 0 0 119 119 119 0 0 0 187 187 187 0 0 0 255 255 255 255 0 +0 51 0 0 0 0 0 119 0 0 0 0 0 187 0 0 0 0 0 255 0 0 0 0 +0 51 0 0 0 0 0 119 119 119 119 0 0 187 187 187 187 0 0 255 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 \ No newline at end of file diff --git a/tests/Images/Input/Pbm/rgb_plain.ppm b/tests/Images/Input/Pbm/rgb_plain.ppm new file mode 100644 index 000000000..ecd1b915c --- /dev/null +++ b/tests/Images/Input/Pbm/rgb_plain.ppm @@ -0,0 +1,8 @@ +P3 +# example from the man page +4 4 +15 + 0 0 0 0 0 0 0 0 0 15 0 15 + 0 0 0 0 15 7 0 0 0 0 0 0 + 0 0 0 0 0 0 0 15 7 0 0 0 +15 0 15 0 0 0 0 0 0 0 0 0 \ No newline at end of file diff --git a/tests/Images/Input/Pbm/rgb_plain_normalized.ppm b/tests/Images/Input/Pbm/rgb_plain_normalized.ppm new file mode 100644 index 000000000..628931579 --- /dev/null +++ b/tests/Images/Input/Pbm/rgb_plain_normalized.ppm @@ -0,0 +1,8 @@ +P3 +# example from the man page +4 4 +255 + 0 0 0 0 0 0 0 0 0 255 0 255 + 0 0 0 0 255 119 0 0 0 0 0 0 + 0 0 0 0 0 0 0 255 119 0 0 0 +255 0 255 0 0 0 0 0 0 0 0 0 \ No newline at end of file diff --git a/tests/Images/Input/Pbm/rings.pgm b/tests/Images/Input/Pbm/rings.pgm new file mode 100644 index 0000000000000000000000000000000000000000..e0d4b4ed4d4cfc4da44b131a68f60824957428b6 GIT binary patch literal 40038 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 Wa*AACLyF_*_)AQ-%Z&HTYW)|`Dr-*w literal 0 HcmV?d00001 From 9599efe5201dc516673000adecf1dd84b6976cf5 Mon Sep 17 00:00:00 2001 From: Ynse Hoornenborg Date: Mon, 29 Nov 2021 20:51:17 +0100 Subject: [PATCH 11/65] Update .gitattributes file --- .gitattributes | 8 ++++++-- shared-infrastructure | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/.gitattributes b/.gitattributes index 70ced6903..355b64dce 100644 --- a/.gitattributes +++ b/.gitattributes @@ -87,7 +87,6 @@ *.eot binary *.exe binary *.otf binary -*.pbm binary *.pdf binary *.ppt binary *.pptx binary @@ -95,7 +94,6 @@ *.snk binary *.ttc binary *.ttf binary -*.wbmp binary *.woff binary *.woff2 binary *.xls binary @@ -126,3 +124,9 @@ *.dds filter=lfs diff=lfs merge=lfs -text *.ktx filter=lfs diff=lfs merge=lfs -text *.ktx2 filter=lfs diff=lfs merge=lfs -text +*.pam filter=lfs diff=lfs merge=lfs -text +*.pbm filter=lfs diff=lfs merge=lfs -text +*.pgm filter=lfs diff=lfs merge=lfs -text +*.ppm filter=lfs diff=lfs merge=lfs -text +*.pnm filter=lfs diff=lfs merge=lfs -text +*.wbmp filter=lfs diff=lfs merge=lfs -text diff --git a/shared-infrastructure b/shared-infrastructure index a042aba17..59ce17f5a 160000 --- a/shared-infrastructure +++ b/shared-infrastructure @@ -1 +1 @@ -Subproject commit a042aba176cdb840d800c6ed4cfe41a54fb7b1e3 +Subproject commit 59ce17f5a4e1f956811133f41add7638e74c2836 From cf8e1841fc757faf77b87751d13715891be43d6c Mon Sep 17 00:00:00 2001 From: Ynse Hoornenborg Date: Tue, 30 Nov 2021 21:23:04 +0100 Subject: [PATCH 12/65] Revert stack allocation in Plain Encoder --- src/ImageSharp/Formats/Pbm/PlainEncoder.cs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/ImageSharp/Formats/Pbm/PlainEncoder.cs b/src/ImageSharp/Formats/Pbm/PlainEncoder.cs index e362f8680..b67f0a077 100644 --- a/src/ImageSharp/Formats/Pbm/PlainEncoder.cs +++ b/src/ImageSharp/Formats/Pbm/PlainEncoder.cs @@ -15,7 +15,6 @@ namespace SixLabors.ImageSharp.Formats.Pbm /// internal class PlainEncoder { - private const int MaxLineLength = 70; private const byte NewLine = 0x0a; private const byte Space = 0x20; private const byte Zero = 0x30; @@ -77,7 +76,8 @@ namespace SixLabors.ImageSharp.Formats.Pbm MemoryAllocator allocator = configuration.MemoryAllocator; using IMemoryOwner row = allocator.Allocate(width); Span rowSpan = row.GetSpan(); - Span plainSpan = stackalloc byte[width * MaxCharsPerPixelGrayscale]; + IMemoryOwner plainMemory = allocator.Allocate(width * MaxCharsPerPixelGrayscale); + Span plainSpan = plainMemory.GetSpan(); for (int y = 0; y < height; y++) { @@ -108,7 +108,8 @@ namespace SixLabors.ImageSharp.Formats.Pbm MemoryAllocator allocator = configuration.MemoryAllocator; using IMemoryOwner row = allocator.Allocate(width); Span rowSpan = row.GetSpan(); - Span plainSpan = stackalloc byte[width * MaxCharsPerPixelGrayscaleWide]; + IMemoryOwner plainMemory = allocator.Allocate(width * MaxCharsPerPixelGrayscaleWide); + Span plainSpan = plainMemory.GetSpan(); for (int y = 0; y < height; y++) { @@ -139,7 +140,8 @@ namespace SixLabors.ImageSharp.Formats.Pbm MemoryAllocator allocator = configuration.MemoryAllocator; using IMemoryOwner row = allocator.Allocate(width); Span rowSpan = row.GetSpan(); - Span plainSpan = stackalloc byte[width * MaxCharsPerPixelRgb]; + IMemoryOwner plainMemory = allocator.Allocate(width * MaxCharsPerPixelRgb); + Span plainSpan = plainMemory.GetSpan(); for (int y = 0; y < height; y++) { @@ -176,7 +178,8 @@ namespace SixLabors.ImageSharp.Formats.Pbm MemoryAllocator allocator = configuration.MemoryAllocator; using IMemoryOwner row = allocator.Allocate(width); Span rowSpan = row.GetSpan(); - Span plainSpan = stackalloc byte[width * MaxCharsPerPixelRgbWide]; + IMemoryOwner plainMemory = allocator.Allocate(width * MaxCharsPerPixelRgbWide); + Span plainSpan = plainMemory.GetSpan(); for (int y = 0; y < height; y++) { @@ -213,7 +216,8 @@ namespace SixLabors.ImageSharp.Formats.Pbm MemoryAllocator allocator = configuration.MemoryAllocator; using IMemoryOwner row = allocator.Allocate(width); Span rowSpan = row.GetSpan(); - Span plainSpan = stackalloc byte[width * MaxCharsPerPixelBlackAndWhite]; + IMemoryOwner plainMemory = allocator.Allocate(width * MaxCharsPerPixelBlackAndWhite); + Span plainSpan = plainMemory.GetSpan(); for (int y = 0; y < height; y++) { From 7617b38fec1246c664c172cc3e5cd2468fd86535 Mon Sep 17 00:00:00 2001 From: Dmitry Pentin Date: Wed, 1 Dec 2021 07:39:28 +0300 Subject: [PATCH 13/65] Base implementation for new converters --- ...egColorConverter.Avx2JpegColorConverter.cs | 18 --- ...gColorConverter.BasicJpegColorConverter.cs | 18 --- ...2.cs => JpegColorConverter.FromCmykAvx.cs} | 28 ++--- ...s => JpegColorConverter.FromCmykScalar.cs} | 9 +- .../JpegColorConverter.FromCmykVector8.cs | 25 ++--- ...=> JpegColorConverter.FromGrayScaleAvx.cs} | 22 ++-- .../JpegColorConverter.FromGrayScaleBasic.cs | 53 --------- .../JpegColorConverter.FromGrayScaleScalar.cs | 34 ++++++ ...JpegColorConverter.FromGrayScaleVector8.cs | 38 +++++++ ...x2.cs => JpegColorConverter.FromRgbAvx.cs} | 28 ++--- .../JpegColorConverter.FromRgbBasic.cs | 32 ------ .../JpegColorConverter.FromRgbScalar.cs | 26 +++++ .../JpegColorConverter.FromRgbVector8.cs | 11 +- ....cs => JpegColorConverter.FromYCbCrAvx.cs} | 33 ++---- .../JpegColorConverter.FromYCbCrBasic.cs | 42 ------- .../JpegColorConverter.FromYCbCrScalar.cs | 50 +++++++++ .../JpegColorConverter.FromYCbCrVector4.cs | 88 --------------- .../JpegColorConverter.FromYCbCrVector8.cs | 22 ++-- ...2.cs => JpegColorConverter.FromYccKAvx.cs} | 30 ++--- ...s => JpegColorConverter.FromYccKScalar.cs} | 13 +-- .../JpegColorConverter.FromYccKVector8.cs | 28 +++-- ...olorConverter.Vector8JpegColorConverter.cs | 18 --- .../ColorConverters/JpegColorConverterAvx.cs | 32 ++++++ ...Converter.cs => JpegColorConverterBase.cs} | 104 +++++++++--------- .../JpegColorConverterScalar.cs | 22 ++++ ...nverter.cs => JpegColorConverterVector.cs} | 27 +++-- .../Components/Decoder/SpectralConverter.cs | 2 +- .../Decoder/SpectralConverter{TPixel}.cs | 4 +- .../Decompressors/RgbJpegSpectralConverter.cs | 2 +- .../ColorConversion/CmykColorConversion.cs | 12 +- .../GrayscaleColorConversion.cs | 8 +- .../ColorConversion/RgbColorConversion.cs | 12 +- .../ColorConversion/YCbCrColorConversion.cs | 16 +-- .../ColorConversion/YccKColorConverter.cs | 12 +- .../Formats/Jpg/JpegColorConverterTests.cs | 76 +++++-------- 35 files changed, 432 insertions(+), 563 deletions(-) delete mode 100644 src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.Avx2JpegColorConverter.cs delete mode 100644 src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.BasicJpegColorConverter.cs rename src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/{JpegColorConverter.FromCmykAvx2.cs => JpegColorConverter.FromCmykAvx.cs} (58%) rename src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/{JpegColorConverter.FromCmykBasic.cs => JpegColorConverter.FromCmykScalar.cs} (83%) rename src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/{JpegColorConverter.FromGrayScaleAvx2.cs => JpegColorConverter.FromGrayScaleAvx.cs} (62%) delete mode 100644 src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleBasic.cs create mode 100644 src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleScalar.cs create mode 100644 src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleVector8.cs rename src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/{JpegColorConverter.FromRgbAvx2.cs => JpegColorConverter.FromRgbAvx.cs} (56%) delete mode 100644 src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbBasic.cs create mode 100644 src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbScalar.cs rename src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/{JpegColorConverter.FromYCbCrAvx2.cs => JpegColorConverter.FromYCbCrAvx.cs} (71%) delete mode 100644 src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrBasic.cs create mode 100644 src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrScalar.cs delete mode 100644 src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrVector4.cs rename src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/{JpegColorConverter.FromYccKAvx2.cs => JpegColorConverter.FromYccKAvx.cs} (79%) rename src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/{JpegColorConverter.FromYccKBasic.cs => JpegColorConverter.FromYccKScalar.cs} (81%) delete mode 100644 src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.Vector8JpegColorConverter.cs create mode 100644 src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterAvx.cs rename src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/{JpegColorConverter.cs => JpegColorConverterBase.cs} (67%) create mode 100644 src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterScalar.cs rename src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/{JpegColorConverter.VectorizedJpegColorConverter.cs => JpegColorConverterVector.cs} (64%) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.Avx2JpegColorConverter.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.Avx2JpegColorConverter.cs deleted file mode 100644 index 90ebce3b8..000000000 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.Avx2JpegColorConverter.cs +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Apache License, Version 2.0. - -namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters -{ - internal abstract partial class JpegColorConverter - { - internal abstract class Avx2JpegColorConverter : VectorizedJpegColorConverter - { - protected Avx2JpegColorConverter(JpegColorSpace colorSpace, int precision) - : base(colorSpace, precision, 8) - { - } - - protected sealed override bool IsAvailable => SimdUtils.HasAvx2; - } - } -} diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.BasicJpegColorConverter.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.BasicJpegColorConverter.cs deleted file mode 100644 index ed2e2cd76..000000000 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.BasicJpegColorConverter.cs +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Apache License, Version 2.0. - -namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters -{ - internal abstract partial class JpegColorConverter - { - internal abstract class BasicJpegColorConverter : JpegColorConverter - { - protected BasicJpegColorConverter(JpegColorSpace colorSpace, int precision) - : base(colorSpace, precision) - { - } - - protected override bool IsAvailable => true; - } - } -} diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykAvx2.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykAvx.cs similarity index 58% rename from src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykAvx2.cs rename to src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykAvx.cs index 216c12735..2671dec70 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykAvx2.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykAvx.cs @@ -1,38 +1,33 @@ // Copyright (c) Six Labors. // Licensed under the Apache License, Version 2.0. -using System; -using System.Numerics; +#if SUPPORTS_RUNTIME_INTRINSICS using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -#if SUPPORTS_RUNTIME_INTRINSICS using System.Runtime.Intrinsics; using System.Runtime.Intrinsics.X86; -using static SixLabors.ImageSharp.SimdUtils; -#endif namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { - internal abstract partial class JpegColorConverter + internal abstract partial class JpegColorConverterBase { - internal sealed class FromCmykAvx2 : Avx2JpegColorConverter + internal sealed class FromCmykAvx : AvxColorConverter { - public FromCmykAvx2(int precision) + public FromCmykAvx(int precision) : base(JpegColorSpace.Cmyk, precision) { } - protected override void ConvertCoreVectorizedInplace(in ComponentValues values) + public override void ConvertToRgbInplace(in ComponentValues values) { -#if SUPPORTS_RUNTIME_INTRINSICS ref Vector256 c0Base = - ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component0)); + ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component0)); ref Vector256 c1Base = - ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component1)); + ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component1)); ref Vector256 c2Base = - ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component2)); + ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component2)); ref Vector256 c3Base = - ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component3)); + ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component3)); // Used for the color conversion var scale = Vector256.Create(1 / this.MaximumValue); @@ -50,11 +45,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters m = Avx.Multiply(Avx.Multiply(m, k), scale); y = Avx.Multiply(Avx.Multiply(y, k), scale); } -#endif } - - protected override void ConvertCoreInplace(in ComponentValues values) => - FromCmykBasic.ConvertCoreInplace(values, this.MaximumValue); } } } +#endif diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykBasic.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykScalar.cs similarity index 83% rename from src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykBasic.cs rename to src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykScalar.cs index b0ad50301..057d7846a 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykBasic.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykScalar.cs @@ -1,16 +1,15 @@ -// Copyright (c) Six Labors. +// Copyright (c) Six Labors. // Licensed under the Apache License, Version 2.0. using System; -using System.Numerics; namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { - internal abstract partial class JpegColorConverter + internal abstract partial class JpegColorConverterBase { - internal sealed class FromCmykBasic : BasicJpegColorConverter + internal sealed class FromCmykScalar : ScalarJpegColorConverter { - public FromCmykBasic(int precision) + public FromCmykScalar(int precision) : base(JpegColorSpace.Cmyk, precision) { } diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykVector8.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykVector8.cs index 0da4c9ec2..685e25aad 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykVector8.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykVector8.cs @@ -1,17 +1,15 @@ -// Copyright (c) Six Labors. +// Copyright (c) Six Labors. // Licensed under the Apache License, Version 2.0. -using System; using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using SixLabors.ImageSharp.Tuples; namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { - internal abstract partial class JpegColorConverter + internal abstract partial class JpegColorConverterBase { - internal sealed class FromCmykVector8 : Vector8JpegColorConverter + internal sealed class FromCmykVector8 : VectorizedJpegColorConverter { public FromCmykVector8(int precision) : base(JpegColorSpace.Cmyk, precision) @@ -21,17 +19,16 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters protected override void ConvertCoreVectorizedInplace(in ComponentValues values) { ref Vector cBase = - ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component0)); + ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component0)); ref Vector mBase = - ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component1)); + ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component1)); ref Vector yBase = - ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component2)); + ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component2)); ref Vector kBase = - ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component3)); + ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component3)); var scale = new Vector(1 / this.MaximumValue); - // Walking 8 elements at one step: nint n = values.Component0.Length / 8; for (nint i = 0; i < n; i++) { @@ -40,14 +37,14 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters ref Vector y = ref Unsafe.Add(ref yBase, i); Vector k = Unsafe.Add(ref kBase, i) * scale; - c = (c * k) * scale; - m = (m * k) * scale; - y = (y * k) * scale; + c = c * k * scale; + m = m * k * scale; + y = y * k * scale; } } protected override void ConvertCoreInplace(in ComponentValues values) => - FromCmykBasic.ConvertCoreInplace(values, this.MaximumValue); + FromCmykScalar.ConvertCoreInplace(values, this.MaximumValue); } } } diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleAvx2.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleAvx.cs similarity index 62% rename from src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleAvx2.cs rename to src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleAvx.cs index eca6b6292..38b159bba 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleAvx2.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleAvx.cs @@ -1,30 +1,25 @@ -// Copyright (c) Six Labors. +// Copyright (c) Six Labors. // Licensed under the Apache License, Version 2.0. -using System; -using System.Numerics; +#if SUPPORTS_RUNTIME_INTRINSICS using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -#if SUPPORTS_RUNTIME_INTRINSICS using System.Runtime.Intrinsics; using System.Runtime.Intrinsics.X86; -using static SixLabors.ImageSharp.SimdUtils; -#endif namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { - internal abstract partial class JpegColorConverter + internal abstract partial class JpegColorConverterBase { - internal sealed class FromGrayscaleAvx2 : Avx2JpegColorConverter + internal sealed class FromGrayscaleAvx : AvxColorConverter { - public FromGrayscaleAvx2(int precision) + public FromGrayscaleAvx(int precision) : base(JpegColorSpace.Grayscale, precision) { } - protected override void ConvertCoreVectorizedInplace(in ComponentValues values) + public override void ConvertToRgbInplace(in ComponentValues values) { -#if SUPPORTS_RUNTIME_INTRINSICS ref Vector256 c0Base = ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component0)); @@ -37,11 +32,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters ref Vector256 c0 = ref Unsafe.Add(ref c0Base, i); c0 = Avx.Multiply(c0, scale); } -#endif } - - protected override void ConvertCoreInplace(in ComponentValues values) => - FromGrayscaleBasic.ScaleValues(values.Component0, this.MaximumValue); } } } +#endif diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleBasic.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleBasic.cs deleted file mode 100644 index 76d57bf06..000000000 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleBasic.cs +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Apache License, Version 2.0. - -using System; -using System.Numerics; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters -{ - internal abstract partial class JpegColorConverter - { - internal sealed class FromGrayscaleBasic : BasicJpegColorConverter - { - public FromGrayscaleBasic(int precision) - : base(JpegColorSpace.Grayscale, precision) - { - } - - public override void ConvertToRgbInplace(in ComponentValues values) => - ScaleValues(values.Component0, this.MaximumValue); - - internal static void ScaleValues(Span values, float maxValue) - { - Span vecValues = MemoryMarshal.Cast(values); - - var scaleVector = new Vector4(1 / maxValue); - - for (int i = 0; i < vecValues.Length; i++) - { - vecValues[i] *= scaleVector; - } - - values = values.Slice(vecValues.Length * 4); - if (!values.IsEmpty) - { - float scaleValue = 1f / maxValue; - values[0] *= scaleValue; - - if ((uint)values.Length > 1) - { - values[1] *= scaleValue; - - if ((uint)values.Length > 2) - { - values[2] *= scaleValue; - } - } - } - } - } - } -} diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleScalar.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleScalar.cs new file mode 100644 index 000000000..18ac5ff99 --- /dev/null +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleScalar.cs @@ -0,0 +1,34 @@ +// Copyright (c) Six Labors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters +{ + internal abstract partial class JpegColorConverterBase + { + internal sealed class FromGrayscaleScalar : ScalarJpegColorConverter + { + public FromGrayscaleScalar(int precision) + : base(JpegColorSpace.Grayscale, precision) + { + } + + public override void ConvertToRgbInplace(in ComponentValues values) => + ConvertCoreInplace(values.Component0, this.MaximumValue); + + internal static void ConvertCoreInplace(Span values, float maxValue) + { + ref float valuesRef = ref MemoryMarshal.GetReference(values); + float scale = 1 / maxValue; + + for (nint i = 0; i < values.Length; i++) + { + Unsafe.Add(ref valuesRef, i) *= scale; + } + } + } + } +} diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleVector8.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleVector8.cs new file mode 100644 index 000000000..6aa0b59a9 --- /dev/null +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleVector8.cs @@ -0,0 +1,38 @@ +// Copyright (c) Six Labors. +// Licensed under the Apache License, Version 2.0. + +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters +{ + internal abstract partial class JpegColorConverterBase + { + internal sealed class FromGrayScaleVector8 : VectorizedJpegColorConverter + { + public FromGrayScaleVector8(int precision) + : base(JpegColorSpace.Grayscale, precision) + { + } + + protected override void ConvertCoreVectorizedInplace(in ComponentValues values) + { + ref Vector cBase = + ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component0)); + + var scale = new Vector(1 / this.MaximumValue); + + nint n = values.Component0.Length / 8; + for (nint i = 0; i < n; i++) + { + ref Vector c0 = ref Unsafe.Add(ref cBase, i); + c0 *= scale; + } + } + + protected override void ConvertCoreInplace(in ComponentValues values) => + FromGrayscaleScalar.ConvertCoreInplace(values.Component0, this.MaximumValue); + } + } +} diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbAvx2.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbAvx.cs similarity index 56% rename from src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbAvx2.cs rename to src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbAvx.cs index 557e4e417..31c573903 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbAvx2.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbAvx.cs @@ -1,36 +1,31 @@ -// Copyright (c) Six Labors. +// Copyright (c) Six Labors. // Licensed under the Apache License, Version 2.0. -using System; -using System.Numerics; +#if SUPPORTS_RUNTIME_INTRINSICS using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -#if SUPPORTS_RUNTIME_INTRINSICS using System.Runtime.Intrinsics; using System.Runtime.Intrinsics.X86; -using static SixLabors.ImageSharp.SimdUtils; -#endif namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { - internal abstract partial class JpegColorConverter + internal abstract partial class JpegColorConverterBase { - internal sealed class FromRgbAvx2 : Avx2JpegColorConverter + internal sealed class FromRgbAvx : AvxColorConverter { - public FromRgbAvx2(int precision) + public FromRgbAvx(int precision) : base(JpegColorSpace.RGB, precision) { } - protected override void ConvertCoreVectorizedInplace(in ComponentValues values) + public override void ConvertToRgbInplace(in ComponentValues values) { -#if SUPPORTS_RUNTIME_INTRINSICS ref Vector256 rBase = - ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component0)); + ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component0)); ref Vector256 gBase = - ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component1)); + ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component1)); ref Vector256 bBase = - ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component2)); + ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component2)); // Used for the color conversion var scale = Vector256.Create(1 / this.MaximumValue); @@ -44,11 +39,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters g = Avx.Multiply(g, scale); b = Avx.Multiply(b, scale); } -#endif } - - protected override void ConvertCoreInplace(in ComponentValues values) => - FromRgbBasic.ConvertCoreInplace(values, this.MaximumValue); } } } +#endif diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbBasic.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbBasic.cs deleted file mode 100644 index 1425e7b58..000000000 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbBasic.cs +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Apache License, Version 2.0. - -using System; -using System.Numerics; -using System.Runtime.InteropServices; - -namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters -{ - internal abstract partial class JpegColorConverter - { - internal sealed class FromRgbBasic : BasicJpegColorConverter - { - public FromRgbBasic(int precision) - : base(JpegColorSpace.RGB, precision) - { - } - - public override void ConvertToRgbInplace(in ComponentValues values) - { - ConvertCoreInplace(values, this.MaximumValue); - } - - internal static void ConvertCoreInplace(ComponentValues values, float maxValue) - { - FromGrayscaleBasic.ScaleValues(values.Component0, maxValue); - FromGrayscaleBasic.ScaleValues(values.Component1, maxValue); - FromGrayscaleBasic.ScaleValues(values.Component2, maxValue); - } - } - } -} diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbScalar.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbScalar.cs new file mode 100644 index 000000000..83861d1e2 --- /dev/null +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbScalar.cs @@ -0,0 +1,26 @@ +// Copyright (c) Six Labors. +// Licensed under the Apache License, Version 2.0. + +namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters +{ + internal abstract partial class JpegColorConverterBase + { + internal sealed class FromRgbScalar : ScalarJpegColorConverter + { + public FromRgbScalar(int precision) + : base(JpegColorSpace.RGB, precision) + { + } + + public override void ConvertToRgbInplace(in ComponentValues values) => + ConvertCoreInplace(values, this.MaximumValue); + + internal static void ConvertCoreInplace(ComponentValues values, float maxValue) + { + FromGrayscaleScalar.ConvertCoreInplace(values.Component0, maxValue); + FromGrayscaleScalar.ConvertCoreInplace(values.Component1, maxValue); + FromGrayscaleScalar.ConvertCoreInplace(values.Component2, maxValue); + } + } + } +} diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbVector8.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbVector8.cs index a00361d97..0dc440b7d 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbVector8.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbVector8.cs @@ -1,17 +1,15 @@ -// Copyright (c) Six Labors. +// Copyright (c) Six Labors. // Licensed under the Apache License, Version 2.0. -using System; using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using SixLabors.ImageSharp.Tuples; namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { - internal abstract partial class JpegColorConverter + internal abstract partial class JpegColorConverterBase { - internal sealed class FromRgbVector8 : Vector8JpegColorConverter + internal sealed class FromRgbVector8 : VectorizedJpegColorConverter { public FromRgbVector8(int precision) : base(JpegColorSpace.RGB, precision) @@ -29,7 +27,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters var scale = new Vector(1 / this.MaximumValue); - // Walking 8 elements at one step: nint n = values.Component0.Length / 8; for (nint i = 0; i < n; i++) { @@ -43,7 +40,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters } protected override void ConvertCoreInplace(in ComponentValues values) => - FromRgbBasic.ConvertCoreInplace(values, this.MaximumValue); + FromRgbScalar.ConvertCoreInplace(values, this.MaximumValue); } } } diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrAvx2.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrAvx.cs similarity index 71% rename from src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrAvx2.cs rename to src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrAvx.cs index 5aae1faa2..1bf1c4461 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrAvx2.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrAvx.cs @@ -1,31 +1,27 @@ // Copyright (c) Six Labors. // Licensed under the Apache License, Version 2.0. -using System; -using System.Numerics; +#if SUPPORTS_RUNTIME_INTRINSICS using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -#if SUPPORTS_RUNTIME_INTRINSICS using System.Runtime.Intrinsics; using System.Runtime.Intrinsics.X86; using static SixLabors.ImageSharp.SimdUtils; -#endif // ReSharper disable ImpureMethodCallOnReadonlyValueField namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { - internal abstract partial class JpegColorConverter + internal abstract partial class JpegColorConverterBase { - internal sealed class FromYCbCrAvx2 : Avx2JpegColorConverter + internal sealed class FromYCbCrAvx : AvxColorConverter { - public FromYCbCrAvx2(int precision) + public FromYCbCrAvx(int precision) : base(JpegColorSpace.YCbCr, precision) { } - protected override void ConvertCoreVectorizedInplace(in ComponentValues values) + public override void ConvertToRgbInplace(in ComponentValues values) { -#if SUPPORTS_RUNTIME_INTRINSICS ref Vector256 c0Base = ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component0)); ref Vector256 c1Base = @@ -36,15 +32,10 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters // Used for the color conversion var chromaOffset = Vector256.Create(-this.HalfValue); var scale = Vector256.Create(1 / this.MaximumValue); - var rCrMult = Vector256.Create(1.402F); - var gCbMult = Vector256.Create(-0.344136F); - var gCrMult = Vector256.Create(-0.714136F); - var bCbMult = Vector256.Create(1.772F); - - // Used for packing. - var va = Vector256.Create(1F); - ref byte control = ref MemoryMarshal.GetReference(HwIntrinsics.PermuteMaskEvenOdd8x32); - Vector256 vcontrol = Unsafe.As>(ref control); + var rCrMult = Vector256.Create(FromYCbCrScalar.RCrMult); + var gCbMult = Vector256.Create(-FromYCbCrScalar.GCbMult); + var gCrMult = Vector256.Create(-FromYCbCrScalar.GCrMult); + var bCbMult = Vector256.Create(FromYCbCrScalar.BCbMult); // Walking 8 elements at one step: nint n = values.Component0.Length / 8; @@ -64,7 +55,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters // r = y + (1.402F * cr); // g = y - (0.344136F * cb) - (0.714136F * cr); // b = y + (1.772F * cb); - // Adding & multiplying 8 elements at one time: Vector256 r = HwIntrinsics.MultiplyAdd(y, cr, rCrMult); Vector256 g = HwIntrinsics.MultiplyAdd(HwIntrinsics.MultiplyAdd(y, cb, gCbMult), cr, gCrMult); Vector256 b = HwIntrinsics.MultiplyAdd(y, cb, bCbMult); @@ -77,11 +67,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters c1 = g; c2 = b; } -#endif } - - protected override void ConvertCoreInplace(in ComponentValues values) => - FromYCbCrBasic.ConvertCoreInplace(values, this.MaximumValue, this.HalfValue); } } } +#endif diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrBasic.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrBasic.cs deleted file mode 100644 index 990d29aa0..000000000 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrBasic.cs +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Apache License, Version 2.0. - -using System; -using System.Numerics; - -namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters -{ - internal abstract partial class JpegColorConverter - { - internal sealed class FromYCbCrBasic : BasicJpegColorConverter - { - public FromYCbCrBasic(int precision) - : base(JpegColorSpace.YCbCr, precision) - { - } - - public override void ConvertToRgbInplace(in ComponentValues values) - => ConvertCoreInplace(values, this.MaximumValue, this.HalfValue); - - internal static void ConvertCoreInplace(in ComponentValues values, float maxValue, float halfValue) - { - Span c0 = values.Component0; - Span c1 = values.Component1; - Span c2 = values.Component2; - - var scale = 1 / maxValue; - - for (int i = 0; i < c0.Length; i++) - { - float y = c0[i]; - float cb = c1[i] - halfValue; - float cr = c2[i] - halfValue; - - c0[i] = MathF.Round(y + (1.402F * cr), MidpointRounding.AwayFromZero) * scale; - c1[i] = MathF.Round(y - (0.344136F * cb) - (0.714136F * cr), MidpointRounding.AwayFromZero) * scale; - c2[i] = MathF.Round(y + (1.772F * cb), MidpointRounding.AwayFromZero) * scale; - } - } - } - } -} diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrScalar.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrScalar.cs new file mode 100644 index 000000000..73c73970d --- /dev/null +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrScalar.cs @@ -0,0 +1,50 @@ +// Copyright (c) Six Labors. +// Licensed under the Apache License, Version 2.0. + +using System; + +namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters +{ + internal abstract partial class JpegColorConverterBase + { + internal sealed class FromYCbCrScalar : ScalarJpegColorConverter + { + // TODO: comments, derived from ITU-T Rec. T.871 + internal const float RCrMult = 1.402f; + internal const float GCbMult = (float)(0.114 * 1.772 / 0.587); + internal const float GCrMult = (float)(0.299 * 1.402 / 0.587); + internal const float BCbMult = 1.772f; + + public FromYCbCrScalar(int precision) + : base(JpegColorSpace.YCbCr, precision) + { + } + + public override void ConvertToRgbInplace(in ComponentValues values) + => ConvertCoreInplace(values, this.MaximumValue, this.HalfValue); + + internal static void ConvertCoreInplace(in ComponentValues values, float maxValue, float halfValue) + { + Span c0 = values.Component0; + Span c1 = values.Component1; + Span c2 = values.Component2; + + float scale = 1 / maxValue; + + for (int i = 0; i < c0.Length; i++) + { + float y = c0[i]; + float cb = c1[i] - halfValue; + float cr = c2[i] - halfValue; + + // r = y + (1.402F * cr); + // g = y - (0.344136F * cb) - (0.714136F * cr); + // b = y + (1.772F * cb); + c0[i] = MathF.Round(y + (RCrMult * cr), MidpointRounding.AwayFromZero) * scale; + c1[i] = MathF.Round(y - (GCbMult * cb) - (GCrMult * cr), MidpointRounding.AwayFromZero) * scale; + c2[i] = MathF.Round(y + (BCbMult * cb), MidpointRounding.AwayFromZero) * scale; + } + } + } + } +} diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrVector4.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrVector4.cs deleted file mode 100644 index 1ebc3e879..000000000 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrVector4.cs +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Apache License, Version 2.0. - -using System; -using System.Numerics; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using SixLabors.ImageSharp.Tuples; - -namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters -{ - internal abstract partial class JpegColorConverter - { - internal sealed class FromYCbCrVector4 : VectorizedJpegColorConverter - { - public FromYCbCrVector4(int precision) - : base(JpegColorSpace.YCbCr, precision, 8) - { - } - - protected override bool IsAvailable => SimdUtils.HasVector4; - - protected override void ConvertCoreVectorizedInplace(in ComponentValues values) - { - DebugGuard.IsTrue(values.Component0.Length % 8 == 0, nameof(values), "Length should be divisible by 8!"); - - ref Vector4Pair c0Base = - ref Unsafe.As(ref MemoryMarshal.GetReference(values.Component0)); - ref Vector4Pair c1Base = - ref Unsafe.As(ref MemoryMarshal.GetReference(values.Component1)); - ref Vector4Pair c2Base = - ref Unsafe.As(ref MemoryMarshal.GetReference(values.Component2)); - - var chromaOffset = new Vector4(-this.HalfValue); - var maxValue = this.MaximumValue; - - // Walking 8 elements at one step: - nint n = values.Component0.Length / 8; - - for (nint i = 0; i < n; i++) - { - // y = yVals[i]; - ref Vector4Pair c0 = ref Unsafe.Add(ref c0Base, i); - - // cb = cbVals[i] - halfValue); - ref Vector4Pair c1 = ref Unsafe.Add(ref c1Base, i); - c1.AddInplace(chromaOffset); - - // cr = crVals[i] - halfValue; - ref Vector4Pair c2 = ref Unsafe.Add(ref c2Base, i); - c2.AddInplace(chromaOffset); - - // r = y + (1.402F * cr); - Vector4Pair r = c0; - Vector4Pair tmp = c2; - tmp.MultiplyInplace(1.402F); - r.AddInplace(ref tmp); - - // g = y - (0.344136F * cb) - (0.714136F * cr); - Vector4Pair g = c0; - tmp = c1; - tmp.MultiplyInplace(-0.344136F); - g.AddInplace(ref tmp); - tmp = c2; - tmp.MultiplyInplace(-0.714136F); - g.AddInplace(ref tmp); - - // b = y + (1.772F * cb); - Vector4Pair b = c0; - tmp = c1; - tmp.MultiplyInplace(1.772F); - b.AddInplace(ref tmp); - - r.RoundAndDownscalePreVector8(maxValue); - g.RoundAndDownscalePreVector8(maxValue); - b.RoundAndDownscalePreVector8(maxValue); - - c0 = r; - c1 = g; - c2 = b; - } - } - - protected override void ConvertCoreInplace(in ComponentValues values) - => FromYCbCrBasic.ConvertCoreInplace(values, this.MaximumValue, this.HalfValue); - } - } -} diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrVector8.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrVector8.cs index a077b9ed8..da71e2466 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrVector8.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrVector8.cs @@ -1,18 +1,16 @@ // Copyright (c) Six Labors. // Licensed under the Apache License, Version 2.0. -using System; using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using SixLabors.ImageSharp.Tuples; // ReSharper disable ImpureMethodCallOnReadonlyValueField namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { - internal abstract partial class JpegColorConverter + internal abstract partial class JpegColorConverterBase { - internal sealed class FromYCbCrVector8 : Vector8JpegColorConverter + internal sealed class FromYCbCrVector8 : VectorizedJpegColorConverter { public FromYCbCrVector8(int precision) : base(JpegColorSpace.YCbCr, precision) @@ -30,10 +28,13 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters var chromaOffset = new Vector(-this.HalfValue); - // Walking 8 elements at one step: - nint n = values.Component0.Length / 8; var scale = new Vector(1 / this.MaximumValue); + var rCrMult = new Vector(FromYCbCrScalar.RCrMult); + var gCbMult = new Vector(-FromYCbCrScalar.GCbMult); + var gCrMult = new Vector(-FromYCbCrScalar.GCrMult); + var bCbMult = new Vector(FromYCbCrScalar.BCbMult); + nint n = values.Component0.Length / 8; for (nint i = 0; i < n; i++) { // y = yVals[i]; @@ -49,10 +50,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters // r = y + (1.402F * cr); // g = y - (0.344136F * cb) - (0.714136F * cr); // b = y + (1.772F * cb); - // Adding & multiplying 8 elements at one time: - Vector r = y + (cr * new Vector(1.402F)); - Vector g = y - (cb * new Vector(0.344136F)) - (cr * new Vector(0.714136F)); - Vector b = y + (cb * new Vector(1.772F)); + Vector r = y + (cr * rCrMult); + Vector g = y + (cb * gCbMult) + (cr * gCrMult); + Vector b = y + (cb * bCbMult); r = r.FastRound(); g = g.FastRound(); @@ -68,7 +68,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters } protected override void ConvertCoreInplace(in ComponentValues values) => - FromYCbCrBasic.ConvertCoreInplace(values, this.MaximumValue, this.HalfValue); + FromYCbCrScalar.ConvertCoreInplace(values, this.MaximumValue, this.HalfValue); } } } diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKAvx2.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKAvx.cs similarity index 79% rename from src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKAvx2.cs rename to src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKAvx.cs index a3500a096..53912ee07 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKAvx2.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKAvx.cs @@ -1,30 +1,26 @@ -// Copyright (c) Six Labors. +// Copyright (c) Six Labors. // Licensed under the Apache License, Version 2.0. -using System; -using System.Numerics; +#if SUPPORTS_RUNTIME_INTRINSICS using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -#if SUPPORTS_RUNTIME_INTRINSICS using System.Runtime.Intrinsics; using System.Runtime.Intrinsics.X86; using static SixLabors.ImageSharp.SimdUtils; -#endif namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { - internal abstract partial class JpegColorConverter + internal abstract partial class JpegColorConverterBase { - internal sealed class FromYccKAvx2 : Avx2JpegColorConverter + internal sealed class FromYccKAvx : AvxColorConverter { - public FromYccKAvx2(int precision) + public FromYccKAvx(int precision) : base(JpegColorSpace.Ycck, precision) { } - protected override void ConvertCoreVectorizedInplace(in ComponentValues values) + public override void ConvertToRgbInplace(in ComponentValues values) { -#if SUPPORTS_RUNTIME_INTRINSICS ref Vector256 c0Base = ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component0)); ref Vector256 c1Base = @@ -38,10 +34,10 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters var chromaOffset = Vector256.Create(-this.HalfValue); var scale = Vector256.Create(1 / (this.MaximumValue * this.MaximumValue)); var max = Vector256.Create(this.MaximumValue); - var rCrMult = Vector256.Create(1.402F); - var gCbMult = Vector256.Create(-0.344136F); - var gCrMult = Vector256.Create(-0.714136F); - var bCbMult = Vector256.Create(1.772F); + var rCrMult = Vector256.Create(FromYCbCrScalar.RCrMult); + var gCbMult = Vector256.Create(-FromYCbCrScalar.GCbMult); + var gCrMult = Vector256.Create(-FromYCbCrScalar.GCrMult); + var bCbMult = Vector256.Create(FromYCbCrScalar.BCbMult); // Walking 8 elements at one step: nint n = values.Component0.Length / 8; @@ -62,7 +58,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters // r = y + (1.402F * cr); // g = y - (0.344136F * cb) - (0.714136F * cr); // b = y + (1.772F * cb); - // Adding & multiplying 8 elements at one time: Vector256 r = HwIntrinsics.MultiplyAdd(y, cr, rCrMult); Vector256 g = HwIntrinsics.MultiplyAdd(HwIntrinsics.MultiplyAdd(y, cb, gCbMult), cr, gCrMult); @@ -80,11 +75,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters c1 = g; c2 = b; } -#endif } - - protected override void ConvertCoreInplace(in ComponentValues values) => - FromYccKBasic.ConvertCoreInplace(values, this.MaximumValue, this.HalfValue); } } } +#endif diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKBasic.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKScalar.cs similarity index 81% rename from src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKBasic.cs rename to src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKScalar.cs index 4833f4868..4657e50cf 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKBasic.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKScalar.cs @@ -1,16 +1,15 @@ -// Copyright (c) Six Labors. +// Copyright (c) Six Labors. // Licensed under the Apache License, Version 2.0. using System; -using System.Numerics; namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { - internal abstract partial class JpegColorConverter + internal abstract partial class JpegColorConverterBase { - internal sealed class FromYccKBasic : BasicJpegColorConverter + internal sealed class FromYccKScalar : ScalarJpegColorConverter { - public FromYccKBasic(int precision) + public FromYccKScalar(int precision) : base(JpegColorSpace.Ycck, precision) { } @@ -25,9 +24,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters Span c2 = values.Component2; Span c3 = values.Component3; - var v = new Vector4(0, 0, 0, 1F); - - var scale = 1 / (maxValue * maxValue); + float scale = 1 / (maxValue * maxValue); for (int i = 0; i < values.Component0.Length; i++) { diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKVector8.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKVector8.cs index f830e5042..152a0793c 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKVector8.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKVector8.cs @@ -1,17 +1,15 @@ -// Copyright (c) Six Labors. +// Copyright (c) Six Labors. // Licensed under the Apache License, Version 2.0. -using System; using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using SixLabors.ImageSharp.Tuples; namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { - internal abstract partial class JpegColorConverter + internal abstract partial class JpegColorConverterBase { - internal sealed class FromYccKVector8 : Vector8JpegColorConverter + internal sealed class FromYccKVector8 : VectorizedJpegColorConverter { public FromYccKVector8(int precision) : base(JpegColorSpace.Ycck, precision) @@ -30,13 +28,14 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component3)); var chromaOffset = new Vector(-this.HalfValue); - - // Walking 8 elements at one step: - nint n = values.Component0.Length / 8; - + var scale = new Vector(1 / (this.MaximumValue * this.MaximumValue)); var max = new Vector(this.MaximumValue); - var scale = new Vector(1f) / (max * max); + var rCrMult = new Vector(FromYCbCrScalar.RCrMult); + var gCbMult = new Vector(-FromYCbCrScalar.GCbMult); + var gCrMult = new Vector(-FromYCbCrScalar.GCrMult); + var bCbMult = new Vector(FromYCbCrScalar.BCbMult); + nint n = values.Component0.Length / 8; for (nint i = 0; i < n; i++) { // y = yVals[i]; @@ -55,10 +54,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters // r = y + (1.402F * cr); // g = y - (0.344136F * cb) - (0.714136F * cr); // b = y + (1.772F * cb); - // Adding & multiplying 8 elements at one time: - Vector r = y + (cr * new Vector(1.402F)); - Vector g = y - (cb * new Vector(0.344136F)) - (cr * new Vector(0.714136F)); - Vector b = y + (cb * new Vector(1.772F)); + Vector r = y + (cr * rCrMult); + Vector g = y + (cb * gCbMult) + (cr * gCrMult); + Vector b = y + (cb * bCbMult); r = (max - r.FastRound()) * scaledK; g = (max - g.FastRound()) * scaledK; @@ -71,7 +69,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters } protected override void ConvertCoreInplace(in ComponentValues values) => - FromYccKBasic.ConvertCoreInplace(values, this.MaximumValue, this.HalfValue); + FromYccKScalar.ConvertCoreInplace(values, this.MaximumValue, this.HalfValue); } } } diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.Vector8JpegColorConverter.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.Vector8JpegColorConverter.cs deleted file mode 100644 index 3e9b889db..000000000 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.Vector8JpegColorConverter.cs +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Apache License, Version 2.0. - -namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters -{ - internal abstract partial class JpegColorConverter - { - internal abstract class Vector8JpegColorConverter : VectorizedJpegColorConverter - { - protected Vector8JpegColorConverter(JpegColorSpace colorSpace, int precision) - : base(colorSpace, precision, 8) - { - } - - protected sealed override bool IsAvailable => SimdUtils.HasVector8; - } - } -} diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterAvx.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterAvx.cs new file mode 100644 index 000000000..ff82b36dc --- /dev/null +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterAvx.cs @@ -0,0 +1,32 @@ +// Copyright (c) Six Labors. +// Licensed under the Apache License, Version 2.0. +#if SUPPORTS_RUNTIME_INTRINSICS +using System.Runtime.Intrinsics.X86; + +namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters +{ + internal abstract partial class JpegColorConverterBase + { + /// + /// abstract base for implementations + /// based on instructions. + /// + /// + /// Converters of this family would expect input buffers lengths to be + /// divisible by 8 without a remainder. + /// This is guaranteed by real-life data as jpeg stores pixels via 8x8 blocks. + /// DO NOT pass test data of invalid size to these converters as they + /// potentially won't do a bound check and return a false positive result. + /// + internal abstract class AvxColorConverter : JpegColorConverterBase + { + protected AvxColorConverter(JpegColorSpace colorSpace, int precision) + : base(colorSpace, precision) + { + } + + protected override bool IsAvailable => Avx.IsSupported; + } + } +} +#endif diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterBase.cs similarity index 67% rename from src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.cs rename to src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterBase.cs index dad46861e..8767f5efc 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterBase.cs @@ -4,26 +4,24 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Numerics; using SixLabors.ImageSharp.Memory; -using SixLabors.ImageSharp.Tuples; namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { /// - /// Encapsulates the conversion of Jpeg channels to RGBA values packed in buffer. + /// Encapsulates the conversion of color channels from jpeg image to RGB channels. /// - internal abstract partial class JpegColorConverter + internal abstract partial class JpegColorConverterBase { /// /// The available converters /// - private static readonly JpegColorConverter[] Converters = CreateConverters(); + private static readonly JpegColorConverterBase[] Converters = CreateConverters(); /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// - protected JpegColorConverter(JpegColorSpace colorSpace, int precision) + protected JpegColorConverterBase(JpegColorSpace colorSpace, int precision) { this.ColorSpace = colorSpace; this.Precision = precision; @@ -32,7 +30,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters } /// - /// Gets a value indicating whether this is available + /// Gets a value indicating whether this is available /// on the current runtime and CPU architecture. /// protected abstract bool IsAvailable { get; } @@ -58,11 +56,11 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters private float HalfValue { get; } /// - /// Returns the corresponding to the given + /// Returns the corresponding to the given /// - public static JpegColorConverter GetConverter(JpegColorSpace colorSpace, int precision) + public static JpegColorConverterBase GetConverter(JpegColorSpace colorSpace, int precision) { - JpegColorConverter converter = Array.Find( + JpegColorConverterBase converter = Array.Find( Converters, c => c.ColorSpace == colorSpace && c.Precision == precision); @@ -82,11 +80,11 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters public abstract void ConvertToRgbInplace(in ComponentValues values); /// - /// Returns the s for all supported colorspaces and precisions. + /// Returns the s for all supported colorspaces and precisions. /// - private static JpegColorConverter[] CreateConverters() + private static JpegColorConverterBase[] CreateConverters() { - var converters = new List(); + var converters = new List(); // 8-bit converters converters.AddRange(GetYCbCrConverters(8)); @@ -106,63 +104,63 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters } /// - /// Returns the s for the YCbCr colorspace. + /// Returns the s for the YCbCr colorspace. /// - private static IEnumerable GetYCbCrConverters(int precision) + private static IEnumerable GetYCbCrConverters(int precision) { #if SUPPORTS_RUNTIME_INTRINSICS - yield return new FromYCbCrAvx2(precision); + yield return new FromYCbCrAvx(precision); #endif yield return new FromYCbCrVector8(precision); - yield return new FromYCbCrVector4(precision); - yield return new FromYCbCrBasic(precision); + yield return new FromYCbCrScalar(precision); } /// - /// Returns the s for the YccK colorspace. + /// Returns the s for the YccK colorspace. /// - private static IEnumerable GetYccKConverters(int precision) + private static IEnumerable GetYccKConverters(int precision) { #if SUPPORTS_RUNTIME_INTRINSICS - yield return new FromYccKAvx2(precision); + yield return new FromYccKAvx(precision); #endif yield return new FromYccKVector8(precision); - yield return new FromYccKBasic(precision); + yield return new FromYccKScalar(precision); } /// - /// Returns the s for the CMYK colorspace. + /// Returns the s for the CMYK colorspace. /// - private static IEnumerable GetCmykConverters(int precision) + private static IEnumerable GetCmykConverters(int precision) { #if SUPPORTS_RUNTIME_INTRINSICS - yield return new FromCmykAvx2(precision); + yield return new FromCmykAvx(precision); #endif yield return new FromCmykVector8(precision); - yield return new FromCmykBasic(precision); + yield return new FromCmykScalar(precision); } /// - /// Returns the s for the gray scale colorspace. + /// Returns the s for the gray scale colorspace. /// - private static IEnumerable GetGrayScaleConverters(int precision) + private static IEnumerable GetGrayScaleConverters(int precision) { #if SUPPORTS_RUNTIME_INTRINSICS - yield return new FromGrayscaleAvx2(precision); + yield return new FromGrayscaleAvx(precision); #endif - yield return new FromGrayscaleBasic(precision); + yield return new FromGrayScaleVector8(precision); + yield return new FromGrayscaleScalar(precision); } /// - /// Returns the s for the RGB colorspace. + /// Returns the s for the RGB colorspace. /// - private static IEnumerable GetRgbConverters(int precision) + private static IEnumerable GetRgbConverters(int precision) { #if SUPPORTS_RUNTIME_INTRINSICS - yield return new FromRgbAvx2(precision); + yield return new FromRgbAvx(precision); #endif yield return new FromRgbVector8(precision); - yield return new FromRgbBasic(precision); + yield return new FromRgbScalar(precision); } /// @@ -200,35 +198,39 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters /// /// Initializes a new instance of the struct. /// - /// The 1-4 sized list of component post processors. - /// The row to convert - public ComponentValues(IReadOnlyList componentProcessors, int row) + /// List of component buffers. + /// Row to convert + public ComponentValues(IReadOnlyList> componentBuffers, int row) { - this.ComponentCount = componentProcessors.Count; + DebugGuard.MustBeGreaterThan(componentBuffers.Count, 0, nameof(componentBuffers)); + + this.ComponentCount = componentBuffers.Count; - this.Component0 = componentProcessors[0].GetColorBufferRowSpan(row); + this.Component0 = componentBuffers[0].GetRowSpan(row); // In case of grayscale, Component1 and Component2 point to Component0 memory area - this.Component1 = this.ComponentCount > 1 ? componentProcessors[1].GetColorBufferRowSpan(row) : this.Component0; - this.Component2 = this.ComponentCount > 2 ? componentProcessors[2].GetColorBufferRowSpan(row) : this.Component0; - this.Component3 = this.ComponentCount > 3 ? componentProcessors[3].GetColorBufferRowSpan(row) : Span.Empty; + this.Component1 = this.ComponentCount > 1 ? componentBuffers[1].GetRowSpan(row) : this.Component0; + this.Component2 = this.ComponentCount > 2 ? componentBuffers[2].GetRowSpan(row) : this.Component0; + this.Component3 = this.ComponentCount > 3 ? componentBuffers[3].GetRowSpan(row) : Span.Empty; } /// /// Initializes a new instance of the struct. /// - /// The 1-4 sized list of component buffers. - /// The row to convert - public ComponentValues(IReadOnlyList> componentBuffers, int row) + /// List of component color processors. + /// Row to convert + public ComponentValues(IReadOnlyList processors, int row) { - this.ComponentCount = componentBuffers.Count; + DebugGuard.MustBeGreaterThan(processors.Count, 0, nameof(processors)); - this.Component0 = componentBuffers[0].GetRowSpan(row); + this.ComponentCount = processors.Count; + + this.Component0 = processors[0].ColorBuffer.GetRowSpan(row); // In case of grayscale, Component1 and Component2 point to Component0 memory area - this.Component1 = this.ComponentCount > 1 ? componentBuffers[1].GetRowSpan(row) : this.Component0; - this.Component2 = this.ComponentCount > 2 ? componentBuffers[2].GetRowSpan(row) : this.Component0; - this.Component3 = this.ComponentCount > 3 ? componentBuffers[3].GetRowSpan(row) : Span.Empty; + this.Component1 = this.ComponentCount > 1 ? processors[1].ColorBuffer.GetRowSpan(row) : this.Component0; + this.Component2 = this.ComponentCount > 2 ? processors[2].ColorBuffer.GetRowSpan(row) : this.Component0; + this.Component3 = this.ComponentCount > 3 ? processors[3].ColorBuffer.GetRowSpan(row) : Span.Empty; } internal ComponentValues( diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterScalar.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterScalar.cs new file mode 100644 index 000000000..89d6c4544 --- /dev/null +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterScalar.cs @@ -0,0 +1,22 @@ +// Copyright (c) Six Labors. +// Licensed under the Apache License, Version 2.0. + +namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters +{ + internal abstract partial class JpegColorConverterBase + { + /// + /// abstract base for implementations + /// based on scalar instructions. + /// + internal abstract class ScalarJpegColorConverter : JpegColorConverterBase + { + protected ScalarJpegColorConverter(JpegColorSpace colorSpace, int precision) + : base(colorSpace, precision) + { + } + + protected override bool IsAvailable => true; + } + } +} diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.VectorizedJpegColorConverter.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterVector.cs similarity index 64% rename from src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.VectorizedJpegColorConverter.cs rename to src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterVector.cs index fc4fb7786..3a40fad0c 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.VectorizedJpegColorConverter.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterVector.cs @@ -1,27 +1,36 @@ -// Copyright (c) Six Labors. +// Copyright (c) Six Labors. // Licensed under the Apache License, Version 2.0. using System; -using System.Numerics; namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { - internal abstract partial class JpegColorConverter + internal abstract partial class JpegColorConverterBase { - internal abstract class VectorizedJpegColorConverter : JpegColorConverter + /// + /// abstract base for implementations + /// based on API. + /// + /// + /// Converters of this family can work with data of any size. + /// Even though real life data is guaranteed to be of size + /// divisible by 8 newer SIMD instructions like AVX512 won't work with + /// such data out of the box. These converters have fallback code + /// for 'remainder' data. + /// + internal abstract class VectorizedJpegColorConverter : JpegColorConverterBase { - private readonly int vectorSize; - - protected VectorizedJpegColorConverter(JpegColorSpace colorSpace, int precision, int vectorSize) + protected VectorizedJpegColorConverter(JpegColorSpace colorSpace, int precision) : base(colorSpace, precision) { - this.vectorSize = vectorSize; } + protected sealed override bool IsAvailable => SimdUtils.HasVector8; + public override void ConvertToRgbInplace(in ComponentValues values) { int length = values.Component0.Length; - int remainder = values.Component0.Length % this.vectorSize; + int remainder = values.Component0.Length % 8; int simdCount = length - remainder; if (simdCount > 0) { diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter.cs index 1eb74ff80..acd98bcfc 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter.cs @@ -57,6 +57,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder /// The jpeg frame with the color space to convert to. /// The raw JPEG data. /// The color converter. - protected virtual JpegColorConverter GetColorConverter(JpegFrame frame, IRawJpegData jpegData) => JpegColorConverter.GetConverter(jpegData.ColorSpace, frame.Precision); + protected virtual JpegColorConverterBase GetColorConverter(JpegFrame frame, IRawJpegData jpegData) => JpegColorConverterBase.GetConverter(jpegData.ColorSpace, frame.Precision); } } diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter{TPixel}.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter{TPixel}.cs index 0003437e7..7137c5203 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter{TPixel}.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter{TPixel}.cs @@ -39,7 +39,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder /// /// Color converter from jpeg color space to target pixel color space. /// - private JpegColorConverter colorConverter; + private JpegColorConverterBase colorConverter; /// /// Intermediate buffer of RGB components used in color conversion. @@ -163,7 +163,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder { int y = yy - this.pixelRowCounter; - var values = new JpegColorConverter.ComponentValues(this.componentProcessors, y); + var values = new JpegColorConverterBase.ComponentValues(this.componentProcessors, y); this.colorConverter.ConvertToRgbInplace(values); values = values.Slice(0, width); // slice away Jpeg padding diff --git a/src/ImageSharp/Formats/Tiff/Compression/Decompressors/RgbJpegSpectralConverter.cs b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/RgbJpegSpectralConverter.cs index 3b5833c10..001480542 100644 --- a/src/ImageSharp/Formats/Tiff/Compression/Decompressors/RgbJpegSpectralConverter.cs +++ b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/RgbJpegSpectralConverter.cs @@ -27,6 +27,6 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Decompressors } /// - protected override JpegColorConverter GetColorConverter(JpegFrame frame, IRawJpegData jpegData) => JpegColorConverter.GetConverter(JpegColorSpace.RGB, frame.Precision); + protected override JpegColorConverterBase GetColorConverter(JpegFrame frame, IRawJpegData jpegData) => JpegColorConverterBase.GetConverter(JpegColorSpace.RGB, frame.Precision); } } diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/CmykColorConversion.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/CmykColorConversion.cs index 490beec6f..2642c21f1 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/CmykColorConversion.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/CmykColorConversion.cs @@ -17,25 +17,25 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg [Benchmark(Baseline = true)] public void Scalar() { - var values = new JpegColorConverter.ComponentValues(this.Input, 0); + var values = new JpegColorConverterBase.ComponentValues(this.Input, 0); - new JpegColorConverter.FromCmykBasic(8).ConvertToRgbInplace(values); + new JpegColorConverterBase.FromCmykBasic(8).ConvertToRgbInplace(values); } [Benchmark] public void SimdVector8() { - var values = new JpegColorConverter.ComponentValues(this.Input, 0); + var values = new JpegColorConverterBase.ComponentValues(this.Input, 0); - new JpegColorConverter.FromCmykVector8(8).ConvertToRgbInplace(values); + new JpegColorConverterBase.FromCmykVector8(8).ConvertToRgbInplace(values); } [Benchmark] public void SimdVectorAvx2() { - var values = new JpegColorConverter.ComponentValues(this.Input, 0); + var values = new JpegColorConverterBase.ComponentValues(this.Input, 0); - new JpegColorConverter.FromCmykAvx2(8).ConvertToRgbInplace(values); + new JpegColorConverterBase.FromCmykAvx2(8).ConvertToRgbInplace(values); } } } diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/GrayscaleColorConversion.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/GrayscaleColorConversion.cs index 7b62e1434..1fc85e967 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/GrayscaleColorConversion.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/GrayscaleColorConversion.cs @@ -17,17 +17,17 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg [Benchmark(Baseline = true)] public void Scalar() { - var values = new JpegColorConverter.ComponentValues(this.Input, 0); + var values = new JpegColorConverterBase.ComponentValues(this.Input, 0); - new JpegColorConverter.FromGrayscaleBasic(8).ConvertToRgbInplace(values); + new JpegColorConverterBase.FromGrayscaleBasic(8).ConvertToRgbInplace(values); } [Benchmark] public void SimdVectorAvx2() { - var values = new JpegColorConverter.ComponentValues(this.Input, 0); + var values = new JpegColorConverterBase.ComponentValues(this.Input, 0); - new JpegColorConverter.FromGrayscaleAvx2(8).ConvertToRgbInplace(values); + new JpegColorConverterBase.FromGrayscaleAvx2(8).ConvertToRgbInplace(values); } } } diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/RgbColorConversion.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/RgbColorConversion.cs index af03b31e5..517630a50 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/RgbColorConversion.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/RgbColorConversion.cs @@ -17,25 +17,25 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg [Benchmark(Baseline = true)] public void Scalar() { - var values = new JpegColorConverter.ComponentValues(this.Input, 0); + var values = new JpegColorConverterBase.ComponentValues(this.Input, 0); - new JpegColorConverter.FromRgbBasic(8).ConvertToRgbInplace(values); + new JpegColorConverterBase.FromRgbBasic(8).ConvertToRgbInplace(values); } [Benchmark] public void SimdVector8() { - var values = new JpegColorConverter.ComponentValues(this.Input, 0); + var values = new JpegColorConverterBase.ComponentValues(this.Input, 0); - new JpegColorConverter.FromRgbVector8(8).ConvertToRgbInplace(values); + new JpegColorConverterBase.FromRgbVector8(8).ConvertToRgbInplace(values); } [Benchmark] public void SimdVectorAvx2() { - var values = new JpegColorConverter.ComponentValues(this.Input, 0); + var values = new JpegColorConverterBase.ComponentValues(this.Input, 0); - new JpegColorConverter.FromRgbAvx2(8).ConvertToRgbInplace(values); + new JpegColorConverterBase.FromRgbAvx2(8).ConvertToRgbInplace(values); } } } diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/YCbCrColorConversion.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/YCbCrColorConversion.cs index 18daa364c..3b142d925 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/YCbCrColorConversion.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/YCbCrColorConversion.cs @@ -17,33 +17,33 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg [Benchmark] public void Scalar() { - var values = new JpegColorConverter.ComponentValues(this.Input, 0); + var values = new JpegColorConverterBase.ComponentValues(this.Input, 0); - new JpegColorConverter.FromYCbCrBasic(8).ConvertToRgbInplace(values); + new JpegColorConverterBase.FromYCbCrBasic(8).ConvertToRgbInplace(values); } [Benchmark(Baseline = true)] public void SimdVector() { - var values = new JpegColorConverter.ComponentValues(this.Input, 0); + var values = new JpegColorConverterBase.ComponentValues(this.Input, 0); - new JpegColorConverter.FromYCbCrVector4(8).ConvertToRgbInplace(values); + new JpegColorConverterBase.FromYCbCrVector4(8).ConvertToRgbInplace(values); } [Benchmark] public void SimdVector8() { - var values = new JpegColorConverter.ComponentValues(this.Input, 0); + var values = new JpegColorConverterBase.ComponentValues(this.Input, 0); - new JpegColorConverter.FromYCbCrVector8(8).ConvertToRgbInplace(values); + new JpegColorConverterBase.FromYCbCrVector8(8).ConvertToRgbInplace(values); } [Benchmark] public void SimdVectorAvx2() { - var values = new JpegColorConverter.ComponentValues(this.Input, 0); + var values = new JpegColorConverterBase.ComponentValues(this.Input, 0); - new JpegColorConverter.FromYCbCrAvx2(8).ConvertToRgbInplace(values); + new JpegColorConverterBase.FromYCbCrAvx2(8).ConvertToRgbInplace(values); } } } diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/YccKColorConverter.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/YccKColorConverter.cs index 08e5e50d1..b26ac0622 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/YccKColorConverter.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/YccKColorConverter.cs @@ -17,25 +17,25 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg [Benchmark(Baseline = true)] public void Scalar() { - var values = new JpegColorConverter.ComponentValues(this.Input, 0); + var values = new JpegColorConverterBase.ComponentValues(this.Input, 0); - new JpegColorConverter.FromYccKBasic(8).ConvertToRgbInplace(values); + new JpegColorConverterBase.FromYccKBasic(8).ConvertToRgbInplace(values); } [Benchmark] public void SimdVector8() { - var values = new JpegColorConverter.ComponentValues(this.Input, 0); + var values = new JpegColorConverterBase.ComponentValues(this.Input, 0); - new JpegColorConverter.FromYccKVector8(8).ConvertToRgbInplace(values); + new JpegColorConverterBase.FromYccKVector8(8).ConvertToRgbInplace(values); } [Benchmark] public void SimdVectorAvx2() { - var values = new JpegColorConverter.ComponentValues(this.Input, 0); + var values = new JpegColorConverterBase.ComponentValues(this.Input, 0); - new JpegColorConverter.FromYccKAvx2(8).ConvertToRgbInplace(values); + new JpegColorConverterBase.FromYccKAvx2(8).ConvertToRgbInplace(values); } } } diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs index d6dc57e83..fc3529513 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs @@ -45,25 +45,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg public void FromYCbCrBasic(int inputBufferLength, int resultBufferLength, int seed) { ValidateConversion( - new JpegColorConverter.FromYCbCrBasic(8), - 3, - inputBufferLength, - resultBufferLength, - seed); - } - - [Theory] - [MemberData(nameof(CommonConversionData))] - public void FromYCbCrVector4(int inputBufferLength, int resultBufferLength, int seed) - { - if (!SimdUtils.HasVector4) - { - this.Output.WriteLine("No SSE present, skipping test!"); - return; - } - - ValidateConversion( - new JpegColorConverter.FromYCbCrVector4(8), + new JpegColorConverterBase.FromYCbCrScalar(8), 3, inputBufferLength, resultBufferLength, @@ -81,7 +63,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg } ValidateConversion( - new JpegColorConverter.FromYCbCrVector8(8), + new JpegColorConverterBase.FromYCbCrVector8(8), 3, inputBufferLength, resultBufferLength, @@ -99,7 +81,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg } ValidateConversion( - new JpegColorConverter.FromYCbCrAvx2(8), + new JpegColorConverterBase.FromYCbCrAvx(8), 3, inputBufferLength, resultBufferLength, @@ -123,7 +105,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg public void FromCmykBasic(int inputBufferLength, int resultBufferLength, int seed) { ValidateConversion( - new JpegColorConverter.FromCmykBasic(8), + new JpegColorConverterBase.FromCmykScalar(8), 4, inputBufferLength, resultBufferLength, @@ -141,7 +123,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg } ValidateConversion( - new JpegColorConverter.FromCmykVector8(8), + new JpegColorConverterBase.FromCmykVector8(8), 4, inputBufferLength, resultBufferLength, @@ -159,7 +141,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg } ValidateConversion( - new JpegColorConverter.FromCmykAvx2(8), + new JpegColorConverterBase.FromCmykAvx(8), 4, inputBufferLength, resultBufferLength, @@ -183,7 +165,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg public void FromGrayscaleBasic(int inputBufferLength, int resultBufferLength, int seed) { ValidateConversion( - new JpegColorConverter.FromGrayscaleBasic(8), + new JpegColorConverterBase.FromGrayscaleScalar(8), 1, inputBufferLength, resultBufferLength, @@ -201,7 +183,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg } ValidateConversion( - new JpegColorConverter.FromGrayscaleAvx2(8), + new JpegColorConverterBase.FromGrayscaleAvx(8), 1, inputBufferLength, resultBufferLength, @@ -225,7 +207,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg public void FromRgbBasic(int inputBufferLength, int resultBufferLength, int seed) { ValidateConversion( - new JpegColorConverter.FromRgbBasic(8), + new JpegColorConverterBase.FromRgbScalar(8), 3, inputBufferLength, resultBufferLength, @@ -243,7 +225,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg } ValidateConversion( - new JpegColorConverter.FromRgbVector8(8), + new JpegColorConverterBase.FromRgbVector8(8), 3, inputBufferLength, resultBufferLength, @@ -261,7 +243,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg } ValidateConversion( - new JpegColorConverter.FromRgbAvx2(8), + new JpegColorConverterBase.FromRgbAvx(8), 3, inputBufferLength, resultBufferLength, @@ -285,7 +267,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg public void FromYccKBasic(int inputBufferLength, int resultBufferLength, int seed) { ValidateConversion( - new JpegColorConverter.FromYccKBasic(8), + new JpegColorConverterBase.FromYccKScalar(8), 4, inputBufferLength, resultBufferLength, @@ -303,7 +285,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg } ValidateConversion( - new JpegColorConverter.FromYccKVector8(8), + new JpegColorConverterBase.FromYccKVector8(8), 4, inputBufferLength, resultBufferLength, @@ -321,7 +303,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg } ValidateConversion( - new JpegColorConverter.FromYccKAvx2(8), + new JpegColorConverterBase.FromYccKAvx(8), 4, inputBufferLength, resultBufferLength, @@ -340,7 +322,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg seed); } - private static JpegColorConverter.ComponentValues CreateRandomValues( + private static JpegColorConverterBase.ComponentValues CreateRandomValues( int componentCount, int inputBufferLength, int seed, @@ -365,7 +347,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg buffers[i] = new Buffer2D(source, values.Length, 1); } - return new JpegColorConverter.ComponentValues(buffers, 0); + return new JpegColorConverterBase.ComponentValues(buffers, 0); } private static void ValidateConversion( @@ -376,7 +358,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg int seed) { ValidateConversion( - JpegColorConverter.GetConverter(colorSpace, 8), + JpegColorConverterBase.GetConverter(colorSpace, 8), componentCount, inputBufferLength, resultBufferLength, @@ -384,14 +366,14 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg } private static void ValidateConversion( - JpegColorConverter converter, + JpegColorConverterBase converter, int componentCount, int inputBufferLength, int resultBufferLength, int seed) { - JpegColorConverter.ComponentValues original = CreateRandomValues(componentCount, inputBufferLength, seed); - JpegColorConverter.ComponentValues values = Copy(original); + JpegColorConverterBase.ComponentValues original = CreateRandomValues(componentCount, inputBufferLength, seed); + JpegColorConverterBase.ComponentValues values = Copy(original); converter.ConvertToRgbInplace(values); @@ -400,20 +382,20 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg Validate(converter.ColorSpace, original, values, i); } - static JpegColorConverter.ComponentValues Copy(JpegColorConverter.ComponentValues values) + static JpegColorConverterBase.ComponentValues Copy(JpegColorConverterBase.ComponentValues values) { Span c0 = values.Component0.ToArray(); Span c1 = values.ComponentCount > 1 ? values.Component1.ToArray().AsSpan() : c0; Span c2 = values.ComponentCount > 2 ? values.Component2.ToArray().AsSpan() : c0; Span c3 = values.ComponentCount > 3 ? values.Component3.ToArray().AsSpan() : Span.Empty; - return new JpegColorConverter.ComponentValues(values.ComponentCount, c0, c1, c2, c3); + return new JpegColorConverterBase.ComponentValues(values.ComponentCount, c0, c1, c2, c3); } } private static void Validate( JpegColorSpace colorSpace, - in JpegColorConverter.ComponentValues original, - in JpegColorConverter.ComponentValues result, + in JpegColorConverterBase.ComponentValues original, + in JpegColorConverterBase.ComponentValues result, int i) { switch (colorSpace) @@ -439,7 +421,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg } } - private static void ValidateYCbCr(in JpegColorConverter.ComponentValues values, in JpegColorConverter.ComponentValues result, int i) + private static void ValidateYCbCr(in JpegColorConverterBase.ComponentValues values, in JpegColorConverterBase.ComponentValues result, int i) { float y = values.Component0[i]; float cb = values.Component1[i]; @@ -452,7 +434,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg Assert.Equal(expected, actual, ColorSpaceComparer); } - private static void ValidateCyyK(in JpegColorConverter.ComponentValues values, in JpegColorConverter.ComponentValues result, int i) + private static void ValidateCyyK(in JpegColorConverterBase.ComponentValues values, in JpegColorConverterBase.ComponentValues result, int i) { var v = new Vector4(0, 0, 0, 1F); var scale = new Vector4(1 / 255F, 1 / 255F, 1 / 255F, 1F); @@ -477,7 +459,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg Assert.Equal(expected, actual, ColorSpaceComparer); } - private static void ValidateRgb(in JpegColorConverter.ComponentValues values, in JpegColorConverter.ComponentValues result, int i) + private static void ValidateRgb(in JpegColorConverterBase.ComponentValues values, in JpegColorConverterBase.ComponentValues result, int i) { float r = values.Component0[i]; float g = values.Component1[i]; @@ -489,7 +471,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg Assert.Equal(expected, actual, ColorSpaceComparer); } - private static void ValidateGrayScale(in JpegColorConverter.ComponentValues values, in JpegColorConverter.ComponentValues result, int i) + private static void ValidateGrayScale(in JpegColorConverterBase.ComponentValues values, in JpegColorConverterBase.ComponentValues result, int i) { float y = values.Component0[i]; var actual = new Rgb(result.Component0[i], result.Component0[i], result.Component0[i]); @@ -498,7 +480,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg Assert.Equal(expected, actual, ColorSpaceComparer); } - private static void ValidateCmyk(in JpegColorConverter.ComponentValues values, in JpegColorConverter.ComponentValues result, int i) + private static void ValidateCmyk(in JpegColorConverterBase.ComponentValues values, in JpegColorConverterBase.ComponentValues result, int i) { var v = new Vector4(0, 0, 0, 1F); var scale = new Vector4(1 / 255F, 1 / 255F, 1 / 255F, 1F); From 311748ef61bbe51efb17b6dfa43516c0eb14445c Mon Sep 17 00:00:00 2001 From: Dmitry Pentin Date: Wed, 1 Dec 2021 08:11:55 +0300 Subject: [PATCH 14/65] Fixed compilation errors --- .../Jpeg/ColorConversion/CmykColorConversion.cs | 8 +++++--- .../ColorConversion/GrayscaleColorConversion.cs | 10 ++++++---- .../Jpeg/ColorConversion/RgbColorConversion.cs | 10 ++++++---- .../Jpeg/ColorConversion/YCbCrColorConversion.cs | 16 +++++----------- .../Jpeg/ColorConversion/YccKColorConverter.cs | 8 +++++--- .../Formats/Jpg/JpegColorConverterTests.cs | 10 ++++++++++ 6 files changed, 37 insertions(+), 25 deletions(-) diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/CmykColorConversion.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/CmykColorConversion.cs index 2642c21f1..36e666957 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/CmykColorConversion.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/CmykColorConversion.cs @@ -19,7 +19,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg { var values = new JpegColorConverterBase.ComponentValues(this.Input, 0); - new JpegColorConverterBase.FromCmykBasic(8).ConvertToRgbInplace(values); + new JpegColorConverterBase.FromCmykScalar(8).ConvertToRgbInplace(values); } [Benchmark] @@ -30,12 +30,14 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg new JpegColorConverterBase.FromCmykVector8(8).ConvertToRgbInplace(values); } +#if SUPPORTS_RUNTIME_INTRINSICS [Benchmark] - public void SimdVectorAvx2() + public void SimdVectorAvx() { var values = new JpegColorConverterBase.ComponentValues(this.Input, 0); - new JpegColorConverterBase.FromCmykAvx2(8).ConvertToRgbInplace(values); + new JpegColorConverterBase.FromCmykAvx(8).ConvertToRgbInplace(values); } +#endif } } diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/GrayscaleColorConversion.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/GrayscaleColorConversion.cs index 1fc85e967..2fdb47077 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/GrayscaleColorConversion.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/GrayscaleColorConversion.cs @@ -1,4 +1,4 @@ -// Copyright (c) Six Labors. +// Copyright (c) Six Labors. // Licensed under the Apache License, Version 2.0. using BenchmarkDotNet.Attributes; @@ -19,15 +19,17 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg { var values = new JpegColorConverterBase.ComponentValues(this.Input, 0); - new JpegColorConverterBase.FromGrayscaleBasic(8).ConvertToRgbInplace(values); + new JpegColorConverterBase.FromGrayscaleScalar(8).ConvertToRgbInplace(values); } +#if SUPPORTS_RUNTIME_INTRINSICS [Benchmark] - public void SimdVectorAvx2() + public void SimdVectorAvx() { var values = new JpegColorConverterBase.ComponentValues(this.Input, 0); - new JpegColorConverterBase.FromGrayscaleAvx2(8).ConvertToRgbInplace(values); + new JpegColorConverterBase.FromGrayscaleAvx(8).ConvertToRgbInplace(values); } +#endif } } diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/RgbColorConversion.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/RgbColorConversion.cs index 517630a50..69c1a3974 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/RgbColorConversion.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/RgbColorConversion.cs @@ -1,4 +1,4 @@ -// Copyright (c) Six Labors. +// Copyright (c) Six Labors. // Licensed under the Apache License, Version 2.0. using BenchmarkDotNet.Attributes; @@ -19,7 +19,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg { var values = new JpegColorConverterBase.ComponentValues(this.Input, 0); - new JpegColorConverterBase.FromRgbBasic(8).ConvertToRgbInplace(values); + new JpegColorConverterBase.FromRgbScalar(8).ConvertToRgbInplace(values); } [Benchmark] @@ -30,12 +30,14 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg new JpegColorConverterBase.FromRgbVector8(8).ConvertToRgbInplace(values); } +#if SUPPORTS_RUNTIME_INTRINSICS [Benchmark] - public void SimdVectorAvx2() + public void SimdVectorAvx() { var values = new JpegColorConverterBase.ComponentValues(this.Input, 0); - new JpegColorConverterBase.FromRgbAvx2(8).ConvertToRgbInplace(values); + new JpegColorConverterBase.FromRgbAvx(8).ConvertToRgbInplace(values); } +#endif } } diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/YCbCrColorConversion.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/YCbCrColorConversion.cs index 3b142d925..656cae104 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/YCbCrColorConversion.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/YCbCrColorConversion.cs @@ -19,15 +19,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg { var values = new JpegColorConverterBase.ComponentValues(this.Input, 0); - new JpegColorConverterBase.FromYCbCrBasic(8).ConvertToRgbInplace(values); - } - - [Benchmark(Baseline = true)] - public void SimdVector() - { - var values = new JpegColorConverterBase.ComponentValues(this.Input, 0); - - new JpegColorConverterBase.FromYCbCrVector4(8).ConvertToRgbInplace(values); + new JpegColorConverterBase.FromYCbCrScalar(8).ConvertToRgbInplace(values); } [Benchmark] @@ -38,12 +30,14 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg new JpegColorConverterBase.FromYCbCrVector8(8).ConvertToRgbInplace(values); } +#if SUPPORTS_RUNTIME_INTRINSICS [Benchmark] - public void SimdVectorAvx2() + public void SimdVectorAvx() { var values = new JpegColorConverterBase.ComponentValues(this.Input, 0); - new JpegColorConverterBase.FromYCbCrAvx2(8).ConvertToRgbInplace(values); + new JpegColorConverterBase.FromYCbCrAvx(8).ConvertToRgbInplace(values); } +#endif } } diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/YccKColorConverter.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/YccKColorConverter.cs index b26ac0622..6c0583b62 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/YccKColorConverter.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/YccKColorConverter.cs @@ -1,4 +1,4 @@ -// Copyright (c) Six Labors. +// Copyright (c) Six Labors. // Licensed under the Apache License, Version 2.0. using BenchmarkDotNet.Attributes; @@ -19,7 +19,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg { var values = new JpegColorConverterBase.ComponentValues(this.Input, 0); - new JpegColorConverterBase.FromYccKBasic(8).ConvertToRgbInplace(values); + new JpegColorConverterBase.FromYccKScalar(8).ConvertToRgbInplace(values); } [Benchmark] @@ -30,12 +30,14 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg new JpegColorConverterBase.FromYccKVector8(8).ConvertToRgbInplace(values); } +#if SUPPORTS_RUNTIME_INTRINSICS [Benchmark] public void SimdVectorAvx2() { var values = new JpegColorConverterBase.ComponentValues(this.Input, 0); - new JpegColorConverterBase.FromYccKAvx2(8).ConvertToRgbInplace(values); + new JpegColorConverterBase.FromYccKAvx(8).ConvertToRgbInplace(values); } +#endif } } diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs index fc3529513..41c9dd6a3 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs @@ -70,6 +70,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg seed); } +#if SUPPORTS_RUNTIME_INTRINSICS [Theory] [MemberData(nameof(CommonConversionData))] public void FromYCbCrAvx2(int inputBufferLength, int resultBufferLength, int seed) @@ -87,6 +88,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg resultBufferLength, seed); } +#endif [Theory] [MemberData(nameof(CommonConversionData))] @@ -130,6 +132,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg seed); } +#if SUPPORTS_RUNTIME_INTRINSICS [Theory] [MemberData(nameof(CommonConversionData))] public void FromCmykAvx2(int inputBufferLength, int resultBufferLength, int seed) @@ -147,6 +150,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg resultBufferLength, seed); } +#endif [Theory] [MemberData(nameof(CommonConversionData))] @@ -172,6 +176,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg seed); } +#if SUPPORTS_RUNTIME_INTRINSICS [Theory] [MemberData(nameof(CommonConversionData))] public void FromGrayscaleAvx2(int inputBufferLength, int resultBufferLength, int seed) @@ -189,6 +194,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg resultBufferLength, seed); } +#endif [Theory] [MemberData(nameof(CommonConversionData))] @@ -232,6 +238,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg seed); } +#if SUPPORTS_RUNTIME_INTRINSICS [Theory] [MemberData(nameof(CommonConversionData))] public void FromRgbAvx2(int inputBufferLength, int resultBufferLength, int seed) @@ -249,6 +256,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg resultBufferLength, seed); } +#endif [Theory] [MemberData(nameof(CommonConversionData))] @@ -292,6 +300,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg seed); } +#if SUPPORTS_RUNTIME_INTRINSICS [Theory] [MemberData(nameof(CommonConversionData))] public void FromYccKAvx2(int inputBufferLength, int resultBufferLength, int seed) @@ -309,6 +318,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg resultBufferLength, seed); } +#endif [Theory] [MemberData(nameof(CommonConversionData))] From 231932f952f8084644e07174adc2d2c52e6e09a2 Mon Sep 17 00:00:00 2001 From: Dmitry Pentin Date: Wed, 1 Dec 2021 08:27:08 +0300 Subject: [PATCH 15/65] Fixed docs --- .../Jpeg/Components/Decoder/SpectralConverter{TPixel}.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter{TPixel}.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter{TPixel}.cs index 7137c5203..a3e98125e 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter{TPixel}.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter{TPixel}.cs @@ -14,11 +14,11 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder /// /// /// Color decoding scheme: - /// + /// /// - /// 1. Decode spectral data to Jpeg color space - /// 2. Convert from Jpeg color space to RGB - /// 3. Convert from RGB to target pixel space + /// Decode spectral data to Jpeg color space + /// Convert from Jpeg color space to RGB + /// Convert from RGB to target pixel space /// /// /// From be057f5a339d9b1e47be4c86558d98bc3abd5dcd Mon Sep 17 00:00:00 2001 From: Dmitry Pentin Date: Wed, 1 Dec 2021 08:37:40 +0300 Subject: [PATCH 16/65] Use Vector256.Count instead of magic 8 --- .../Decoder/ColorConverters/JpegColorConverter.FromCmykAvx.cs | 2 +- .../ColorConverters/JpegColorConverter.FromGrayScaleAvx.cs | 2 +- .../Decoder/ColorConverters/JpegColorConverter.FromRgbAvx.cs | 2 +- .../Decoder/ColorConverters/JpegColorConverter.FromYCbCrAvx.cs | 2 +- .../Decoder/ColorConverters/JpegColorConverter.FromYccKAvx.cs | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykAvx.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykAvx.cs index 2671dec70..4c89fc6fa 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykAvx.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykAvx.cs @@ -32,7 +32,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters // Used for the color conversion var scale = Vector256.Create(1 / this.MaximumValue); - nint n = values.Component0.Length / 8; + nint n = values.Component0.Length / Vector256.Count; for (nint i = 0; i < n; i++) { ref Vector256 c = ref Unsafe.Add(ref c0Base, i); diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleAvx.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleAvx.cs index 38b159bba..fcfcaa2a9 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleAvx.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleAvx.cs @@ -26,7 +26,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters // Used for the color conversion var scale = Vector256.Create(1 / this.MaximumValue); - nint n = values.Component0.Length / 8; + nint n = values.Component0.Length / Vector256.Count; for (nint i = 0; i < n; i++) { ref Vector256 c0 = ref Unsafe.Add(ref c0Base, i); diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbAvx.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbAvx.cs index 31c573903..83fbc369b 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbAvx.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbAvx.cs @@ -29,7 +29,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters // Used for the color conversion var scale = Vector256.Create(1 / this.MaximumValue); - nint n = values.Component0.Length / 8; + nint n = values.Component0.Length / Vector256.Count; for (nint i = 0; i < n; i++) { ref Vector256 r = ref Unsafe.Add(ref rBase, i); diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrAvx.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrAvx.cs index 1bf1c4461..adf6e8e0f 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrAvx.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrAvx.cs @@ -38,7 +38,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters var bCbMult = Vector256.Create(FromYCbCrScalar.BCbMult); // Walking 8 elements at one step: - nint n = values.Component0.Length / 8; + nint n = values.Component0.Length / Vector256.Count; for (nint i = 0; i < n; i++) { // y = yVals[i]; diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKAvx.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKAvx.cs index 53912ee07..86528c74d 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKAvx.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKAvx.cs @@ -40,7 +40,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters var bCbMult = Vector256.Create(FromYCbCrScalar.BCbMult); // Walking 8 elements at one step: - nint n = values.Component0.Length / 8; + nint n = values.Component0.Length / Vector256.Count; for (nint i = 0; i < n; i++) { // y = yVals[i]; From add85f899986218d57723d80b85bfba18dbacad6 Mon Sep 17 00:00:00 2001 From: Dmitry Pentin Date: Wed, 1 Dec 2021 08:46:00 +0300 Subject: [PATCH 17/65] Removed HasAvx2 flag, reorganized test skipping --- src/ImageSharp/Common/Helpers/SimdUtils.cs | 12 ----- .../ColorConverters/JpegColorConverterAvx.cs | 2 +- .../ColorConverters/JpegColorConverterBase.cs | 2 +- .../JpegColorConverterScalar.cs | 2 +- .../JpegColorConverterVector.cs | 2 +- .../Formats/Jpg/JpegColorConverterTests.cs | 45 ++++++++++++------- 6 files changed, 34 insertions(+), 31 deletions(-) diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.cs b/src/ImageSharp/Common/Helpers/SimdUtils.cs index 6d82cfad0..29068a82c 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.cs @@ -33,18 +33,6 @@ namespace SixLabors.ImageSharp public static bool HasVector4 { get; } = Vector.IsHardwareAccelerated && Vector.Count == 4; - public static bool HasAvx2 - { - get - { -#if SUPPORTS_RUNTIME_INTRINSICS - return Avx2.IsSupported; -#else - return false; -#endif - } - } - /// /// Transform all scalars in 'v' in a way that converting them to would have rounding semantics. /// diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterAvx.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterAvx.cs index ff82b36dc..559422273 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterAvx.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterAvx.cs @@ -25,7 +25,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { } - protected override bool IsAvailable => Avx.IsSupported; + public override bool IsAvailable => Avx.IsSupported; } } } diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterBase.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterBase.cs index 8767f5efc..b8fd169e9 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterBase.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterBase.cs @@ -33,7 +33,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters /// Gets a value indicating whether this is available /// on the current runtime and CPU architecture. /// - protected abstract bool IsAvailable { get; } + public abstract bool IsAvailable { get; } /// /// Gets the of this converter. diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterScalar.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterScalar.cs index 89d6c4544..76134d490 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterScalar.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterScalar.cs @@ -16,7 +16,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { } - protected override bool IsAvailable => true; + public override bool IsAvailable => true; } } } diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterVector.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterVector.cs index 3a40fad0c..3cd295f0b 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterVector.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterVector.cs @@ -25,7 +25,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { } - protected sealed override bool IsAvailable => SimdUtils.HasVector8; + public sealed override bool IsAvailable => SimdUtils.HasVector8; public override void ConvertToRgbInplace(in ComponentValues values) { diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs index 41c9dd6a3..7b91e1a8a 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs @@ -75,14 +75,17 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg [MemberData(nameof(CommonConversionData))] public void FromYCbCrAvx2(int inputBufferLength, int resultBufferLength, int seed) { - if (!SimdUtils.HasAvx2) + var converter = new JpegColorConverterBase.FromYCbCrAvx(8); + + if (!converter.IsAvailable) { - this.Output.WriteLine("No AVX2 present, skipping test!"); + this.Output.WriteLine( + $"Skipping test - {converter.GetType().Name} is not supported on current hardware."); return; } ValidateConversion( - new JpegColorConverterBase.FromYCbCrAvx(8), + converter, 3, inputBufferLength, resultBufferLength, @@ -137,14 +140,17 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg [MemberData(nameof(CommonConversionData))] public void FromCmykAvx2(int inputBufferLength, int resultBufferLength, int seed) { - if (!SimdUtils.HasAvx2) + var converter = new JpegColorConverterBase.FromCmykAvx(8); + + if (!converter.IsAvailable) { - this.Output.WriteLine("No AVX2 present, skipping test!"); + this.Output.WriteLine( + $"Skipping test - {converter.GetType().Name} is not supported on current hardware."); return; } ValidateConversion( - new JpegColorConverterBase.FromCmykAvx(8), + converter, 4, inputBufferLength, resultBufferLength, @@ -181,14 +187,17 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg [MemberData(nameof(CommonConversionData))] public void FromGrayscaleAvx2(int inputBufferLength, int resultBufferLength, int seed) { - if (!SimdUtils.HasAvx2) + var converter = new JpegColorConverterBase.FromGrayscaleAvx(8); + + if (!converter.IsAvailable) { - this.Output.WriteLine("No AVX2 present, skipping test!"); + this.Output.WriteLine( + $"Skipping test - {converter.GetType().Name} is not supported on current hardware."); return; } ValidateConversion( - new JpegColorConverterBase.FromGrayscaleAvx(8), + converter, 1, inputBufferLength, resultBufferLength, @@ -243,14 +252,17 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg [MemberData(nameof(CommonConversionData))] public void FromRgbAvx2(int inputBufferLength, int resultBufferLength, int seed) { - if (!SimdUtils.HasAvx2) + var converter = new JpegColorConverterBase.FromRgbAvx(8); + + if (!converter.IsAvailable) { - this.Output.WriteLine("No AVX2 present, skipping test!"); + this.Output.WriteLine( + $"Skipping test - {converter.GetType().Name} is not supported on current hardware."); return; } ValidateConversion( - new JpegColorConverterBase.FromRgbAvx(8), + converter, 3, inputBufferLength, resultBufferLength, @@ -305,14 +317,17 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg [MemberData(nameof(CommonConversionData))] public void FromYccKAvx2(int inputBufferLength, int resultBufferLength, int seed) { - if (!SimdUtils.HasAvx2) + var converter = new JpegColorConverterBase.FromYccKAvx(8); + + if (!converter.IsAvailable) { - this.Output.WriteLine("No AVX2 present, skipping test!"); + this.Output.WriteLine( + $"Skipping test - {converter.GetType().Name} is not supported on current hardware."); return; } ValidateConversion( - new JpegColorConverterBase.FromYccKAvx(8), + converter, 4, inputBufferLength, resultBufferLength, From 87ce4e53e249b280a13ea06af49041a2309d7658 Mon Sep 17 00:00:00 2001 From: Ynse Hoornenborg Date: Wed, 1 Dec 2021 22:11:28 +0100 Subject: [PATCH 18/65] Various review comments --- src/ImageSharp/Formats/Pbm/PbmEncoderCore.cs | 1 + src/ImageSharp/Formats/Pbm/PlainEncoder.cs | 10 +-- .../Formats/Pbm/PbmDecoderTests.cs | 1 + ...RoundTripTests.cs => PbmRoundTripTests.cs} | 24 ++++++- .../Formats/Pbm/PbmTestUtils.cs | 65 ------------------- 5 files changed, 29 insertions(+), 72 deletions(-) rename tests/ImageSharp.Tests/Formats/Pbm/{RoundTripTests.cs => PbmRoundTripTests.cs} (62%) delete mode 100644 tests/ImageSharp.Tests/Formats/Pbm/PbmTestUtils.cs diff --git a/src/ImageSharp/Formats/Pbm/PbmEncoderCore.cs b/src/ImageSharp/Formats/Pbm/PbmEncoderCore.cs index eb1ba8140..158786e3c 100644 --- a/src/ImageSharp/Formats/Pbm/PbmEncoderCore.cs +++ b/src/ImageSharp/Formats/Pbm/PbmEncoderCore.cs @@ -88,6 +88,7 @@ namespace SixLabors.ImageSharp.Formats.Pbm if (this.colorType != PbmColorType.BlackAndWhite) { this.maxPixelValue = this.options.MaxPixelValue ?? metadata.MaxPixelValue; + this.maxPixelValue = Math.Max(this.maxPixelValue, PbmConstants.MaxLength); } } diff --git a/src/ImageSharp/Formats/Pbm/PlainEncoder.cs b/src/ImageSharp/Formats/Pbm/PlainEncoder.cs index b67f0a077..2e7c60e5e 100644 --- a/src/ImageSharp/Formats/Pbm/PlainEncoder.cs +++ b/src/ImageSharp/Formats/Pbm/PlainEncoder.cs @@ -76,7 +76,7 @@ namespace SixLabors.ImageSharp.Formats.Pbm MemoryAllocator allocator = configuration.MemoryAllocator; using IMemoryOwner row = allocator.Allocate(width); Span rowSpan = row.GetSpan(); - IMemoryOwner plainMemory = allocator.Allocate(width * MaxCharsPerPixelGrayscale); + using IMemoryOwner plainMemory = allocator.Allocate(width * MaxCharsPerPixelGrayscale); Span plainSpan = plainMemory.GetSpan(); for (int y = 0; y < height; y++) @@ -108,7 +108,7 @@ namespace SixLabors.ImageSharp.Formats.Pbm MemoryAllocator allocator = configuration.MemoryAllocator; using IMemoryOwner row = allocator.Allocate(width); Span rowSpan = row.GetSpan(); - IMemoryOwner plainMemory = allocator.Allocate(width * MaxCharsPerPixelGrayscaleWide); + using IMemoryOwner plainMemory = allocator.Allocate(width * MaxCharsPerPixelGrayscaleWide); Span plainSpan = plainMemory.GetSpan(); for (int y = 0; y < height; y++) @@ -140,7 +140,7 @@ namespace SixLabors.ImageSharp.Formats.Pbm MemoryAllocator allocator = configuration.MemoryAllocator; using IMemoryOwner row = allocator.Allocate(width); Span rowSpan = row.GetSpan(); - IMemoryOwner plainMemory = allocator.Allocate(width * MaxCharsPerPixelRgb); + using IMemoryOwner plainMemory = allocator.Allocate(width * MaxCharsPerPixelRgb); Span plainSpan = plainMemory.GetSpan(); for (int y = 0; y < height; y++) @@ -178,7 +178,7 @@ namespace SixLabors.ImageSharp.Formats.Pbm MemoryAllocator allocator = configuration.MemoryAllocator; using IMemoryOwner row = allocator.Allocate(width); Span rowSpan = row.GetSpan(); - IMemoryOwner plainMemory = allocator.Allocate(width * MaxCharsPerPixelRgbWide); + using IMemoryOwner plainMemory = allocator.Allocate(width * MaxCharsPerPixelRgbWide); Span plainSpan = plainMemory.GetSpan(); for (int y = 0; y < height; y++) @@ -216,7 +216,7 @@ namespace SixLabors.ImageSharp.Formats.Pbm MemoryAllocator allocator = configuration.MemoryAllocator; using IMemoryOwner row = allocator.Allocate(width); Span rowSpan = row.GetSpan(); - IMemoryOwner plainMemory = allocator.Allocate(width * MaxCharsPerPixelBlackAndWhite); + using IMemoryOwner plainMemory = allocator.Allocate(width * MaxCharsPerPixelBlackAndWhite); Span plainSpan = plainMemory.GetSpan(); for (int y = 0; y < height; y++) diff --git a/tests/ImageSharp.Tests/Formats/Pbm/PbmDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Pbm/PbmDecoderTests.cs index 6c84fba9e..479db2ca5 100644 --- a/tests/ImageSharp.Tests/Formats/Pbm/PbmDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Pbm/PbmDecoderTests.cs @@ -84,6 +84,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Pbm where TPixel : unmanaged, IPixel { using Image image = provider.GetImage(); + image.DebugSave(provider); image.CompareToReferenceOutput(provider, grayscale: isGrayscale); } diff --git a/tests/ImageSharp.Tests/Formats/Pbm/RoundTripTests.cs b/tests/ImageSharp.Tests/Formats/Pbm/PbmRoundTripTests.cs similarity index 62% rename from tests/ImageSharp.Tests/Formats/Pbm/RoundTripTests.cs rename to tests/ImageSharp.Tests/Formats/Pbm/PbmRoundTripTests.cs index 391e8c054..715a1e07e 100644 --- a/tests/ImageSharp.Tests/Formats/Pbm/RoundTripTests.cs +++ b/tests/ImageSharp.Tests/Formats/Pbm/PbmRoundTripTests.cs @@ -11,8 +11,28 @@ using static SixLabors.ImageSharp.Tests.TestImages.Pbm; namespace SixLabors.ImageSharp.Tests.Formats.Pbm { [Trait("Format", "Pbm")] - public class RoundTripTests + public class PbmRoundTripTests { + [Theory] + [InlineData(BlackAndWhiteBinary)] + [InlineData(GrayscalePlain)] + [InlineData(GrayscaleBinary)] + public void PbmGrayscaleImageCanRoundTrip(string imagePath) + { + // Arrange + var testFile = TestFile.Create(imagePath); + using var stream = new MemoryStream(testFile.Bytes, false); + + // Act + using var originalImage = Image.Load(stream); + Image colorImage = originalImage.CloneAs(); + using Image encodedImage = this.RoundTrip(colorImage); + + // Assert + Assert.NotNull(encodedImage); + ImageComparer.Exact.VerifySimilarity(colorImage, encodedImage); + } + [Theory] [InlineData(RgbPlain)] [InlineData(RgbBinary)] @@ -37,7 +57,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Pbm using var decodedStream = new MemoryStream(); originalImage.SaveAsPbm(decodedStream); decodedStream.Seek(0, SeekOrigin.Begin); - var encodedImage = (Image)Image.Load(decodedStream); + var encodedImage = Image.Load(decodedStream); return encodedImage; } } diff --git a/tests/ImageSharp.Tests/Formats/Pbm/PbmTestUtils.cs b/tests/ImageSharp.Tests/Formats/Pbm/PbmTestUtils.cs deleted file mode 100644 index 7b701fe3d..000000000 --- a/tests/ImageSharp.Tests/Formats/Pbm/PbmTestUtils.cs +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Apache License, Version 2.0. - -using System; -using System.IO; -using ImageMagick; -using SixLabors.ImageSharp.PixelFormats; -using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison; -using Xunit; - -namespace SixLabors.ImageSharp.Tests.Formats.Pbm -{ - public static class PbmTestUtils - { - public static void CompareWithReferenceDecoder( - TestImageProvider provider, - Image image, - bool useExactComparer = true, - float compareTolerance = 0.01f) - where TPixel : unmanaged, ImageSharp.PixelFormats.IPixel - { - string path = TestImageProvider.GetFilePathOrNull(provider); - if (path == null) - { - throw new InvalidOperationException("CompareToOriginal() works only with file providers!"); - } - - var testFile = TestFile.Create(path); - Image magickImage = DecodeWithMagick(Configuration.Default, new FileInfo(testFile.FullPath)); - if (useExactComparer) - { - ImageComparer.Exact.VerifySimilarity(magickImage, image); - } - else - { - ImageComparer.Tolerant(compareTolerance).VerifySimilarity(magickImage, image); - } - } - - public static Image DecodeWithMagick(Configuration configuration, FileInfo fileInfo) - where TPixel : unmanaged, ImageSharp.PixelFormats.IPixel - { - using (var magickImage = new MagickImage(fileInfo)) - { - magickImage.AutoOrient(); - var result = new Image(configuration, magickImage.Width, magickImage.Height); - - Assert.True(result.TryGetSinglePixelSpan(out Span resultPixels)); - - using (IUnsafePixelCollection pixels = magickImage.GetPixelsUnsafe()) - { - byte[] data = pixels.ToByteArray(PixelMapping.RGBA); - - PixelOperations.Instance.FromRgba32Bytes( - configuration, - data, - resultPixels, - resultPixels.Length); - } - - return result; - } - } - } -} From a5e1723be913544e4e7c7f52682a096f6e787431 Mon Sep 17 00:00:00 2001 From: Ynse Hoornenborg Date: Wed, 1 Dec 2021 22:44:36 +0100 Subject: [PATCH 19/65] Dispose of images after use, in Pbm Round Trip Test --- tests/ImageSharp.Tests/Formats/Pbm/PbmRoundTripTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ImageSharp.Tests/Formats/Pbm/PbmRoundTripTests.cs b/tests/ImageSharp.Tests/Formats/Pbm/PbmRoundTripTests.cs index 715a1e07e..1735efdce 100644 --- a/tests/ImageSharp.Tests/Formats/Pbm/PbmRoundTripTests.cs +++ b/tests/ImageSharp.Tests/Formats/Pbm/PbmRoundTripTests.cs @@ -25,7 +25,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Pbm // Act using var originalImage = Image.Load(stream); - Image colorImage = originalImage.CloneAs(); + using Image colorImage = originalImage.CloneAs(); using Image encodedImage = this.RoundTrip(colorImage); // Assert From 45e4768b91416a07ab9ada37c389697d89e7bd7b Mon Sep 17 00:00:00 2001 From: Dmitry Pentin Date: Thu, 2 Dec 2021 09:13:06 +0300 Subject: [PATCH 20/65] Vector color converters can work with any available vector size instead of 8 --- ...s => JpegColorConverter.FromCmykVector.cs} | 6 ++-- ...JpegColorConverter.FromGrayScaleVector.cs} | 6 ++-- ...cs => JpegColorConverter.FromRgbVector.cs} | 6 ++-- ... => JpegColorConverter.FromYCbCrVector.cs} | 6 ++-- ...s => JpegColorConverter.FromYccKVector.cs} | 6 ++-- .../ColorConverters/JpegColorConverterBase.cs | 10 +++---- .../JpegColorConverterVector.cs | 30 +++++++++---------- .../ColorConversion/CmykColorConversion.cs | 2 +- .../ColorConversion/RgbColorConversion.cs | 2 +- .../ColorConversion/YCbCrColorConversion.cs | 2 +- .../ColorConversion/YccKColorConverter.cs | 2 +- .../Formats/Jpg/JpegColorConverterTests.cs | 8 ++--- 12 files changed, 43 insertions(+), 43 deletions(-) rename src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/{JpegColorConverter.FromCmykVector8.cs => JpegColorConverter.FromCmykVector.cs} (90%) rename src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/{JpegColorConverter.FromGrayScaleVector8.cs => JpegColorConverter.FromGrayScaleVector.cs} (84%) rename src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/{JpegColorConverter.FromRgbVector8.cs => JpegColorConverter.FromRgbVector.cs} (89%) rename src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/{JpegColorConverter.FromYCbCrVector8.cs => JpegColorConverter.FromYCbCrVector.cs} (93%) rename src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/{JpegColorConverter.FromYccKVector8.cs => JpegColorConverter.FromYccKVector.cs} (94%) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykVector8.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykVector.cs similarity index 90% rename from src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykVector8.cs rename to src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykVector.cs index 685e25aad..9b123547b 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykVector8.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykVector.cs @@ -9,9 +9,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { internal abstract partial class JpegColorConverterBase { - internal sealed class FromCmykVector8 : VectorizedJpegColorConverter + internal sealed class FromCmykVector : VectorizedJpegColorConverter { - public FromCmykVector8(int precision) + public FromCmykVector(int precision) : base(JpegColorSpace.Cmyk, precision) { } @@ -29,7 +29,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters var scale = new Vector(1 / this.MaximumValue); - nint n = values.Component0.Length / 8; + nint n = values.Component0.Length / Vector.Count; for (nint i = 0; i < n; i++) { ref Vector c = ref Unsafe.Add(ref cBase, i); diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleVector8.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleVector.cs similarity index 84% rename from src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleVector8.cs rename to src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleVector.cs index 6aa0b59a9..1ca329a12 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleVector8.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleVector.cs @@ -9,9 +9,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { internal abstract partial class JpegColorConverterBase { - internal sealed class FromGrayScaleVector8 : VectorizedJpegColorConverter + internal sealed class FromGrayScaleVector : VectorizedJpegColorConverter { - public FromGrayScaleVector8(int precision) + public FromGrayScaleVector(int precision) : base(JpegColorSpace.Grayscale, precision) { } @@ -23,7 +23,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters var scale = new Vector(1 / this.MaximumValue); - nint n = values.Component0.Length / 8; + nint n = values.Component0.Length / Vector.Count; for (nint i = 0; i < n; i++) { ref Vector c0 = ref Unsafe.Add(ref cBase, i); diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbVector8.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbVector.cs similarity index 89% rename from src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbVector8.cs rename to src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbVector.cs index 0dc440b7d..b2b059cdc 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbVector8.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbVector.cs @@ -9,9 +9,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { internal abstract partial class JpegColorConverterBase { - internal sealed class FromRgbVector8 : VectorizedJpegColorConverter + internal sealed class FromRgbVector : VectorizedJpegColorConverter { - public FromRgbVector8(int precision) + public FromRgbVector(int precision) : base(JpegColorSpace.RGB, precision) { } @@ -27,7 +27,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters var scale = new Vector(1 / this.MaximumValue); - nint n = values.Component0.Length / 8; + nint n = values.Component0.Length / Vector.Count; for (nint i = 0; i < n; i++) { ref Vector r = ref Unsafe.Add(ref rBase, i); diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrVector8.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrVector.cs similarity index 93% rename from src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrVector8.cs rename to src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrVector.cs index da71e2466..f34014332 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrVector8.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrVector.cs @@ -10,9 +10,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { internal abstract partial class JpegColorConverterBase { - internal sealed class FromYCbCrVector8 : VectorizedJpegColorConverter + internal sealed class FromYCbCrVector : VectorizedJpegColorConverter { - public FromYCbCrVector8(int precision) + public FromYCbCrVector(int precision) : base(JpegColorSpace.YCbCr, precision) { } @@ -34,7 +34,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters var gCrMult = new Vector(-FromYCbCrScalar.GCrMult); var bCbMult = new Vector(FromYCbCrScalar.BCbMult); - nint n = values.Component0.Length / 8; + nint n = values.Component0.Length / Vector.Count; for (nint i = 0; i < n; i++) { // y = yVals[i]; diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKVector8.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKVector.cs similarity index 94% rename from src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKVector8.cs rename to src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKVector.cs index 152a0793c..1e826c2c0 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKVector8.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKVector.cs @@ -9,9 +9,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { internal abstract partial class JpegColorConverterBase { - internal sealed class FromYccKVector8 : VectorizedJpegColorConverter + internal sealed class FromYccKVector : VectorizedJpegColorConverter { - public FromYccKVector8(int precision) + public FromYccKVector(int precision) : base(JpegColorSpace.Ycck, precision) { } @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters var gCrMult = new Vector(-FromYCbCrScalar.GCrMult); var bCbMult = new Vector(FromYCbCrScalar.BCbMult); - nint n = values.Component0.Length / 8; + nint n = values.Component0.Length / Vector.Count; for (nint i = 0; i < n; i++) { // y = yVals[i]; diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterBase.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterBase.cs index b8fd169e9..0ab7a108f 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterBase.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterBase.cs @@ -111,7 +111,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters #if SUPPORTS_RUNTIME_INTRINSICS yield return new FromYCbCrAvx(precision); #endif - yield return new FromYCbCrVector8(precision); + yield return new FromYCbCrVector(precision); yield return new FromYCbCrScalar(precision); } @@ -123,7 +123,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters #if SUPPORTS_RUNTIME_INTRINSICS yield return new FromYccKAvx(precision); #endif - yield return new FromYccKVector8(precision); + yield return new FromYccKVector(precision); yield return new FromYccKScalar(precision); } @@ -135,7 +135,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters #if SUPPORTS_RUNTIME_INTRINSICS yield return new FromCmykAvx(precision); #endif - yield return new FromCmykVector8(precision); + yield return new FromCmykVector(precision); yield return new FromCmykScalar(precision); } @@ -147,7 +147,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters #if SUPPORTS_RUNTIME_INTRINSICS yield return new FromGrayscaleAvx(precision); #endif - yield return new FromGrayScaleVector8(precision); + yield return new FromGrayScaleVector(precision); yield return new FromGrayscaleScalar(precision); } @@ -159,7 +159,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters #if SUPPORTS_RUNTIME_INTRINSICS yield return new FromRgbAvx(precision); #endif - yield return new FromRgbVector8(precision); + yield return new FromRgbVector(precision); yield return new FromRgbScalar(precision); } diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterVector.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterVector.cs index 3cd295f0b..42f6cab5c 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterVector.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterVector.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. using System; +using System.Numerics; namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { @@ -9,7 +10,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { /// /// abstract base for implementations - /// based on API. + /// based on API. /// /// /// Converters of this family can work with data of any size. @@ -25,27 +26,26 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { } - public sealed override bool IsAvailable => SimdUtils.HasVector8; + public sealed override bool IsAvailable => Vector.Count % 4 == 0; public override void ConvertToRgbInplace(in ComponentValues values) { + DebugGuard.IsTrue(this.IsAvailable, $"{this.GetType().Name} converter is not supported on current hardware"); + int length = values.Component0.Length; - int remainder = values.Component0.Length % 8; + int remainder = values.Component0.Length % Vector.Count; + + // Jpeg images are guaranteed to have pixel strides at least 8 pixels wide + // Thus there's no need to check whether simdCount is greater than zero int simdCount = length - remainder; - if (simdCount > 0) + this.ConvertCoreVectorizedInplace(values.Slice(0, simdCount)); + + // There's actually a lot of image/photo resolutions which won't have + // a remainder so it's better to check here than spend useless virtual call + if (remainder > 0) { - // This implementation is actually AVX specific. - // An AVX register is capable of storing 8 float-s. - if (!this.IsAvailable) - { - throw new InvalidOperationException( - "This converter can be used only on architecture having 256 byte floating point SIMD registers!"); - } - - this.ConvertCoreVectorizedInplace(values.Slice(0, simdCount)); + this.ConvertCoreInplace(values.Slice(simdCount, remainder)); } - - this.ConvertCoreInplace(values.Slice(simdCount, remainder)); } protected virtual void ConvertCoreVectorizedInplace(in ComponentValues values) => throw new NotImplementedException(); diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/CmykColorConversion.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/CmykColorConversion.cs index 36e666957..0f791ed8e 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/CmykColorConversion.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/CmykColorConversion.cs @@ -27,7 +27,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg { var values = new JpegColorConverterBase.ComponentValues(this.Input, 0); - new JpegColorConverterBase.FromCmykVector8(8).ConvertToRgbInplace(values); + new JpegColorConverterBase.FromCmykVector(8).ConvertToRgbInplace(values); } #if SUPPORTS_RUNTIME_INTRINSICS diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/RgbColorConversion.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/RgbColorConversion.cs index 69c1a3974..987a93194 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/RgbColorConversion.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/RgbColorConversion.cs @@ -27,7 +27,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg { var values = new JpegColorConverterBase.ComponentValues(this.Input, 0); - new JpegColorConverterBase.FromRgbVector8(8).ConvertToRgbInplace(values); + new JpegColorConverterBase.FromRgbVector(8).ConvertToRgbInplace(values); } #if SUPPORTS_RUNTIME_INTRINSICS diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/YCbCrColorConversion.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/YCbCrColorConversion.cs index 656cae104..8d6846033 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/YCbCrColorConversion.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/YCbCrColorConversion.cs @@ -27,7 +27,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg { var values = new JpegColorConverterBase.ComponentValues(this.Input, 0); - new JpegColorConverterBase.FromYCbCrVector8(8).ConvertToRgbInplace(values); + new JpegColorConverterBase.FromYCbCrVector(8).ConvertToRgbInplace(values); } #if SUPPORTS_RUNTIME_INTRINSICS diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/YccKColorConverter.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/YccKColorConverter.cs index 6c0583b62..7e9edc918 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/YccKColorConverter.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/YccKColorConverter.cs @@ -27,7 +27,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg { var values = new JpegColorConverterBase.ComponentValues(this.Input, 0); - new JpegColorConverterBase.FromYccKVector8(8).ConvertToRgbInplace(values); + new JpegColorConverterBase.FromYccKVector(8).ConvertToRgbInplace(values); } #if SUPPORTS_RUNTIME_INTRINSICS diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs index 7b91e1a8a..fbbb73b15 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs @@ -63,7 +63,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg } ValidateConversion( - new JpegColorConverterBase.FromYCbCrVector8(8), + new JpegColorConverterBase.FromYCbCrVector(8), 3, inputBufferLength, resultBufferLength, @@ -128,7 +128,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg } ValidateConversion( - new JpegColorConverterBase.FromCmykVector8(8), + new JpegColorConverterBase.FromCmykVector(8), 4, inputBufferLength, resultBufferLength, @@ -240,7 +240,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg } ValidateConversion( - new JpegColorConverterBase.FromRgbVector8(8), + new JpegColorConverterBase.FromRgbVector(8), 3, inputBufferLength, resultBufferLength, @@ -305,7 +305,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg } ValidateConversion( - new JpegColorConverterBase.FromYccKVector8(8), + new JpegColorConverterBase.FromYccKVector(8), 4, inputBufferLength, resultBufferLength, From aa2422453126365b96f2c80e632e3c55c49e6d32 Mon Sep 17 00:00:00 2001 From: Dmitry Pentin Date: Thu, 2 Dec 2021 10:54:46 +0300 Subject: [PATCH 21/65] CMYK to RGB converter performance tweaks --- .../ColorConverters/JpegColorConverter.FromCmykAvx.cs | 8 ++++---- .../JpegColorConverter.FromCmykScalar.cs | 11 ++++++----- .../JpegColorConverter.FromCmykVector.cs | 11 ++++++----- 3 files changed, 16 insertions(+), 14 deletions(-) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykAvx.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykAvx.cs index 4c89fc6fa..d627f7eaf 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykAvx.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykAvx.cs @@ -30,7 +30,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component3)); // Used for the color conversion - var scale = Vector256.Create(1 / this.MaximumValue); + var scale = Vector256.Create(1 / (this.MaximumValue * this.MaximumValue)); nint n = values.Component0.Length / Vector256.Count; for (nint i = 0; i < n; i++) @@ -41,9 +41,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters Vector256 k = Unsafe.Add(ref c3Base, i); k = Avx.Multiply(k, scale); - c = Avx.Multiply(Avx.Multiply(c, k), scale); - m = Avx.Multiply(Avx.Multiply(m, k), scale); - y = Avx.Multiply(Avx.Multiply(y, k), scale); + c = Avx.Multiply(c, k); + m = Avx.Multiply(m, k); + y = Avx.Multiply(y, k); } } } diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykScalar.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykScalar.cs index 057d7846a..e70aa7cb4 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykScalar.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykScalar.cs @@ -24,17 +24,18 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters Span c2 = values.Component2; Span c3 = values.Component3; - float scale = 1 / maxValue; + float scale = 1 / (maxValue * maxValue); for (int i = 0; i < c0.Length; i++) { float c = c0[i]; float m = c1[i]; float y = c2[i]; - float k = c3[i] / maxValue; + float k = c3[i]; - c0[i] = c * k * scale; - c1[i] = m * k * scale; - c2[i] = y * k * scale; + k *= scale; + c0[i] = c * k; + c1[i] = m * k; + c2[i] = y * k; } } } diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykVector.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykVector.cs index 9b123547b..8fd918140 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykVector.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykVector.cs @@ -27,7 +27,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters ref Vector kBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component3)); - var scale = new Vector(1 / this.MaximumValue); + var scale = new Vector(1 / (this.MaximumValue * this.MaximumValue)); nint n = values.Component0.Length / Vector.Count; for (nint i = 0; i < n; i++) @@ -35,11 +35,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters ref Vector c = ref Unsafe.Add(ref cBase, i); ref Vector m = ref Unsafe.Add(ref mBase, i); ref Vector y = ref Unsafe.Add(ref yBase, i); - Vector k = Unsafe.Add(ref kBase, i) * scale; + Vector k = Unsafe.Add(ref kBase, i); - c = c * k * scale; - m = m * k * scale; - y = y * k * scale; + k *= scale; + c *= k; + m *= k; + y *= k; } } From 5605de5b19c8462848e91b22c23b3ae04bb51d2b Mon Sep 17 00:00:00 2001 From: Dmitry Pentin Date: Thu, 2 Dec 2021 11:13:00 +0300 Subject: [PATCH 22/65] Fixed existing tests, added grayscale vector test and fixed tests naming --- .../Formats/Jpg/JpegColorConverterTests.cs | 65 ++++++++++++++----- 1 file changed, 49 insertions(+), 16 deletions(-) diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs index fbbb73b15..75d12710d 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs @@ -54,16 +54,19 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg [Theory] [MemberData(nameof(CommonConversionData))] - public void FromYCbCrVector8(int inputBufferLength, int resultBufferLength, int seed) + public void FromYCbCrVector(int inputBufferLength, int resultBufferLength, int seed) { - if (!SimdUtils.HasVector8) + var converter = new JpegColorConverterBase.FromYCbCrVector(8); + + if (!converter.IsAvailable) { - this.Output.WriteLine("No AVX2 present, skipping test!"); + this.Output.WriteLine( + $"Skipping test - {converter.GetType().Name} is not supported on current hardware."); return; } ValidateConversion( - new JpegColorConverterBase.FromYCbCrVector(8), + converter, 3, inputBufferLength, resultBufferLength, @@ -119,16 +122,19 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg [Theory] [MemberData(nameof(CommonConversionData))] - public void FromCmykVector8(int inputBufferLength, int resultBufferLength, int seed) + public void FromCmykVector(int inputBufferLength, int resultBufferLength, int seed) { - if (!SimdUtils.HasVector8) + var converter = new JpegColorConverterBase.FromCmykVector(8); + + if (!converter.IsAvailable) { - this.Output.WriteLine("No AVX2 present, skipping test!"); + this.Output.WriteLine( + $"Skipping test - {converter.GetType().Name} is not supported on current hardware."); return; } ValidateConversion( - new JpegColorConverterBase.FromCmykVector(8), + converter, 4, inputBufferLength, resultBufferLength, @@ -182,6 +188,27 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg seed); } + [Theory] + [MemberData(nameof(CommonConversionData))] + public void FromGrayscaleVector(int inputBufferLength, int resultBufferLength, int seed) + { + var converter = new JpegColorConverterBase.FromGrayScaleVector(8); + + if (!converter.IsAvailable) + { + this.Output.WriteLine( + $"Skipping test - {converter.GetType().Name} is not supported on current hardware."); + return; + } + + ValidateConversion( + converter, + 1, + inputBufferLength, + resultBufferLength, + seed); + } + #if SUPPORTS_RUNTIME_INTRINSICS [Theory] [MemberData(nameof(CommonConversionData))] @@ -231,16 +258,19 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg [Theory] [MemberData(nameof(CommonConversionData))] - public void FromRgbVector8(int inputBufferLength, int resultBufferLength, int seed) + public void FromRgbVector(int inputBufferLength, int resultBufferLength, int seed) { - if (!SimdUtils.HasVector8) + var converter = new JpegColorConverterBase.FromRgbVector(8); + + if (!converter.IsAvailable) { - this.Output.WriteLine("No AVX2 present, skipping test!"); + this.Output.WriteLine( + $"Skipping test - {converter.GetType().Name} is not supported on current hardware."); return; } ValidateConversion( - new JpegColorConverterBase.FromRgbVector(8), + converter, 3, inputBufferLength, resultBufferLength, @@ -296,16 +326,19 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg [Theory] [MemberData(nameof(CommonConversionData))] - public void FromYccKVector8(int inputBufferLength, int resultBufferLength, int seed) + public void FromYccKVector(int inputBufferLength, int resultBufferLength, int seed) { - if (!SimdUtils.HasVector8) + var converter = new JpegColorConverterBase.FromYccKVector(8); + + if (!converter.IsAvailable) { - this.Output.WriteLine("No AVX2 present, skipping test!"); + this.Output.WriteLine( + $"Skipping test - {converter.GetType().Name} is not supported on current hardware."); return; } ValidateConversion( - new JpegColorConverterBase.FromYccKVector(8), + converter, 4, inputBufferLength, resultBufferLength, From f10fe55844f8fe9c6cabca11b412013e6a396118 Mon Sep 17 00:00:00 2001 From: Dmitry Pentin Date: Thu, 2 Dec 2021 11:44:00 +0300 Subject: [PATCH 23/65] Added tests, removed duplicated tests --- .../Jpeg/Components/Decoder/JpegColorSpace.cs | 15 +++ .../Formats/Jpg/JpegColorConverterTests.cs | 109 ++++++++---------- 2 files changed, 64 insertions(+), 60 deletions(-) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegColorSpace.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegColorSpace.cs index 90162aba3..7ef280932 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegColorSpace.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegColorSpace.cs @@ -10,14 +10,29 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder { Undefined = 0, + /// + /// Color space with 1 component. + /// Grayscale, + /// + /// Color space with 4 components. + /// Ycck, + /// + /// Color space with 4 components. + /// Cmyk, + /// + /// Color space with 3 components. + /// RGB, + /// + /// Color space with 3 components. + /// YCbCr } } diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs index 75d12710d..5c2f45307 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs @@ -40,6 +40,55 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg private ITestOutputHelper Output { get; } + [Fact] + public void GetConverterThrowsExceptionOnInvalidColorSpace() + { + Assert.Throws(() => JpegColorConverterBase.GetConverter(JpegColorSpace.Undefined, 8)); + } + + [Fact] + public void GetConverterThrowsExceptionOnInvalidPrecision() + { + // Valid precisions: 8 & 12 bit + Assert.Throws(() => JpegColorConverterBase.GetConverter(JpegColorSpace.YCbCr, 9)); + } + + [Theory] + [InlineData(JpegColorSpace.Grayscale, 8)] + [InlineData(JpegColorSpace.Grayscale, 12)] + [InlineData(JpegColorSpace.Ycck, 8)] + [InlineData(JpegColorSpace.Ycck, 12)] + [InlineData(JpegColorSpace.Cmyk, 8)] + [InlineData(JpegColorSpace.Cmyk, 12)] + [InlineData(JpegColorSpace.RGB, 8)] + [InlineData(JpegColorSpace.RGB, 12)] + [InlineData(JpegColorSpace.YCbCr, 8)] + [InlineData(JpegColorSpace.YCbCr, 12)] + internal void GetConverterReturnsValidConverter(JpegColorSpace colorSpace, int precision) + { + var converter = JpegColorConverterBase.GetConverter(colorSpace, precision); + + Assert.NotNull(converter); + Assert.Equal(colorSpace, converter.ColorSpace); + Assert.Equal(precision, converter.Precision); + } + + [Theory] + [InlineData(JpegColorSpace.Grayscale, 1)] + [InlineData(JpegColorSpace.Ycck, 4)] + [InlineData(JpegColorSpace.Cmyk, 4)] + [InlineData(JpegColorSpace.RGB, 3)] + [InlineData(JpegColorSpace.YCbCr, 3)] + internal void ConvertWithSelectedConverter(JpegColorSpace colorSpace, int componentCount) + { + ValidateConversion( + colorSpace, + componentCount, + 40, + 40, + 1); + } + [Theory] [MemberData(nameof(CommonConversionData))] public void FromYCbCrBasic(int inputBufferLength, int resultBufferLength, int seed) @@ -96,18 +145,6 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg } #endif - [Theory] - [MemberData(nameof(CommonConversionData))] - public void FromYCbCr_WithDefaultConverter(int inputBufferLength, int resultBufferLength, int seed) - { - ValidateConversion( - JpegColorSpace.YCbCr, - 3, - inputBufferLength, - resultBufferLength, - seed); - } - [Theory] [MemberData(nameof(CommonConversionData))] public void FromCmykBasic(int inputBufferLength, int resultBufferLength, int seed) @@ -164,18 +201,6 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg } #endif - [Theory] - [MemberData(nameof(CommonConversionData))] - public void FromCmyk_WithDefaultConverter(int inputBufferLength, int resultBufferLength, int seed) - { - ValidateConversion( - JpegColorSpace.Cmyk, - 4, - inputBufferLength, - resultBufferLength, - seed); - } - [Theory] [MemberData(nameof(CommonConversionData))] public void FromGrayscaleBasic(int inputBufferLength, int resultBufferLength, int seed) @@ -232,18 +257,6 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg } #endif - [Theory] - [MemberData(nameof(CommonConversionData))] - public void FromGraysacle_WithDefaultConverter(int inputBufferLength, int resultBufferLength, int seed) - { - ValidateConversion( - JpegColorSpace.Grayscale, - 1, - inputBufferLength, - resultBufferLength, - seed); - } - [Theory] [MemberData(nameof(CommonConversionData))] public void FromRgbBasic(int inputBufferLength, int resultBufferLength, int seed) @@ -300,18 +313,6 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg } #endif - [Theory] - [MemberData(nameof(CommonConversionData))] - public void FromRgb_WithDefaultConverter(int inputBufferLength, int resultBufferLength, int seed) - { - ValidateConversion( - JpegColorSpace.RGB, - 3, - inputBufferLength, - resultBufferLength, - seed); - } - [Theory] [MemberData(nameof(CommonConversionData))] public void FromYccKBasic(int inputBufferLength, int resultBufferLength, int seed) @@ -368,18 +369,6 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg } #endif - [Theory] - [MemberData(nameof(CommonConversionData))] - public void FromYcck_WithDefaultConverter(int inputBufferLength, int resultBufferLength, int seed) - { - ValidateConversion( - JpegColorSpace.Ycck, - 4, - inputBufferLength, - resultBufferLength, - seed); - } - private static JpegColorConverterBase.ComponentValues CreateRandomValues( int componentCount, int inputBufferLength, From 854b22e8f1d6ce61f9b23de5606ee24bd881dc55 Mon Sep 17 00:00:00 2001 From: Dmitry Pentin Date: Thu, 2 Dec 2021 12:04:00 +0300 Subject: [PATCH 24/65] Fixed tests --- .../Formats/Jpg/JpegColorConverterTests.cs | 130 ++++++------------ 1 file changed, 44 insertions(+), 86 deletions(-) diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs index 5c2f45307..b34c8e997 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs @@ -20,18 +20,13 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg { private const float Precision = 0.1F / 255; - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(Precision); + private const int TestBufferLength = 40; - // int inputBufferLength, int resultBufferLength, int seed - public static readonly TheoryData CommonConversionData = - new TheoryData - { - { 40, 40, 1 }, - { 42, 40, 2 }, - { 42, 39, 3 } - }; + private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new(Precision); + + public static readonly TheoryData Seeds = new() { 1, 2, 3 }; - private static readonly ColorSpaceConverter ColorSpaceConverter = new ColorSpaceConverter(); + private static readonly ColorSpaceConverter ColorSpaceConverter = new(); public JpegColorConverterTests(ITestOutputHelper output) { @@ -84,26 +79,22 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg ValidateConversion( colorSpace, componentCount, - 40, - 40, 1); } [Theory] - [MemberData(nameof(CommonConversionData))] - public void FromYCbCrBasic(int inputBufferLength, int resultBufferLength, int seed) + [MemberData(nameof(Seeds))] + public void FromYCbCrBasic(int seed) { ValidateConversion( new JpegColorConverterBase.FromYCbCrScalar(8), 3, - inputBufferLength, - resultBufferLength, seed); } [Theory] - [MemberData(nameof(CommonConversionData))] - public void FromYCbCrVector(int inputBufferLength, int resultBufferLength, int seed) + [MemberData(nameof(Seeds))] + public void FromYCbCrVector(int seed) { var converter = new JpegColorConverterBase.FromYCbCrVector(8); @@ -117,15 +108,13 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg ValidateConversion( converter, 3, - inputBufferLength, - resultBufferLength, seed); } #if SUPPORTS_RUNTIME_INTRINSICS [Theory] - [MemberData(nameof(CommonConversionData))] - public void FromYCbCrAvx2(int inputBufferLength, int resultBufferLength, int seed) + [MemberData(nameof(Seeds))] + public void FromYCbCrAvx2(int seed) { var converter = new JpegColorConverterBase.FromYCbCrAvx(8); @@ -139,27 +128,23 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg ValidateConversion( converter, 3, - inputBufferLength, - resultBufferLength, seed); } #endif [Theory] - [MemberData(nameof(CommonConversionData))] - public void FromCmykBasic(int inputBufferLength, int resultBufferLength, int seed) + [MemberData(nameof(Seeds))] + public void FromCmykBasic(int seed) { ValidateConversion( new JpegColorConverterBase.FromCmykScalar(8), 4, - inputBufferLength, - resultBufferLength, seed); } [Theory] - [MemberData(nameof(CommonConversionData))] - public void FromCmykVector(int inputBufferLength, int resultBufferLength, int seed) + [MemberData(nameof(Seeds))] + public void FromCmykVector(int seed) { var converter = new JpegColorConverterBase.FromCmykVector(8); @@ -173,15 +158,13 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg ValidateConversion( converter, 4, - inputBufferLength, - resultBufferLength, seed); } #if SUPPORTS_RUNTIME_INTRINSICS [Theory] - [MemberData(nameof(CommonConversionData))] - public void FromCmykAvx2(int inputBufferLength, int resultBufferLength, int seed) + [MemberData(nameof(Seeds))] + public void FromCmykAvx2(int seed) { var converter = new JpegColorConverterBase.FromCmykAvx(8); @@ -195,27 +178,23 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg ValidateConversion( converter, 4, - inputBufferLength, - resultBufferLength, seed); } #endif [Theory] - [MemberData(nameof(CommonConversionData))] - public void FromGrayscaleBasic(int inputBufferLength, int resultBufferLength, int seed) + [MemberData(nameof(Seeds))] + public void FromGrayscaleBasic(int seed) { ValidateConversion( new JpegColorConverterBase.FromGrayscaleScalar(8), 1, - inputBufferLength, - resultBufferLength, seed); } [Theory] - [MemberData(nameof(CommonConversionData))] - public void FromGrayscaleVector(int inputBufferLength, int resultBufferLength, int seed) + [MemberData(nameof(Seeds))] + public void FromGrayscaleVector(int seed) { var converter = new JpegColorConverterBase.FromGrayScaleVector(8); @@ -229,15 +208,13 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg ValidateConversion( converter, 1, - inputBufferLength, - resultBufferLength, seed); } #if SUPPORTS_RUNTIME_INTRINSICS [Theory] - [MemberData(nameof(CommonConversionData))] - public void FromGrayscaleAvx2(int inputBufferLength, int resultBufferLength, int seed) + [MemberData(nameof(Seeds))] + public void FromGrayscaleAvx2(int seed) { var converter = new JpegColorConverterBase.FromGrayscaleAvx(8); @@ -251,27 +228,23 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg ValidateConversion( converter, 1, - inputBufferLength, - resultBufferLength, seed); } #endif [Theory] - [MemberData(nameof(CommonConversionData))] - public void FromRgbBasic(int inputBufferLength, int resultBufferLength, int seed) + [MemberData(nameof(Seeds))] + public void FromRgbBasic(int seed) { ValidateConversion( new JpegColorConverterBase.FromRgbScalar(8), 3, - inputBufferLength, - resultBufferLength, seed); } [Theory] - [MemberData(nameof(CommonConversionData))] - public void FromRgbVector(int inputBufferLength, int resultBufferLength, int seed) + [MemberData(nameof(Seeds))] + public void FromRgbVector(int seed) { var converter = new JpegColorConverterBase.FromRgbVector(8); @@ -285,15 +258,13 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg ValidateConversion( converter, 3, - inputBufferLength, - resultBufferLength, seed); } #if SUPPORTS_RUNTIME_INTRINSICS [Theory] - [MemberData(nameof(CommonConversionData))] - public void FromRgbAvx2(int inputBufferLength, int resultBufferLength, int seed) + [MemberData(nameof(Seeds))] + public void FromRgbAvx2(int seed) { var converter = new JpegColorConverterBase.FromRgbAvx(8); @@ -307,27 +278,23 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg ValidateConversion( converter, 3, - inputBufferLength, - resultBufferLength, seed); } #endif [Theory] - [MemberData(nameof(CommonConversionData))] - public void FromYccKBasic(int inputBufferLength, int resultBufferLength, int seed) + [MemberData(nameof(Seeds))] + public void FromYccKBasic(int seed) { ValidateConversion( new JpegColorConverterBase.FromYccKScalar(8), 4, - inputBufferLength, - resultBufferLength, seed); } [Theory] - [MemberData(nameof(CommonConversionData))] - public void FromYccKVector(int inputBufferLength, int resultBufferLength, int seed) + [MemberData(nameof(Seeds))] + public void FromYccKVector(int seed) { var converter = new JpegColorConverterBase.FromYccKVector(8); @@ -341,15 +308,13 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg ValidateConversion( converter, 4, - inputBufferLength, - resultBufferLength, seed); } #if SUPPORTS_RUNTIME_INTRINSICS [Theory] - [MemberData(nameof(CommonConversionData))] - public void FromYccKAvx2(int inputBufferLength, int resultBufferLength, int seed) + [MemberData(nameof(Seeds))] + public void FromYccKAvx2(int seed) { var converter = new JpegColorConverterBase.FromYccKAvx(8); @@ -363,27 +328,26 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg ValidateConversion( converter, 4, - inputBufferLength, - resultBufferLength, seed); } #endif private static JpegColorConverterBase.ComponentValues CreateRandomValues( + int length, int componentCount, - int inputBufferLength, - int seed, - float minVal = 0f, - float maxVal = 255f) + int seed) { + const float minVal = 0f; + const float maxVal = Precision; + var rnd = new Random(seed); var buffers = new Buffer2D[componentCount]; for (int i = 0; i < componentCount; i++) { - var values = new float[inputBufferLength]; + float[] values = new float[length]; - for (int j = 0; j < inputBufferLength; j++) + for (int j = 0; j < values.Length; j++) { values[j] = ((float)rnd.NextDouble() * (maxVal - minVal)) + minVal; } @@ -400,31 +364,25 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg private static void ValidateConversion( JpegColorSpace colorSpace, int componentCount, - int inputBufferLength, - int resultBufferLength, int seed) { ValidateConversion( JpegColorConverterBase.GetConverter(colorSpace, 8), componentCount, - inputBufferLength, - resultBufferLength, seed); } private static void ValidateConversion( JpegColorConverterBase converter, int componentCount, - int inputBufferLength, - int resultBufferLength, int seed) { - JpegColorConverterBase.ComponentValues original = CreateRandomValues(componentCount, inputBufferLength, seed); + JpegColorConverterBase.ComponentValues original = CreateRandomValues(TestBufferLength, componentCount, seed); JpegColorConverterBase.ComponentValues values = Copy(original); converter.ConvertToRgbInplace(values); - for (int i = 0; i < resultBufferLength; i++) + for (int i = 0; i < TestBufferLength; i++) { Validate(converter.ColorSpace, original, values, i); } From 9ec9b5a9876a3860286b48e0426c314014c988e5 Mon Sep 17 00:00:00 2001 From: Dmitry Pentin Date: Thu, 2 Dec 2021 12:26:28 +0300 Subject: [PATCH 25/65] Added avx/no-avx runs to every Vector API based test --- .../Formats/Jpg/JpegColorConverterTests.cs | 87 ++++++++++++------- 1 file changed, 54 insertions(+), 33 deletions(-) diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs index b34c8e997..067f59aeb 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs @@ -9,7 +9,7 @@ using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder; using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - +using SixLabors.ImageSharp.Tests.TestUtilities; using Xunit; using Xunit.Abstractions; @@ -64,6 +64,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg var converter = JpegColorConverterBase.GetConverter(colorSpace, precision); Assert.NotNull(converter); + Assert.True(converter.IsAvailable); Assert.Equal(colorSpace, converter.ColorSpace); Assert.Equal(precision, converter.Precision); } @@ -76,8 +77,9 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg [InlineData(JpegColorSpace.YCbCr, 3)] internal void ConvertWithSelectedConverter(JpegColorSpace colorSpace, int componentCount) { + var converter = JpegColorConverterBase.GetConverter(colorSpace, 8); ValidateConversion( - colorSpace, + converter, componentCount, 1); } @@ -105,10 +107,16 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg return; } - ValidateConversion( - converter, - 3, - seed); + FeatureTestRunner.RunWithHwIntrinsicsFeature( + RunTest, + seed, + HwIntrinsics.AllowAll | HwIntrinsics.DisableAVX); + + static void RunTest(string arg) => + ValidateConversion( + new JpegColorConverterBase.FromYCbCrVector(8), + 3, + FeatureTestRunner.Deserialize(arg)); } #if SUPPORTS_RUNTIME_INTRINSICS @@ -155,10 +163,16 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg return; } - ValidateConversion( - converter, - 4, - seed); + FeatureTestRunner.RunWithHwIntrinsicsFeature( + RunTest, + seed, + HwIntrinsics.AllowAll | HwIntrinsics.DisableAVX); + + static void RunTest(string arg) => + ValidateConversion( + new JpegColorConverterBase.FromCmykVector(8), + 4, + FeatureTestRunner.Deserialize(arg)); } #if SUPPORTS_RUNTIME_INTRINSICS @@ -205,10 +219,16 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg return; } - ValidateConversion( - converter, - 1, - seed); + FeatureTestRunner.RunWithHwIntrinsicsFeature( + RunTest, + seed, + HwIntrinsics.AllowAll | HwIntrinsics.DisableAVX); + + static void RunTest(string arg) => + ValidateConversion( + new JpegColorConverterBase.FromGrayScaleVector(8), + 1, + FeatureTestRunner.Deserialize(arg)); } #if SUPPORTS_RUNTIME_INTRINSICS @@ -255,10 +275,16 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg return; } - ValidateConversion( - converter, - 3, - seed); + FeatureTestRunner.RunWithHwIntrinsicsFeature( + RunTest, + seed, + HwIntrinsics.AllowAll | HwIntrinsics.DisableAVX); + + static void RunTest(string arg) => + ValidateConversion( + new JpegColorConverterBase.FromRgbVector(8), + 3, + FeatureTestRunner.Deserialize(arg)); } #if SUPPORTS_RUNTIME_INTRINSICS @@ -305,10 +331,16 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg return; } - ValidateConversion( - converter, - 4, - seed); + FeatureTestRunner.RunWithHwIntrinsicsFeature( + RunTest, + seed, + HwIntrinsics.AllowAll | HwIntrinsics.DisableAVX); + + static void RunTest(string arg) => + ValidateConversion( + new JpegColorConverterBase.FromYccKVector(8), + 4, + FeatureTestRunner.Deserialize(arg)); } #if SUPPORTS_RUNTIME_INTRINSICS @@ -361,17 +393,6 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg return new JpegColorConverterBase.ComponentValues(buffers, 0); } - private static void ValidateConversion( - JpegColorSpace colorSpace, - int componentCount, - int seed) - { - ValidateConversion( - JpegColorConverterBase.GetConverter(colorSpace, 8), - componentCount, - seed); - } - private static void ValidateConversion( JpegColorConverterBase converter, int componentCount, From ffd1ea8a3532c23ca63ec307ae0b4ef9f01dfaa2 Mon Sep 17 00:00:00 2001 From: Dmitry Pentin Date: Thu, 2 Dec 2021 12:32:04 +0300 Subject: [PATCH 26/65] Fixed comments --- .../Decoder/ColorConverters/JpegColorConverterVector.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterVector.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterVector.cs index 42f6cab5c..c04591a28 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterVector.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterVector.cs @@ -40,8 +40,11 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters int simdCount = length - remainder; this.ConvertCoreVectorizedInplace(values.Slice(0, simdCount)); - // There's actually a lot of image/photo resolutions which won't have - // a remainder so it's better to check here than spend useless virtual call + // Jpeg images width is always divisible by 8 without a remainder + // so it's safe to say SSE/AVX implementations would never have + // 'remainder' pixels + // But some exotic simd implementations e.g. AVX-512 can have + // remainder pixels if (remainder > 0) { this.ConvertCoreInplace(values.Slice(simdCount, remainder)); From a26a758011713da068a24251111486808ba18050 Mon Sep 17 00:00:00 2001 From: Dmitry Pentin Date: Fri, 3 Dec 2021 07:24:24 +0300 Subject: [PATCH 27/65] Removed redundant allocations, fixed assertion & switch-case --- .../Formats/Jpg/JpegColorConverterTests.cs | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs index 067f59aeb..3ebc137fa 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs @@ -399,7 +399,12 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg int seed) { JpegColorConverterBase.ComponentValues original = CreateRandomValues(TestBufferLength, componentCount, seed); - JpegColorConverterBase.ComponentValues values = Copy(original); + JpegColorConverterBase.ComponentValues values = new( + original.ComponentCount, + original.Component0, + original.Component1, + original.Component2, + original.Component3); converter.ConvertToRgbInplace(values); @@ -407,15 +412,6 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg { Validate(converter.ColorSpace, original, values, i); } - - static JpegColorConverterBase.ComponentValues Copy(JpegColorConverterBase.ComponentValues values) - { - Span c0 = values.Component0.ToArray(); - Span c1 = values.ComponentCount > 1 ? values.Component1.ToArray().AsSpan() : c0; - Span c2 = values.ComponentCount > 2 ? values.Component2.ToArray().AsSpan() : c0; - Span c3 = values.ComponentCount > 3 ? values.Component3.ToArray().AsSpan() : Span.Empty; - return new JpegColorConverterBase.ComponentValues(values.ComponentCount, c0, c1, c2, c3); - } } private static void Validate( @@ -441,8 +437,9 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg case JpegColorSpace.YCbCr: ValidateYCbCr(original, result, i); break; + case JpegColorSpace.Undefined: default: - Assert.True(false, $"Colorspace {colorSpace} not supported!"); + Assert.True(false, $"Invalid Colorspace enum value: {colorSpace}."); break; } } From 5b62e94b26450fe5ad08813c61904f63a7681830 Mon Sep 17 00:00:00 2001 From: Dmitry Pentin Date: Fri, 3 Dec 2021 08:11:09 +0300 Subject: [PATCH 28/65] Minor fixes --- .../Decoder/ColorConverters/JpegColorConverterVector.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterVector.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterVector.cs index c04591a28..523ac8896 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterVector.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterVector.cs @@ -26,14 +26,14 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { } - public sealed override bool IsAvailable => Vector.Count % 4 == 0; + public sealed override bool IsAvailable => Vector.IsHardwareAccelerated && Vector.Count % 4 == 0; public override void ConvertToRgbInplace(in ComponentValues values) { - DebugGuard.IsTrue(this.IsAvailable, $"{this.GetType().Name} converter is not supported on current hardware"); + DebugGuard.IsTrue(this.IsAvailable, $"{this.GetType().Name} converter is not supported on current hardware."); int length = values.Component0.Length; - int remainder = values.Component0.Length % Vector.Count; + int remainder = length % Vector.Count; // Jpeg images are guaranteed to have pixel strides at least 8 pixels wide // Thus there's no need to check whether simdCount is greater than zero From 09b2e54c7184124c37bc5a70657002b7e97f7f07 Mon Sep 17 00:00:00 2001 From: Dmitry Pentin Date: Fri, 3 Dec 2021 08:34:54 +0300 Subject: [PATCH 29/65] More robust test failure output --- .../Formats/Jpg/JpegColorConverterTests.cs | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs index 3ebc137fa..086ae30f3 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs @@ -454,7 +454,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg var actual = new Rgb(result.Component0[i], result.Component1[i], result.Component2[i]); var expected = ColorSpaceConverter.ToRgb(ycbcr); - Assert.Equal(expected, actual, ColorSpaceComparer); + bool equal = ColorSpaceComparer.Equals(expected, actual); + Assert.True(equal, $"Colors {expected} and {actual} are not equal at index {i}"); } private static void ValidateCyyK(in JpegColorConverterBase.ComponentValues values, in JpegColorConverterBase.ComponentValues result, int i) @@ -479,7 +480,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg var actual = new Rgb(result.Component0[i], result.Component1[i], result.Component2[i]); var expected = new Rgb(v.X, v.Y, v.Z); - Assert.Equal(expected, actual, ColorSpaceComparer); + bool equal = ColorSpaceComparer.Equals(expected, actual); + Assert.True(equal, $"Colors {expected} and {actual} are not equal at index {i}"); } private static void ValidateRgb(in JpegColorConverterBase.ComponentValues values, in JpegColorConverterBase.ComponentValues result, int i) @@ -491,7 +493,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg var actual = new Rgb(result.Component0[i], result.Component1[i], result.Component2[i]); var expected = new Rgb(r / 255F, g / 255F, b / 255F); - Assert.Equal(expected, actual, ColorSpaceComparer); + bool equal = ColorSpaceComparer.Equals(expected, actual); + Assert.True(equal, $"Colors {expected} and {actual} are not equal at index {i}"); } private static void ValidateGrayScale(in JpegColorConverterBase.ComponentValues values, in JpegColorConverterBase.ComponentValues result, int i) @@ -500,7 +503,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg var actual = new Rgb(result.Component0[i], result.Component0[i], result.Component0[i]); var expected = new Rgb(y / 255F, y / 255F, y / 255F); - Assert.Equal(expected, actual, ColorSpaceComparer); + bool equal = ColorSpaceComparer.Equals(expected, actual); + Assert.True(equal, $"Colors {expected} and {actual} are not equal at index {i}"); } private static void ValidateCmyk(in JpegColorConverterBase.ComponentValues values, in JpegColorConverterBase.ComponentValues result, int i) @@ -523,7 +527,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg var actual = new Rgb(result.Component0[i], result.Component1[i], result.Component2[i]); var expected = new Rgb(v.X, v.Y, v.Z); - Assert.Equal(expected, actual, ColorSpaceComparer); + bool equal = ColorSpaceComparer.Equals(expected, actual); + Assert.True(equal, $"Colors {expected} and {actual} are not equal at index {i}"); } } } From 26b3e664db2eb20d5ddb848dd0c01ea1b31c1c37 Mon Sep 17 00:00:00 2001 From: Ynse Hoornenborg Date: Fri, 3 Dec 2021 11:34:45 +0100 Subject: [PATCH 30/65] Fix bug in black and white plain decoding --- src/ImageSharp/Formats/Pbm/PlainDecoder.cs | 4 ++-- src/ImageSharp/Formats/Pbm/PlainEncoder.cs | 2 +- tests/ImageSharp.Tests/Formats/Pbm/PbmRoundTripTests.cs | 1 + 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/ImageSharp/Formats/Pbm/PlainDecoder.cs b/src/ImageSharp/Formats/Pbm/PlainDecoder.cs index bf2b10e1d..9fa8e513e 100644 --- a/src/ImageSharp/Formats/Pbm/PlainDecoder.cs +++ b/src/ImageSharp/Formats/Pbm/PlainDecoder.cs @@ -174,8 +174,8 @@ namespace SixLabors.ImageSharp.Formats.Pbm MemoryAllocator allocator = configuration.MemoryAllocator; using IMemoryOwner row = allocator.Allocate(width); Span rowSpan = row.GetSpan(); - var white = new L8(0); - var black = new L8(255); + var white = new L8(255); + var black = new L8(0); for (int y = 0; y < height; y++) { diff --git a/src/ImageSharp/Formats/Pbm/PlainEncoder.cs b/src/ImageSharp/Formats/Pbm/PlainEncoder.cs index 2e7c60e5e..8d534b7a9 100644 --- a/src/ImageSharp/Formats/Pbm/PlainEncoder.cs +++ b/src/ImageSharp/Formats/Pbm/PlainEncoder.cs @@ -230,7 +230,7 @@ namespace SixLabors.ImageSharp.Formats.Pbm int written = 0; for (int x = 0; x < width; x++) { - byte value = (rowSpan[x].PackedValue > 127) ? Zero : One; + byte value = (rowSpan[x].PackedValue < 128) ? One : Zero; plainSpan[written++] = value; plainSpan[written++] = Space; } diff --git a/tests/ImageSharp.Tests/Formats/Pbm/PbmRoundTripTests.cs b/tests/ImageSharp.Tests/Formats/Pbm/PbmRoundTripTests.cs index 1735efdce..cba75b2a0 100644 --- a/tests/ImageSharp.Tests/Formats/Pbm/PbmRoundTripTests.cs +++ b/tests/ImageSharp.Tests/Formats/Pbm/PbmRoundTripTests.cs @@ -14,6 +14,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Pbm public class PbmRoundTripTests { [Theory] + [InlineData(BlackAndWhitePlain)] [InlineData(BlackAndWhiteBinary)] [InlineData(GrayscalePlain)] [InlineData(GrayscaleBinary)] From c4cf012ac4f3eaf315ed23ff4161acf4a0a8d981 Mon Sep 17 00:00:00 2001 From: Ynse Hoornenborg Date: Fri, 3 Dec 2021 13:45:08 +0100 Subject: [PATCH 31/65] Scale pixel value up to full allocation range --- src/ImageSharp/Formats/Pbm/PbmDecoderCore.cs | 30 +++++++++++++++++++ .../Formats/Pbm/PbmDecoderTests.cs | 3 ++ .../Formats/Pbm/PbmRoundTripTests.cs | 2 ++ ...ecodeReferenceImage_L8_grayscale_plain.png | 3 ++ .../DecodeReferenceImage_Rgb24_rgb_plain.png | 3 ++ 5 files changed, 41 insertions(+) create mode 100644 tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L8_grayscale_plain.png create mode 100644 tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_Rgb24_rgb_plain.png diff --git a/src/ImageSharp/Formats/Pbm/PbmDecoderCore.cs b/src/ImageSharp/Formats/Pbm/PbmDecoderCore.cs index bd99a578a..427ea15e8 100644 --- a/src/ImageSharp/Formats/Pbm/PbmDecoderCore.cs +++ b/src/ImageSharp/Formats/Pbm/PbmDecoderCore.cs @@ -7,6 +7,7 @@ using SixLabors.ImageSharp.IO; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Metadata; using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Processing; namespace SixLabors.ImageSharp.Formats.Pbm { @@ -52,6 +53,23 @@ namespace SixLabors.ImageSharp.Formats.Pbm /// Size IImageDecoderInternals.Dimensions => this.PixelSize; + private bool NeedsUpscaling + { + get + { + bool needsUpscaling = false; + if (this.ColorType != PbmColorType.BlackAndWhite) + { + if (this.MaxPixelValue is not 255 and not 65535) + { + needsUpscaling = true; + } + } + + return needsUpscaling; + } + } + /// public Image Decode(BufferedReadStream stream, CancellationToken cancellationToken) where TPixel : unmanaged, IPixel @@ -63,6 +81,10 @@ namespace SixLabors.ImageSharp.Formats.Pbm Buffer2D pixels = image.GetRootFramePixelBuffer(); this.ProcessPixels(stream, pixels); + if (this.NeedsUpscaling) + { + this.ProcessUpscaling(image); + } return image; } @@ -165,5 +187,13 @@ namespace SixLabors.ImageSharp.Formats.Pbm PlainDecoder.Process(this.Configuration, pixels, stream, this.ColorType, this.MaxPixelValue); } } + + private void ProcessUpscaling(Image image) + where TPixel : unmanaged, IPixel + { + int maxAllocationValue = (this.MaxPixelValue > 255) ? 65535 : 255; + float factor = maxAllocationValue / this.MaxPixelValue; + image.Mutate(x => x.Brightness(factor)); + } } } diff --git a/tests/ImageSharp.Tests/Formats/Pbm/PbmDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Pbm/PbmDecoderTests.cs index 479db2ca5..8b8e1a08f 100644 --- a/tests/ImageSharp.Tests/Formats/Pbm/PbmDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Pbm/PbmDecoderTests.cs @@ -74,10 +74,13 @@ namespace SixLabors.ImageSharp.Tests.Formats.Pbm } [Theory] + [WithFile(BlackAndWhitePlain, PixelTypes.L8, true)] [WithFile(BlackAndWhiteBinary, PixelTypes.L8, true)] + [WithFile(GrayscalePlain, PixelTypes.L8, true)] [WithFile(GrayscalePlainNormalized, PixelTypes.L8, true)] [WithFile(GrayscaleBinary, PixelTypes.L8, true)] [WithFile(GrayscaleBinaryWide, PixelTypes.L16, true)] + [WithFile(RgbPlain, PixelTypes.Rgb24, false)] [WithFile(RgbPlainNormalized, PixelTypes.Rgb24, false)] [WithFile(RgbBinary, PixelTypes.Rgb24, false)] public void DecodeReferenceImage(TestImageProvider provider, bool isGrayscale) diff --git a/tests/ImageSharp.Tests/Formats/Pbm/PbmRoundTripTests.cs b/tests/ImageSharp.Tests/Formats/Pbm/PbmRoundTripTests.cs index cba75b2a0..9521ee7e9 100644 --- a/tests/ImageSharp.Tests/Formats/Pbm/PbmRoundTripTests.cs +++ b/tests/ImageSharp.Tests/Formats/Pbm/PbmRoundTripTests.cs @@ -17,6 +17,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Pbm [InlineData(BlackAndWhitePlain)] [InlineData(BlackAndWhiteBinary)] [InlineData(GrayscalePlain)] + [InlineData(GrayscalePlainNormalized)] [InlineData(GrayscaleBinary)] public void PbmGrayscaleImageCanRoundTrip(string imagePath) { @@ -36,6 +37,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Pbm [Theory] [InlineData(RgbPlain)] + [InlineData(RgbPlainNormalized)] [InlineData(RgbBinary)] public void PbmColorImageCanRoundTrip(string imagePath) { diff --git a/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L8_grayscale_plain.png b/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L8_grayscale_plain.png new file mode 100644 index 000000000..9c86c2fc1 --- /dev/null +++ b/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L8_grayscale_plain.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f8e8b8a1a05e76b1eeb577373c3a6f492e356f0dd58489afded248415cec4a07 +size 145 diff --git a/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_Rgb24_rgb_plain.png b/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_Rgb24_rgb_plain.png new file mode 100644 index 000000000..421a59849 --- /dev/null +++ b/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_Rgb24_rgb_plain.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c44322c4bf461acea27053057f5241afb029d9a1e66e94dcf1be6f86f7f97727 +size 152 From 09d056e42b2b56d65a2a2bc80e4adb94d1d80341 Mon Sep 17 00:00:00 2001 From: Dmitry Pentin Date: Fri, 3 Dec 2021 15:42:18 +0300 Subject: [PATCH 32/65] Fixed test bug introduced in one of previous commits, code cleanup --- .../Formats/Jpg/JpegColorConverterTests.cs | 42 ++++++++----------- 1 file changed, 17 insertions(+), 25 deletions(-) diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs index 086ae30f3..2c6b29382 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs @@ -18,11 +18,13 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg [Trait("Format", "Jpg")] public class JpegColorConverterTests { + private static readonly float MaxColorChannelValue = 255f; + private const float Precision = 0.1F / 255; private const int TestBufferLength = 40; - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new(Precision); + private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new(epsilon: Precision); public static readonly TheoryData Seeds = new() { 1, 2, 3 }; @@ -369,9 +371,6 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg int componentCount, int seed) { - const float minVal = 0f; - const float maxVal = Precision; - var rnd = new Random(seed); var buffers = new Buffer2D[componentCount]; @@ -381,7 +380,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg for (int j = 0; j < values.Length; j++) { - values[j] = ((float)rnd.NextDouble() * (maxVal - minVal)) + minVal; + values[j] = (float)rnd.NextDouble() * MaxColorChannelValue; } // no need to dispose when buffer is not array owner @@ -401,10 +400,10 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg JpegColorConverterBase.ComponentValues original = CreateRandomValues(TestBufferLength, componentCount, seed); JpegColorConverterBase.ComponentValues values = new( original.ComponentCount, - original.Component0, - original.Component1, - original.Component2, - original.Component3); + original.Component0.ToArray(), + original.Component1.ToArray(), + original.Component2.ToArray(), + original.Component3.ToArray()); converter.ConvertToRgbInplace(values); @@ -449,10 +448,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg float y = values.Component0[i]; float cb = values.Component1[i]; float cr = values.Component2[i]; - var ycbcr = new YCbCr(y, cb, cr); - + var expected = ColorSpaceConverter.ToRgb(new YCbCr(y, cb, cr)); var actual = new Rgb(result.Component0[i], result.Component1[i], result.Component2[i]); - var expected = ColorSpaceConverter.ToRgb(ycbcr); bool equal = ColorSpaceComparer.Equals(expected, actual); Assert.True(equal, $"Colors {expected} and {actual} are not equal at index {i}"); @@ -460,8 +457,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg private static void ValidateCyyK(in JpegColorConverterBase.ComponentValues values, in JpegColorConverterBase.ComponentValues result, int i) { - var v = new Vector4(0, 0, 0, 1F); - var scale = new Vector4(1 / 255F, 1 / 255F, 1 / 255F, 1F); + Vector4 v = Vector4.Zero; float y = values.Component0[i]; float cb = values.Component1[i] - 128F; @@ -475,10 +471,9 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg v.Z = (255F - (float)Math.Round(y + (1.772F * cb), MidpointRounding.AwayFromZero)) * k; v.W = 1F; - v *= scale; - - var actual = new Rgb(result.Component0[i], result.Component1[i], result.Component2[i]); + v /= new Vector4(MaxColorChannelValue, MaxColorChannelValue, MaxColorChannelValue, 1f); var expected = new Rgb(v.X, v.Y, v.Z); + var actual = new Rgb(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}"); @@ -489,9 +484,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg float r = values.Component0[i]; float g = values.Component1[i]; float b = values.Component2[i]; - + var expected = new Rgb(new Vector3(r, g, b) / new Vector3(MaxColorChannelValue)); var actual = new Rgb(result.Component0[i], result.Component1[i], result.Component2[i]); - var expected = new Rgb(r / 255F, g / 255F, b / 255F); bool equal = ColorSpaceComparer.Equals(expected, actual); Assert.True(equal, $"Colors {expected} and {actual} are not equal at index {i}"); @@ -500,8 +494,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg private static void ValidateGrayScale(in JpegColorConverterBase.ComponentValues values, in JpegColorConverterBase.ComponentValues result, int i) { float y = values.Component0[i]; + var expected = new Rgb(new Vector3(y) / new Vector3(MaxColorChannelValue)); var actual = new Rgb(result.Component0[i], result.Component0[i], result.Component0[i]); - var expected = new Rgb(y / 255F, y / 255F, y / 255F); bool equal = ColorSpaceComparer.Equals(expected, actual); Assert.True(equal, $"Colors {expected} and {actual} are not equal at index {i}"); @@ -509,8 +503,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg private static void ValidateCmyk(in JpegColorConverterBase.ComponentValues values, in JpegColorConverterBase.ComponentValues result, int i) { - var v = new Vector4(0, 0, 0, 1F); - var scale = new Vector4(1 / 255F, 1 / 255F, 1 / 255F, 1F); + Vector4 v = Vector4.Zero; float c = values.Component0[i]; float m = values.Component1[i]; @@ -522,10 +515,9 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg v.Z = y * k; v.W = 1F; - v *= scale; - - var actual = new Rgb(result.Component0[i], result.Component1[i], result.Component2[i]); + v /= new Vector4(MaxColorChannelValue, MaxColorChannelValue, MaxColorChannelValue, 1f); var expected = new Rgb(v.X, v.Y, v.Z); + var actual = new Rgb(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}"); From f3b35e8acba740cec6687da4ba806507337d63e1 Mon Sep 17 00:00:00 2001 From: Dmitry Pentin Date: Fri, 3 Dec 2021 16:42:21 +0300 Subject: [PATCH 33/65] Yet another 'fix' --- .../Formats/Jpg/JpegColorConverterTests.cs | 33 ++++++++++--------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs index 2c6b29382..22af74525 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs @@ -449,6 +449,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg float cb = values.Component1[i]; float cr = values.Component2[i]; var expected = ColorSpaceConverter.ToRgb(new YCbCr(y, cb, cr)); + var actual = new Rgb(result.Component0[i], result.Component1[i], result.Component2[i]); bool equal = ColorSpaceComparer.Equals(expected, actual); @@ -469,10 +470,12 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg y - (0.344136F * cb) - (0.714136F * cr), MidpointRounding.AwayFromZero)) * k; v.Z = (255F - (float)Math.Round(y + (1.772F * cb), MidpointRounding.AwayFromZero)) * k; - v.W = 1F; - v /= new Vector4(MaxColorChannelValue, MaxColorChannelValue, MaxColorChannelValue, 1f); - var expected = new Rgb(v.X, v.Y, v.Z); + float r = v.X / MaxColorChannelValue; + float g = v.Y / MaxColorChannelValue; + float b = v.Z / MaxColorChannelValue; + var expected = new Rgb(r, g, b); + var actual = new Rgb(result.Component0[i], result.Component1[i], result.Component2[i]); bool equal = ColorSpaceComparer.Equals(expected, actual); @@ -481,10 +484,11 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg private static void ValidateRgb(in JpegColorConverterBase.ComponentValues values, in JpegColorConverterBase.ComponentValues result, int i) { - float r = values.Component0[i]; - float g = values.Component1[i]; - float b = values.Component2[i]; - var expected = new Rgb(new Vector3(r, g, b) / new Vector3(MaxColorChannelValue)); + 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); + var actual = new Rgb(result.Component0[i], result.Component1[i], result.Component2[i]); bool equal = ColorSpaceComparer.Equals(expected, actual); @@ -493,8 +497,9 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg private static void ValidateGrayScale(in JpegColorConverterBase.ComponentValues values, in JpegColorConverterBase.ComponentValues result, int i) { - float y = values.Component0[i]; - var expected = new Rgb(new Vector3(y) / new Vector3(MaxColorChannelValue)); + float y = values.Component0[i] / MaxColorChannelValue; + var expected = new Rgb(y, y, y); + var actual = new Rgb(result.Component0[i], result.Component0[i], result.Component0[i]); bool equal = ColorSpaceComparer.Equals(expected, actual); @@ -510,13 +515,11 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg float y = values.Component2[i]; float k = values.Component3[i] / 255F; - v.X = c * k; - v.Y = m * k; - v.Z = y * k; - v.W = 1F; + float r = c * k / MaxColorChannelValue; + float g = m * k / MaxColorChannelValue; + float b = y * k / MaxColorChannelValue; + var expected = new Rgb(r, g, b); - v /= new Vector4(MaxColorChannelValue, MaxColorChannelValue, MaxColorChannelValue, 1f); - var expected = new Rgb(v.X, v.Y, v.Z); var actual = new Rgb(result.Component0[i], result.Component1[i], result.Component2[i]); bool equal = ColorSpaceComparer.Equals(expected, actual); From ca9ad91c020009a70ec4659c363a22f254f72b79 Mon Sep 17 00:00:00 2001 From: Dmitry Pentin Date: Sat, 4 Dec 2021 16:04:16 +0300 Subject: [PATCH 34/65] Removed duplicated code, removed unused variables --- .../Formats/Jpg/JpegColorConverterTests.cs | 149 ++++-------------- 1 file changed, 34 insertions(+), 115 deletions(-) diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs index 22af74525..f1e3684de 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs @@ -88,13 +88,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg [Theory] [MemberData(nameof(Seeds))] - public void FromYCbCrBasic(int seed) - { - ValidateConversion( - new JpegColorConverterBase.FromYCbCrScalar(8), - 3, - seed); - } + public void FromYCbCrBasic(int seed) => + this.TestConverter(new JpegColorConverterBase.FromYCbCrScalar(8), 3, seed); [Theory] [MemberData(nameof(Seeds))] @@ -124,33 +119,14 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg #if SUPPORTS_RUNTIME_INTRINSICS [Theory] [MemberData(nameof(Seeds))] - public void FromYCbCrAvx2(int seed) - { - var converter = new JpegColorConverterBase.FromYCbCrAvx(8); - - if (!converter.IsAvailable) - { - this.Output.WriteLine( - $"Skipping test - {converter.GetType().Name} is not supported on current hardware."); - return; - } - - ValidateConversion( - converter, - 3, - seed); - } + public void FromYCbCrAvx2(int seed) => + this.TestConverter(new JpegColorConverterBase.FromYCbCrAvx(8), 3, seed); #endif [Theory] [MemberData(nameof(Seeds))] - public void FromCmykBasic(int seed) - { - ValidateConversion( - new JpegColorConverterBase.FromCmykScalar(8), - 4, - seed); - } + public void FromCmykBasic(int seed) => + this.TestConverter(new JpegColorConverterBase.FromCmykScalar(8), 4, seed); [Theory] [MemberData(nameof(Seeds))] @@ -180,33 +156,14 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg #if SUPPORTS_RUNTIME_INTRINSICS [Theory] [MemberData(nameof(Seeds))] - public void FromCmykAvx2(int seed) - { - var converter = new JpegColorConverterBase.FromCmykAvx(8); - - if (!converter.IsAvailable) - { - this.Output.WriteLine( - $"Skipping test - {converter.GetType().Name} is not supported on current hardware."); - return; - } - - ValidateConversion( - converter, - 4, - seed); - } + public void FromCmykAvx2(int seed) => + this.TestConverter(new JpegColorConverterBase.FromCmykAvx(8), 4, seed); #endif [Theory] [MemberData(nameof(Seeds))] - public void FromGrayscaleBasic(int seed) - { - ValidateConversion( - new JpegColorConverterBase.FromGrayscaleScalar(8), - 1, - seed); - } + public void FromGrayscaleBasic(int seed) => + this.TestConverter(new JpegColorConverterBase.FromGrayscaleScalar(8), 1, seed); [Theory] [MemberData(nameof(Seeds))] @@ -236,33 +193,14 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg #if SUPPORTS_RUNTIME_INTRINSICS [Theory] [MemberData(nameof(Seeds))] - public void FromGrayscaleAvx2(int seed) - { - var converter = new JpegColorConverterBase.FromGrayscaleAvx(8); - - if (!converter.IsAvailable) - { - this.Output.WriteLine( - $"Skipping test - {converter.GetType().Name} is not supported on current hardware."); - return; - } - - ValidateConversion( - converter, - 1, - seed); - } + public void FromGrayscaleAvx2(int seed) => + this.TestConverter(new JpegColorConverterBase.FromGrayscaleAvx(8), 1, seed); #endif [Theory] [MemberData(nameof(Seeds))] - public void FromRgbBasic(int seed) - { - ValidateConversion( - new JpegColorConverterBase.FromRgbScalar(8), - 3, - seed); - } + public void FromRgbBasic(int seed) => + this.TestConverter(new JpegColorConverterBase.FromRgbScalar(8), 3, seed); [Theory] [MemberData(nameof(Seeds))] @@ -292,33 +230,14 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg #if SUPPORTS_RUNTIME_INTRINSICS [Theory] [MemberData(nameof(Seeds))] - public void FromRgbAvx2(int seed) - { - var converter = new JpegColorConverterBase.FromRgbAvx(8); - - if (!converter.IsAvailable) - { - this.Output.WriteLine( - $"Skipping test - {converter.GetType().Name} is not supported on current hardware."); - return; - } - - ValidateConversion( - converter, - 3, - seed); - } + public void FromRgbAvx2(int seed) => + this.TestConverter(new JpegColorConverterBase.FromRgbAvx(8), 3, seed); #endif [Theory] [MemberData(nameof(Seeds))] - public void FromYccKBasic(int seed) - { - ValidateConversion( - new JpegColorConverterBase.FromYccKScalar(8), - 4, - seed); - } + public void FromYccKBasic(int seed) => + this.TestConverter(new JpegColorConverterBase.FromYccKScalar(8), 4, seed); [Theory] [MemberData(nameof(Seeds))] @@ -348,10 +267,15 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg #if SUPPORTS_RUNTIME_INTRINSICS [Theory] [MemberData(nameof(Seeds))] - public void FromYccKAvx2(int seed) - { - var converter = new JpegColorConverterBase.FromYccKAvx(8); + public void FromYccKAvx2(int seed) => + this.TestConverter(new JpegColorConverterBase.FromYccKAvx(8), 4, seed); +#endif + private void TestConverter( + JpegColorConverterBase converter, + int componentCount, + int seed) + { if (!converter.IsAvailable) { this.Output.WriteLine( @@ -361,10 +285,9 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg ValidateConversion( converter, - 4, + componentCount, seed); } -#endif private static JpegColorConverterBase.ComponentValues CreateRandomValues( int length, @@ -458,22 +381,20 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg private static void ValidateCyyK(in JpegColorConverterBase.ComponentValues values, in JpegColorConverterBase.ComponentValues result, int i) { - Vector4 v = Vector4.Zero; - float y = values.Component0[i]; float cb = values.Component1[i] - 128F; float cr = values.Component2[i] - 128F; float k = values.Component3[i] / 255F; - v.X = (255F - (float)Math.Round(y + (1.402F * cr), MidpointRounding.AwayFromZero)) * k; - v.Y = (255F - (float)Math.Round( + float r = (255F - (float)Math.Round(y + (1.402F * cr), MidpointRounding.AwayFromZero)) * k; + float g = (255F - (float)Math.Round( y - (0.344136F * cb) - (0.714136F * cr), MidpointRounding.AwayFromZero)) * k; - v.Z = (255F - (float)Math.Round(y + (1.772F * cb), MidpointRounding.AwayFromZero)) * k; + float b = (255F - (float)Math.Round(y + (1.772F * cb), MidpointRounding.AwayFromZero)) * k; - float r = v.X / MaxColorChannelValue; - float g = v.Y / MaxColorChannelValue; - float b = v.Z / MaxColorChannelValue; + r /= MaxColorChannelValue; + g /= MaxColorChannelValue; + b /= MaxColorChannelValue; var expected = new Rgb(r, g, b); var actual = new Rgb(result.Component0[i], result.Component1[i], result.Component2[i]); @@ -508,12 +429,10 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg private static void ValidateCmyk(in JpegColorConverterBase.ComponentValues values, in JpegColorConverterBase.ComponentValues result, int i) { - Vector4 v = Vector4.Zero; - float c = values.Component0[i]; float m = values.Component1[i]; float y = values.Component2[i]; - float k = values.Component3[i] / 255F; + float k = values.Component3[i] / MaxColorChannelValue; float r = c * k / MaxColorChannelValue; float g = m * k / MaxColorChannelValue; From ea2f5894eeae7afaf10a4c41ff734ac8dde7d587 Mon Sep 17 00:00:00 2001 From: Dmitry Pentin Date: Sat, 4 Dec 2021 16:13:32 +0300 Subject: [PATCH 35/65] Renamings --- .../ColorConverters/JpegColorConverter.FromCmykAvx.cs | 2 +- .../ColorConverters/JpegColorConverter.FromCmykScalar.cs | 2 +- .../ColorConverters/JpegColorConverter.FromCmykVector.cs | 2 +- .../ColorConverters/JpegColorConverter.FromGrayScaleAvx.cs | 2 +- .../JpegColorConverter.FromGrayScaleScalar.cs | 2 +- .../JpegColorConverter.FromGrayScaleVector.cs | 2 +- .../ColorConverters/JpegColorConverter.FromRgbAvx.cs | 2 +- .../ColorConverters/JpegColorConverter.FromRgbScalar.cs | 2 +- .../ColorConverters/JpegColorConverter.FromRgbVector.cs | 2 +- .../ColorConverters/JpegColorConverter.FromYCbCrAvx.cs | 2 +- .../ColorConverters/JpegColorConverter.FromYCbCrScalar.cs | 2 +- .../ColorConverters/JpegColorConverter.FromYCbCrVector.cs | 2 +- .../ColorConverters/JpegColorConverter.FromYccKAvx.cs | 2 +- .../ColorConverters/JpegColorConverter.FromYccKScalar.cs | 2 +- .../ColorConverters/JpegColorConverter.FromYccKVector.cs | 2 +- .../Decoder/ColorConverters/JpegColorConverterAvx.cs | 4 ++-- .../Decoder/ColorConverters/JpegColorConverterScalar.cs | 4 ++-- .../Decoder/ColorConverters/JpegColorConverterVector.cs | 6 +++--- 18 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykAvx.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykAvx.cs index d627f7eaf..7366ee30a 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykAvx.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykAvx.cs @@ -11,7 +11,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { internal abstract partial class JpegColorConverterBase { - internal sealed class FromCmykAvx : AvxColorConverter + internal sealed class FromCmykAvx : JpegColorConverterAvx { public FromCmykAvx(int precision) : base(JpegColorSpace.Cmyk, precision) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykScalar.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykScalar.cs index e70aa7cb4..68dfa9bfb 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykScalar.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykScalar.cs @@ -7,7 +7,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { internal abstract partial class JpegColorConverterBase { - internal sealed class FromCmykScalar : ScalarJpegColorConverter + internal sealed class FromCmykScalar : JpegColorConverterScalar { public FromCmykScalar(int precision) : base(JpegColorSpace.Cmyk, precision) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykVector.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykVector.cs index 8fd918140..6b7ed169e 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykVector.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykVector.cs @@ -9,7 +9,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { internal abstract partial class JpegColorConverterBase { - internal sealed class FromCmykVector : VectorizedJpegColorConverter + internal sealed class FromCmykVector : JpegColorConverterVector { public FromCmykVector(int precision) : base(JpegColorSpace.Cmyk, precision) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleAvx.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleAvx.cs index fcfcaa2a9..963543ad4 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleAvx.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleAvx.cs @@ -11,7 +11,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { internal abstract partial class JpegColorConverterBase { - internal sealed class FromGrayscaleAvx : AvxColorConverter + internal sealed class FromGrayscaleAvx : JpegColorConverterAvx { public FromGrayscaleAvx(int precision) : base(JpegColorSpace.Grayscale, precision) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleScalar.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleScalar.cs index 18ac5ff99..3f6a6caa4 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleScalar.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleScalar.cs @@ -9,7 +9,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { internal abstract partial class JpegColorConverterBase { - internal sealed class FromGrayscaleScalar : ScalarJpegColorConverter + internal sealed class FromGrayscaleScalar : JpegColorConverterScalar { public FromGrayscaleScalar(int precision) : base(JpegColorSpace.Grayscale, precision) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleVector.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleVector.cs index 1ca329a12..c484aac28 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleVector.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleVector.cs @@ -9,7 +9,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { internal abstract partial class JpegColorConverterBase { - internal sealed class FromGrayScaleVector : VectorizedJpegColorConverter + internal sealed class FromGrayScaleVector : JpegColorConverterVector { public FromGrayScaleVector(int precision) : base(JpegColorSpace.Grayscale, precision) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbAvx.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbAvx.cs index 83fbc369b..f017716e3 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbAvx.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbAvx.cs @@ -11,7 +11,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { internal abstract partial class JpegColorConverterBase { - internal sealed class FromRgbAvx : AvxColorConverter + internal sealed class FromRgbAvx : JpegColorConverterAvx { public FromRgbAvx(int precision) : base(JpegColorSpace.RGB, precision) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbScalar.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbScalar.cs index 83861d1e2..24c59206d 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbScalar.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbScalar.cs @@ -5,7 +5,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { internal abstract partial class JpegColorConverterBase { - internal sealed class FromRgbScalar : ScalarJpegColorConverter + internal sealed class FromRgbScalar : JpegColorConverterScalar { public FromRgbScalar(int precision) : base(JpegColorSpace.RGB, precision) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbVector.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbVector.cs index b2b059cdc..ff3a2bee1 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbVector.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbVector.cs @@ -9,7 +9,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { internal abstract partial class JpegColorConverterBase { - internal sealed class FromRgbVector : VectorizedJpegColorConverter + internal sealed class FromRgbVector : JpegColorConverterVector { public FromRgbVector(int precision) : base(JpegColorSpace.RGB, precision) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrAvx.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrAvx.cs index adf6e8e0f..892bcc79e 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrAvx.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrAvx.cs @@ -13,7 +13,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { internal abstract partial class JpegColorConverterBase { - internal sealed class FromYCbCrAvx : AvxColorConverter + internal sealed class FromYCbCrAvx : JpegColorConverterAvx { public FromYCbCrAvx(int precision) : base(JpegColorSpace.YCbCr, precision) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrScalar.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrScalar.cs index 73c73970d..4b6d88f72 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrScalar.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrScalar.cs @@ -7,7 +7,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { internal abstract partial class JpegColorConverterBase { - internal sealed class FromYCbCrScalar : ScalarJpegColorConverter + internal sealed class FromYCbCrScalar : JpegColorConverterScalar { // TODO: comments, derived from ITU-T Rec. T.871 internal const float RCrMult = 1.402f; diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrVector.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrVector.cs index f34014332..48e311d99 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrVector.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrVector.cs @@ -10,7 +10,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { internal abstract partial class JpegColorConverterBase { - internal sealed class FromYCbCrVector : VectorizedJpegColorConverter + internal sealed class FromYCbCrVector : JpegColorConverterVector { public FromYCbCrVector(int precision) : base(JpegColorSpace.YCbCr, precision) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKAvx.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKAvx.cs index 86528c74d..1f18d5324 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKAvx.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKAvx.cs @@ -12,7 +12,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { internal abstract partial class JpegColorConverterBase { - internal sealed class FromYccKAvx : AvxColorConverter + internal sealed class FromYccKAvx : JpegColorConverterAvx { public FromYccKAvx(int precision) : base(JpegColorSpace.Ycck, precision) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKScalar.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKScalar.cs index 4657e50cf..d6387ae71 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKScalar.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKScalar.cs @@ -7,7 +7,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { internal abstract partial class JpegColorConverterBase { - internal sealed class FromYccKScalar : ScalarJpegColorConverter + internal sealed class FromYccKScalar : JpegColorConverterScalar { public FromYccKScalar(int precision) : base(JpegColorSpace.Ycck, precision) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKVector.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKVector.cs index 1e826c2c0..66c79ae7c 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKVector.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKVector.cs @@ -9,7 +9,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { internal abstract partial class JpegColorConverterBase { - internal sealed class FromYccKVector : VectorizedJpegColorConverter + internal sealed class FromYccKVector : JpegColorConverterVector { public FromYccKVector(int precision) : base(JpegColorSpace.Ycck, precision) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterAvx.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterAvx.cs index 559422273..81c7c0764 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterAvx.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterAvx.cs @@ -18,9 +18,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters /// DO NOT pass test data of invalid size to these converters as they /// potentially won't do a bound check and return a false positive result. /// - internal abstract class AvxColorConverter : JpegColorConverterBase + internal abstract class JpegColorConverterAvx : JpegColorConverterBase { - protected AvxColorConverter(JpegColorSpace colorSpace, int precision) + protected JpegColorConverterAvx(JpegColorSpace colorSpace, int precision) : base(colorSpace, precision) { } diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterScalar.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterScalar.cs index 76134d490..ff88ab969 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterScalar.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterScalar.cs @@ -9,9 +9,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters /// abstract base for implementations /// based on scalar instructions. /// - internal abstract class ScalarJpegColorConverter : JpegColorConverterBase + internal abstract class JpegColorConverterScalar : JpegColorConverterBase { - protected ScalarJpegColorConverter(JpegColorSpace colorSpace, int precision) + protected JpegColorConverterScalar(JpegColorSpace colorSpace, int precision) : base(colorSpace, precision) { } diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterVector.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterVector.cs index 523ac8896..ca482d78d 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterVector.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterVector.cs @@ -19,9 +19,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters /// such data out of the box. These converters have fallback code /// for 'remainder' data. /// - internal abstract class VectorizedJpegColorConverter : JpegColorConverterBase + internal abstract class JpegColorConverterVector : JpegColorConverterBase { - protected VectorizedJpegColorConverter(JpegColorSpace colorSpace, int precision) + protected JpegColorConverterVector(JpegColorSpace colorSpace, int precision) : base(colorSpace, precision) { } @@ -33,7 +33,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters DebugGuard.IsTrue(this.IsAvailable, $"{this.GetType().Name} converter is not supported on current hardware."); int length = values.Component0.Length; - int remainder = length % Vector.Count; + int remainder = (int)((uint)length % (uint)Vector.Count); // Jpeg images are guaranteed to have pixel strides at least 8 pixels wide // Thus there's no need to check whether simdCount is greater than zero From 284772c11cdd54a864a8a729282eef6404390204 Mon Sep 17 00:00:00 2001 From: Ynse Hoornenborg Date: Sat, 4 Dec 2021 21:06:20 +0100 Subject: [PATCH 36/65] Push input images to LFS again --- tests/Images/Input/Pbm/00000_00000.ppm | 7 +++---- .../Pbm/Gene-UP WebSocket RunImageMask.pgm | Bin 614417 -> 131 bytes .../Images/Input/Pbm/blackandwhite_binary.pbm | 6 +++--- .../Images/Input/Pbm/blackandwhite_plain.pbm | 13 +++---------- tests/Images/Input/Pbm/grayscale_plain.pgm | 13 +++---------- .../Input/Pbm/grayscale_plain_normalized.pgm | 13 +++---------- tests/Images/Input/Pbm/rgb_plain.ppm | 11 +++-------- .../Images/Input/Pbm/rgb_plain_normalized.ppm | 11 +++-------- tests/Images/Input/Pbm/rings.pgm | Bin 40038 -> 130 bytes 9 files changed, 21 insertions(+), 53 deletions(-) diff --git a/tests/Images/Input/Pbm/00000_00000.ppm b/tests/Images/Input/Pbm/00000_00000.ppm index 321188762..f6e085787 100644 --- a/tests/Images/Input/Pbm/00000_00000.ppm +++ b/tests/Images/Input/Pbm/00000_00000.ppm @@ -1,4 +1,3 @@ -P6 -29 30 -255 -KNPJLNVWTl^UtrnryysɻܫmpCARVbmY[aKOPDKKAEDBCBSTVPPRZYTk_{YQUZϧ~ѰɊʇR?NQ[ug\kTQVIMNLNKPPNNNPVUV]Z[xzkfD6ڹŕyݩbkbhberZ[^SSHJHIJENNJJKM[SSn\duQP[G㾵ؐFOL9oc}`ZKHBIJCIOJGJG`QHb`swIHrkϸدңΘˎy^mJH6"RHnnULJIKHP]\EJBxfTuaXA@Y_Ӂtujk``XVPNLJHED@A=?;>:y=9m=8x>7?1S=LDfkSPRJJJiknempmlB6A=@DAECGEJHOHNHNKNOOUW[_clky]`rkrlsorjqf}KHw_cHJJLIFh__{lmgrtw{}ɉ؎䐟쟵Ս|lalVPcQOZML_KJeJKTGKEEDJHBPLJo|xeq_kxbo}tttt``LLMPOTdkyiqgo```YYPWWRXVTRNNIFHIGGHGDJJHȻіoq\fJ\|f_ryXt]S^J;A9HGONIHCwvޮڳًaCBC}Pqe_nTSQOSQSURLLHNMGZWRţ~|kMWWJ[|T^xla~LVldŎ˱խýzy}сMQPZyhl]WW\a`Y[YPOLVSO[VQǎwWJJ:z`deuPOMRԝmwPmǟ}hڝYaG:qkvabkpp^a_QRPSSQ\[VaVUGvmslt@>gk٣ƺvWp^kf©zo|?9UTkmbhhY]\RUTRTT`b`r^daTwut@<ʁȾǕy˶nvճ۠@AWYmq]abX[ZUXXSUVZ\\|sqvpm}~|~x~}@<̔vq~~wǭƘ}AAZ[orX[[WZVUXTTWS[^Zlrthjndciffnhjfw}sD@pv󚗳lurxѵϑ?>^_jmVVTYZSVYQZ]T^aXlgHHX[él[[}Ĉuk۽ʺkl>4RNfg[YWZZUZ]W]`Y^aZĭëcgAAtq֨t~wjµļEOS?yor]\_\Z[[XWYUZ[V]]X­nvkxqyYOF8ɉt̰⡰_gckhplfjYTU^Z[a`bUWWUURXUQlvSk]n^q][BE*ʆhcK]cyX|YThTRV^^cWX_SUXOQPSUR|Y}}db|gI`Oj{Jm^OS?fOy_\K@7RTdrkhӇ裷Ähk]hkSeTOYPPSZ^bNQWLORHMNIQOU?OduOlKp`J_Fsw]d`lNRMI}MFQGVNoisjzcVWOKLRRT[_cMOUSTXJNQNUToĮX^:DO4mNveFlNNrUYx]b|l|jdhaztz~lkz[Y`NKPOORTXZLNOOOOMPPNTRLyWgnUW]M\|je^c}]h~bngmuy}}}{|wljy\[iMLUJJOPRRQRNRRNRSOQTPo|qkshjkdz}y}yziprnnhuoqup{okvjiuRS[FFJJJJOOKMNJNNI[[Wzpy|suvvruoothmrdkq`inbhmcgfekcKTKdla}[cinmasmugcm]Z`JHKKIIUTP^^Yab[cgc[_c[bgJUYDHKMJLTLM^QU]W^Z[`__bXVXJMNIRQLUQXaipmfumphah]V[PKOLHH]ZWge_nqh`hbUTW_ek=JOAGLEDESOMc[^ZW`RSXZZ\cbhQR]LPVNTVT_jfkhnnmb^ce^cWRWIGHQPMff_cfZZaY \ No newline at end of file +version https://git-lfs.github.com/spec/v1 +oid sha256:3b291c0d3a0747c7425a3445bea1de1fa7c112a183d2f78bb9fc96ec5ae9804e +size 2623 diff --git a/tests/Images/Input/Pbm/Gene-UP WebSocket RunImageMask.pgm b/tests/Images/Input/Pbm/Gene-UP WebSocket RunImageMask.pgm index 8265eaa50621a9a5455776fbe2c5faeb5933b862..efd46a2c89c2106981842f9fca60d12947f070c7 100644 GIT binary patch literal 131 zcmWN^%MHUI3;@tOQ?Nio_(Qe<+bKwGiE5HVr*BSA@1igF@sVxLgEys~eLh}0FSqTi z3yinogFszcjE<69F+OZIK_~@l(b2nvm4eFw$w1Ozp+=q2Si8EM@9q(uv5{gzf;A`d NR&f834B9yz#UCXGC)@x4 literal 614417 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 UfB_6(00S7n00uCCfxLnL0M1c2-v9sr diff --git a/tests/Images/Input/Pbm/blackandwhite_binary.pbm b/tests/Images/Input/Pbm/blackandwhite_binary.pbm index a25b1d350..d07976894 100644 --- a/tests/Images/Input/Pbm/blackandwhite_binary.pbm +++ b/tests/Images/Input/Pbm/blackandwhite_binary.pbm @@ -1,3 +1,3 @@ -P4 -# CREATOR: bitmap2pbm Version 1.0.0 -8 4 @0@0 +version https://git-lfs.github.com/spec/v1 +oid sha256:0313a99c2acdd34d6ba67815d1daa25f2452bfada71a1828dbcbb3cc48a20b20 +size 48 diff --git a/tests/Images/Input/Pbm/blackandwhite_plain.pbm b/tests/Images/Input/Pbm/blackandwhite_plain.pbm index fea8cafd0..9c92a99cc 100644 --- a/tests/Images/Input/Pbm/blackandwhite_plain.pbm +++ b/tests/Images/Input/Pbm/blackandwhite_plain.pbm @@ -1,10 +1,3 @@ -P1 -# PBM example -24 7 -0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0 1 1 1 1 0 0 1 1 1 1 0 0 1 1 1 1 0 0 1 1 1 1 0 -0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 1 0 -0 1 1 1 0 0 0 1 1 1 0 0 0 1 1 1 0 0 0 1 1 1 1 0 -0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 -0 1 0 0 0 0 0 1 1 1 1 0 0 1 1 1 1 0 0 1 0 0 0 0 -0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 \ No newline at end of file +version https://git-lfs.github.com/spec/v1 +oid sha256:12ccfacadea1c97c15b6d192ee3ae3b6a1d79bdca30fddbe597390f71e86d59c +size 367 diff --git a/tests/Images/Input/Pbm/grayscale_plain.pgm b/tests/Images/Input/Pbm/grayscale_plain.pgm index ba4757248..fa521b5da 100644 --- a/tests/Images/Input/Pbm/grayscale_plain.pgm +++ b/tests/Images/Input/Pbm/grayscale_plain.pgm @@ -1,10 +1,3 @@ -P2 -24 7 -15 -0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0 3 3 3 3 0 0 7 7 7 7 0 0 11 11 11 11 0 0 15 15 15 15 0 -0 3 0 0 0 0 0 7 0 0 0 0 0 11 0 0 0 0 0 15 0 0 15 0 -0 3 3 3 0 0 0 7 7 7 0 0 0 11 11 11 0 0 0 15 15 15 15 0 -0 3 0 0 0 0 0 7 0 0 0 0 0 11 0 0 0 0 0 15 0 0 0 0 -0 3 0 0 0 0 0 7 7 7 7 0 0 11 11 11 11 0 0 15 0 0 0 0 -0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 \ No newline at end of file +version https://git-lfs.github.com/spec/v1 +oid sha256:08068b4d30f19024e716176033f13f7203a45513e6ae73e79dc824509c92621a +size 507 diff --git a/tests/Images/Input/Pbm/grayscale_plain_normalized.pgm b/tests/Images/Input/Pbm/grayscale_plain_normalized.pgm index fe0329629..96497d605 100644 --- a/tests/Images/Input/Pbm/grayscale_plain_normalized.pgm +++ b/tests/Images/Input/Pbm/grayscale_plain_normalized.pgm @@ -1,10 +1,3 @@ -P2 -24 7 -255 -0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0 51 51 51 51 0 0 119 119 119 119 0 0 187 187 187 187 0 0 255 255 255 255 0 -0 51 0 0 0 0 0 119 0 0 0 0 0 187 0 0 0 0 0 255 0 0 255 0 -0 51 51 51 0 0 0 119 119 119 0 0 0 187 187 187 0 0 0 255 255 255 255 0 -0 51 0 0 0 0 0 119 0 0 0 0 0 187 0 0 0 0 0 255 0 0 0 0 -0 51 0 0 0 0 0 119 119 119 119 0 0 187 187 187 187 0 0 255 0 0 0 0 -0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 \ No newline at end of file +version https://git-lfs.github.com/spec/v1 +oid sha256:e39342751c2a57a060a029213fd7d83cb9a72881b8b01dd6d5b0e897df5077de +size 599 diff --git a/tests/Images/Input/Pbm/rgb_plain.ppm b/tests/Images/Input/Pbm/rgb_plain.ppm index ecd1b915c..32472d0ce 100644 --- a/tests/Images/Input/Pbm/rgb_plain.ppm +++ b/tests/Images/Input/Pbm/rgb_plain.ppm @@ -1,8 +1,3 @@ -P3 -# example from the man page -4 4 -15 - 0 0 0 0 0 0 0 0 0 15 0 15 - 0 0 0 0 15 7 0 0 0 0 0 0 - 0 0 0 0 0 0 0 15 7 0 0 0 -15 0 15 0 0 0 0 0 0 0 0 0 \ No newline at end of file +version https://git-lfs.github.com/spec/v1 +oid sha256:895cd889f6723a5357936e852308cff25b74ead01618bf8efa0f876a86dc18c1 +size 205 diff --git a/tests/Images/Input/Pbm/rgb_plain_normalized.ppm b/tests/Images/Input/Pbm/rgb_plain_normalized.ppm index 628931579..3d7fbe241 100644 --- a/tests/Images/Input/Pbm/rgb_plain_normalized.ppm +++ b/tests/Images/Input/Pbm/rgb_plain_normalized.ppm @@ -1,8 +1,3 @@ -P3 -# example from the man page -4 4 -255 - 0 0 0 0 0 0 0 0 0 255 0 255 - 0 0 0 0 255 119 0 0 0 0 0 0 - 0 0 0 0 0 0 0 255 119 0 0 0 -255 0 255 0 0 0 0 0 0 0 0 0 \ No newline at end of file +version https://git-lfs.github.com/spec/v1 +oid sha256:59be6295e3983708ffba811a408acd83df8e9736b487a94d30132dee0edd6cb6 +size 234 diff --git a/tests/Images/Input/Pbm/rings.pgm b/tests/Images/Input/Pbm/rings.pgm index e0d4b4ed4d4cfc4da44b131a68f60824957428b6..4f2c8d2c74faa33c342dad41e4850bfa8d527cf6 100644 GIT binary patch literal 130 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 Wa*AACLyF_*_)AQ-%Z&HTYW)|`Dr-*w From 20b0349455d4918f304e63c6863673c07fcb8a1f Mon Sep 17 00:00:00 2001 From: Ynse Hoornenborg Date: Sat, 4 Dec 2021 21:08:29 +0100 Subject: [PATCH 37/65] NeedsUpscaling code improvements --- src/ImageSharp/Formats/Pbm/PbmDecoderCore.cs | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/src/ImageSharp/Formats/Pbm/PbmDecoderCore.cs b/src/ImageSharp/Formats/Pbm/PbmDecoderCore.cs index 427ea15e8..1aeecc16f 100644 --- a/src/ImageSharp/Formats/Pbm/PbmDecoderCore.cs +++ b/src/ImageSharp/Formats/Pbm/PbmDecoderCore.cs @@ -53,22 +53,7 @@ namespace SixLabors.ImageSharp.Formats.Pbm /// Size IImageDecoderInternals.Dimensions => this.PixelSize; - private bool NeedsUpscaling - { - get - { - bool needsUpscaling = false; - if (this.ColorType != PbmColorType.BlackAndWhite) - { - if (this.MaxPixelValue is not 255 and not 65535) - { - needsUpscaling = true; - } - } - - return needsUpscaling; - } - } + private bool NeedsUpscaling => this.ColorType != PbmColorType.BlackAndWhite && this.MaxPixelValue is not 255 and not 65535; /// public Image Decode(BufferedReadStream stream, CancellationToken cancellationToken) From 3a0a044fe2c6d964ff589aebb1215f34c76d5bda Mon Sep 17 00:00:00 2001 From: Ynse Hoornenborg Date: Sat, 4 Dec 2021 21:14:25 +0100 Subject: [PATCH 38/65] Improve exception messages --- src/ImageSharp/Formats/Pbm/PbmDecoderCore.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/ImageSharp/Formats/Pbm/PbmDecoderCore.cs b/src/ImageSharp/Formats/Pbm/PbmDecoderCore.cs index 1aeecc16f..b2be74ea1 100644 --- a/src/ImageSharp/Formats/Pbm/PbmDecoderCore.cs +++ b/src/ImageSharp/Formats/Pbm/PbmDecoderCore.cs @@ -94,8 +94,7 @@ namespace SixLabors.ImageSharp.Formats.Pbm int bytesRead = stream.Read(buffer); if (bytesRead != 2 || buffer[0] != 'P') { - // Empty or not an PPM image. - throw new InvalidImageContentException("TODO"); + throw new InvalidImageContentException("Empty or not an PPM image."); } switch ((char)buffer[1]) @@ -134,7 +133,7 @@ namespace SixLabors.ImageSharp.Formats.Pbm // PAM image: sequence of images. // Not implemented yet default: - throw new NotImplementedException("TODO"); + throw new InvalidImageContentException("Unknown of not implemented image type encountered."); } stream.SkipWhitespaceAndComments(); From 61cfa66bdb1f60760729a004f302163dbe187ada Mon Sep 17 00:00:00 2001 From: Ynse Hoornenborg Date: Sat, 4 Dec 2021 21:43:36 +0100 Subject: [PATCH 39/65] Make variables as const if possible --- src/ImageSharp/Formats/Pbm/BinaryDecoder.cs | 13 +++++++------ src/ImageSharp/Formats/Pbm/BinaryEncoder.cs | 6 +++--- src/ImageSharp/Formats/Pbm/PlainDecoder.cs | 5 +++-- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/ImageSharp/Formats/Pbm/BinaryDecoder.cs b/src/ImageSharp/Formats/Pbm/BinaryDecoder.cs index 8b6df295b..2a171456a 100644 --- a/src/ImageSharp/Formats/Pbm/BinaryDecoder.cs +++ b/src/ImageSharp/Formats/Pbm/BinaryDecoder.cs @@ -14,6 +14,9 @@ namespace SixLabors.ImageSharp.Formats.Pbm /// internal class BinaryDecoder { + private static L8 white = new L8(255); + private static L8 black = new L8(0); + /// /// Decode the specified pixels. /// @@ -60,9 +63,9 @@ namespace SixLabors.ImageSharp.Formats.Pbm private static void ProcessGrayscale(Configuration configuration, Buffer2D pixels, BufferedReadStream stream) where TPixel : unmanaged, IPixel { + const int bytesPerPixel = 1; int width = pixels.Width; int height = pixels.Height; - int bytesPerPixel = 1; MemoryAllocator allocator = configuration.MemoryAllocator; using IMemoryOwner row = allocator.Allocate(width * bytesPerPixel); Span rowSpan = row.GetSpan(); @@ -82,9 +85,9 @@ namespace SixLabors.ImageSharp.Formats.Pbm private static void ProcessWideGrayscale(Configuration configuration, Buffer2D pixels, BufferedReadStream stream) where TPixel : unmanaged, IPixel { + const int bytesPerPixel = 2; int width = pixels.Width; int height = pixels.Height; - int bytesPerPixel = 2; MemoryAllocator allocator = configuration.MemoryAllocator; using IMemoryOwner row = allocator.Allocate(width * bytesPerPixel); Span rowSpan = row.GetSpan(); @@ -104,9 +107,9 @@ namespace SixLabors.ImageSharp.Formats.Pbm private static void ProcessRgb(Configuration configuration, Buffer2D pixels, BufferedReadStream stream) where TPixel : unmanaged, IPixel { + const int bytesPerPixel = 3; int width = pixels.Width; int height = pixels.Height; - int bytesPerPixel = 3; MemoryAllocator allocator = configuration.MemoryAllocator; using IMemoryOwner row = allocator.Allocate(width * bytesPerPixel); Span rowSpan = row.GetSpan(); @@ -126,9 +129,9 @@ namespace SixLabors.ImageSharp.Formats.Pbm private static void ProcessWideRgb(Configuration configuration, Buffer2D pixels, BufferedReadStream stream) where TPixel : unmanaged, IPixel { + const int bytesPerPixel = 6; int width = pixels.Width; int height = pixels.Height; - int bytesPerPixel = 6; MemoryAllocator allocator = configuration.MemoryAllocator; using IMemoryOwner row = allocator.Allocate(width * bytesPerPixel); Span rowSpan = row.GetSpan(); @@ -154,8 +157,6 @@ namespace SixLabors.ImageSharp.Formats.Pbm MemoryAllocator allocator = configuration.MemoryAllocator; using IMemoryOwner row = allocator.Allocate(width); Span rowSpan = row.GetSpan(); - var white = new L8(255); - var black = new L8(0); for (int y = 0; y < height; y++) { diff --git a/src/ImageSharp/Formats/Pbm/BinaryEncoder.cs b/src/ImageSharp/Formats/Pbm/BinaryEncoder.cs index 2bcbaeef7..626026726 100644 --- a/src/ImageSharp/Formats/Pbm/BinaryEncoder.cs +++ b/src/ImageSharp/Formats/Pbm/BinaryEncoder.cs @@ -83,9 +83,9 @@ namespace SixLabors.ImageSharp.Formats.Pbm private static void WriteWideGrayscale(Configuration configuration, Stream stream, ImageFrame image) where TPixel : unmanaged, IPixel { + const int bytesPerPixel = 2; int width = image.Width; int height = image.Height; - int bytesPerPixel = 2; MemoryAllocator allocator = configuration.MemoryAllocator; using IMemoryOwner row = allocator.Allocate(width * bytesPerPixel); Span rowSpan = row.GetSpan(); @@ -107,9 +107,9 @@ namespace SixLabors.ImageSharp.Formats.Pbm private static void WriteRgb(Configuration configuration, Stream stream, ImageFrame image) where TPixel : unmanaged, IPixel { + const int bytesPerPixel = 3; int width = image.Width; int height = image.Height; - int bytesPerPixel = 3; MemoryAllocator allocator = configuration.MemoryAllocator; using IMemoryOwner row = allocator.Allocate(width * bytesPerPixel); Span rowSpan = row.GetSpan(); @@ -131,9 +131,9 @@ namespace SixLabors.ImageSharp.Formats.Pbm private static void WriteWideRgb(Configuration configuration, Stream stream, ImageFrame image) where TPixel : unmanaged, IPixel { + const int bytesPerPixel = 6; int width = image.Width; int height = image.Height; - int bytesPerPixel = 6; MemoryAllocator allocator = configuration.MemoryAllocator; using IMemoryOwner row = allocator.Allocate(width * bytesPerPixel); Span rowSpan = row.GetSpan(); diff --git a/src/ImageSharp/Formats/Pbm/PlainDecoder.cs b/src/ImageSharp/Formats/Pbm/PlainDecoder.cs index 9fa8e513e..dc5350bdd 100644 --- a/src/ImageSharp/Formats/Pbm/PlainDecoder.cs +++ b/src/ImageSharp/Formats/Pbm/PlainDecoder.cs @@ -14,6 +14,9 @@ namespace SixLabors.ImageSharp.Formats.Pbm /// internal class PlainDecoder { + private static L8 white = new L8(255); + private static L8 black = new L8(0); + /// /// Decode the specified pixels. /// @@ -174,8 +177,6 @@ namespace SixLabors.ImageSharp.Formats.Pbm MemoryAllocator allocator = configuration.MemoryAllocator; using IMemoryOwner row = allocator.Allocate(width); Span rowSpan = row.GetSpan(); - var white = new L8(255); - var black = new L8(0); for (int y = 0; y < height; y++) { From dd49f9a811aabf0a93b73b4a3a1a30016e91367e Mon Sep 17 00:00:00 2001 From: Ynse Hoornenborg Date: Sun, 5 Dec 2021 16:24:39 +0100 Subject: [PATCH 40/65] Single image compare utils for multiple Formats --- .../Formats/Pbm/PbmEncoderTests.cs | 4 +- .../Formats/Tga/TgaDecoderTests.cs | 96 +++++++++---------- .../Formats/Tga/TgaEncoderTests.cs | 4 +- .../Formats/Tiff/TiffMetadataTests.cs | 8 ++ .../Formats/Tiff/TiffTestUtils.cs | 65 ------------- .../Formats/WebP/LosslessUtilsTests.cs | 2 +- .../ImageComparison/ImageComparingUtils.cs} | 5 +- 7 files changed, 63 insertions(+), 121 deletions(-) delete mode 100644 tests/ImageSharp.Tests/Formats/Tiff/TiffTestUtils.cs rename tests/ImageSharp.Tests/{Formats/Tga/TgaTestUtils.cs => TestUtilities/ImageComparison/ImageComparingUtils.cs} (93%) diff --git a/tests/ImageSharp.Tests/Formats/Pbm/PbmEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Pbm/PbmEncoderTests.cs index 339cc4a5c..dcc63618c 100644 --- a/tests/ImageSharp.Tests/Formats/Pbm/PbmEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Pbm/PbmEncoderTests.cs @@ -5,7 +5,7 @@ using System.IO; using SixLabors.ImageSharp.Formats.Pbm; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Tests.Formats.Tga; - +using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison; using Xunit; using static SixLabors.ImageSharp.Tests.TestImages.Pbm; @@ -135,7 +135,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Pbm memStream.Position = 0; using (var encodedImage = (Image)Image.Load(memStream)) { - TgaTestUtils.CompareWithReferenceDecoder(provider, encodedImage, useExactComparer, compareTolerance); + ImageComparingUtils.CompareWithReferenceDecoder(provider, encodedImage, useExactComparer, compareTolerance); } } } diff --git a/tests/ImageSharp.Tests/Formats/Tga/TgaDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Tga/TgaDecoderTests.cs index 1c53ff6a1..bd7a6e07a 100644 --- a/tests/ImageSharp.Tests/Formats/Tga/TgaDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tga/TgaDecoderTests.cs @@ -29,7 +29,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga using (Image image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); } } @@ -41,7 +41,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga using (Image image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); } } @@ -53,7 +53,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga using (Image image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); } } @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga using (Image image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); } } @@ -77,7 +77,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga using (Image image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); } } @@ -89,7 +89,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga using (Image image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); } } @@ -101,7 +101,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga using (Image image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); } } @@ -113,7 +113,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga using (Image image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); } } @@ -245,7 +245,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga using (Image image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); } } @@ -257,7 +257,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga using (Image image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); } } @@ -269,7 +269,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga using (Image image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); } } @@ -281,7 +281,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga using (Image image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); } } @@ -293,7 +293,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga using (Image image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); } } @@ -305,7 +305,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga using (Image image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); } } @@ -317,7 +317,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga using (Image image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); } } @@ -329,7 +329,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga using (Image image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); } } @@ -341,7 +341,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga using (Image image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); } } @@ -353,7 +353,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga using (Image image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); } } @@ -365,7 +365,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga using (Image image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); } } @@ -377,7 +377,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga using (Image image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); } } @@ -389,7 +389,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga using (Image image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); } } @@ -401,7 +401,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga using (Image image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); } } @@ -413,7 +413,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga using (Image image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); } } @@ -425,7 +425,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga using (Image image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); } } @@ -437,7 +437,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga using (Image image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); } } @@ -449,7 +449,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga using (Image image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); } } @@ -461,7 +461,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga using (Image image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); } } @@ -473,7 +473,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga using (Image image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); } } @@ -485,7 +485,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga using (Image image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); } } @@ -497,7 +497,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga using (Image image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); } } @@ -509,7 +509,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga using (Image image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); } } @@ -521,7 +521,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga using (Image image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); } } @@ -533,7 +533,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga using (Image image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); } } @@ -545,7 +545,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga using (Image image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); } } @@ -557,7 +557,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga using (Image image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); } } @@ -569,7 +569,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga using (Image image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); } } @@ -581,7 +581,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga using (Image image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); } } @@ -593,7 +593,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga using (Image image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); } } @@ -605,7 +605,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga using (Image image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); } } @@ -617,7 +617,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga using (Image image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); } } @@ -629,7 +629,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga using (Image image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); } } @@ -641,7 +641,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga using (Image image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); } } @@ -653,7 +653,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga using (Image image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); } } @@ -665,7 +665,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga using (Image image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); } } @@ -677,7 +677,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga using (Image image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); } } @@ -689,7 +689,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga using (Image image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); } } @@ -701,7 +701,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga using (Image image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); } } @@ -714,7 +714,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga using (Image image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); } } diff --git a/tests/ImageSharp.Tests/Formats/Tga/TgaEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Tga/TgaEncoderTests.cs index 4c768a1a5..da8ff8018 100644 --- a/tests/ImageSharp.Tests/Formats/Tga/TgaEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tga/TgaEncoderTests.cs @@ -4,7 +4,7 @@ using System.IO; using SixLabors.ImageSharp.Formats.Tga; using SixLabors.ImageSharp.PixelFormats; - +using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison; using Xunit; using static SixLabors.ImageSharp.Tests.TestImages.Tga; @@ -150,7 +150,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga memStream.Position = 0; using (var encodedImage = (Image)Image.Load(memStream)) { - TgaTestUtils.CompareWithReferenceDecoder(provider, encodedImage, useExactComparer, compareTolerance); + ImageComparingUtils.CompareWithReferenceDecoder(provider, encodedImage, useExactComparer, compareTolerance); } } } diff --git a/tests/ImageSharp.Tests/Formats/Tiff/TiffMetadataTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/TiffMetadataTests.cs index cdd9616a7..c912ae26b 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/TiffMetadataTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tiff/TiffMetadataTests.cs @@ -1,6 +1,7 @@ // Copyright (c) Six Labors. // Licensed under the Apache License, Version 2.0. +using System.Collections.Generic; using System.IO; using System.Linq; using SixLabors.ImageSharp.Common.Helpers; @@ -22,6 +23,13 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff { private static TiffDecoder TiffDecoder => new TiffDecoder(); + private class NumberComparer : IEqualityComparer + { + public bool Equals(Number x, Number y) => x.Equals(y); + + public int GetHashCode(Number obj) => obj.GetHashCode(); + } + [Fact] public void TiffMetadata_CloneIsDeep() { diff --git a/tests/ImageSharp.Tests/Formats/Tiff/TiffTestUtils.cs b/tests/ImageSharp.Tests/Formats/Tiff/TiffTestUtils.cs deleted file mode 100644 index eacadae2b..000000000 --- a/tests/ImageSharp.Tests/Formats/Tiff/TiffTestUtils.cs +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Apache License, Version 2.0. - -using System; -using System.Collections.Generic; -using System.IO; -using ImageMagick; - -using SixLabors.ImageSharp.PixelFormats; -using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison; - -using Xunit; - -namespace SixLabors.ImageSharp.Tests.Formats.Tiff -{ - public static class TiffTestUtils - { - public static void CompareWithReferenceDecoder( - string encodedImagePath, - Image image, - bool useExactComparer = true, - float compareTolerance = 0.01f) - where TPixel : unmanaged, ImageSharp.PixelFormats.IPixel - { - var testFile = TestFile.Create(encodedImagePath); - Image magickImage = DecodeWithMagick(Configuration.Default, new FileInfo(testFile.FullPath)); - if (useExactComparer) - { - ImageComparer.Exact.VerifySimilarity(magickImage, image); - } - else - { - ImageComparer.Tolerant(compareTolerance).VerifySimilarity(magickImage, image); - } - } - - public static Image DecodeWithMagick(Configuration configuration, FileInfo fileInfo) - where TPixel : unmanaged, ImageSharp.PixelFormats.IPixel - { - using var magickImage = new MagickImage(fileInfo); - magickImage.AutoOrient(); - var result = new Image(configuration, magickImage.Width, magickImage.Height); - - Assert.True(result.TryGetSinglePixelSpan(out Span resultPixels)); - - using IUnsafePixelCollection pixels = magickImage.GetPixelsUnsafe(); - byte[] data = pixels.ToByteArray(PixelMapping.RGBA); - - PixelOperations.Instance.FromRgba32Bytes( - configuration, - data, - resultPixels, - resultPixels.Length); - - return result; - } - } - - internal class NumberComparer : IEqualityComparer - { - public bool Equals(Number x, Number y) => x.Equals(y); - - public int GetHashCode(Number obj) => obj.GetHashCode(); - } -} diff --git a/tests/ImageSharp.Tests/Formats/WebP/LosslessUtilsTests.cs b/tests/ImageSharp.Tests/Formats/WebP/LosslessUtilsTests.cs index 684d7791b..bd8a48a44 100644 --- a/tests/ImageSharp.Tests/Formats/WebP/LosslessUtilsTests.cs +++ b/tests/ImageSharp.Tests/Formats/WebP/LosslessUtilsTests.cs @@ -229,7 +229,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Webp public void TransformColorInverse_Works() => RunTransformColorInverseTest(); #if SUPPORTS_RUNTIME_INTRINSICS - + [Fact] public void CombinedShannonEntropy_WithHardwareIntrinsics_Works() => FeatureTestRunner.RunWithHwIntrinsicsFeature(RunCombinedShannonEntropyTest, HwIntrinsics.AllowAll); diff --git a/tests/ImageSharp.Tests/Formats/Tga/TgaTestUtils.cs b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ImageComparingUtils.cs similarity index 93% rename from tests/ImageSharp.Tests/Formats/Tga/TgaTestUtils.cs rename to tests/ImageSharp.Tests/TestUtilities/ImageComparison/ImageComparingUtils.cs index c96777031..7eae5938f 100644 --- a/tests/ImageSharp.Tests/Formats/Tga/TgaTestUtils.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ImageComparingUtils.cs @@ -5,12 +5,11 @@ using System; using System.IO; using ImageMagick; using SixLabors.ImageSharp.PixelFormats; -using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison; using Xunit; -namespace SixLabors.ImageSharp.Tests.Formats.Tga +namespace SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison { - public static class TgaTestUtils + public static class ImageComparingUtils { public static void CompareWithReferenceDecoder( TestImageProvider provider, From 1aa27bd3efdb43d0daac07527212fe4a1a879b2a Mon Sep 17 00:00:00 2001 From: Ynse Hoornenborg Date: Sun, 5 Dec 2021 16:57:24 +0100 Subject: [PATCH 41/65] Add Magick compatible input image --- tests/ImageSharp.Tests/Formats/Pbm/PbmDecoderTests.cs | 5 ++++- tests/ImageSharp.Tests/Formats/Pbm/PbmEncoderTests.cs | 8 ++------ tests/ImageSharp.Tests/Formats/Pbm/PbmRoundTripTests.cs | 2 ++ tests/ImageSharp.Tests/TestImages.cs | 2 ++ tests/Images/Input/Pbm/grayscale_plain_magick.pgm | 3 +++ tests/Images/Input/Pbm/rgb_plain_magick.ppm | 3 +++ 6 files changed, 16 insertions(+), 7 deletions(-) create mode 100644 tests/Images/Input/Pbm/grayscale_plain_magick.pgm create mode 100644 tests/Images/Input/Pbm/rgb_plain_magick.ppm diff --git a/tests/ImageSharp.Tests/Formats/Pbm/PbmDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Pbm/PbmDecoderTests.cs index 8b8e1a08f..51bf61d23 100644 --- a/tests/ImageSharp.Tests/Formats/Pbm/PbmDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Pbm/PbmDecoderTests.cs @@ -4,7 +4,6 @@ using System.IO; using SixLabors.ImageSharp.Formats.Pbm; using SixLabors.ImageSharp.PixelFormats; -using SixLabors.ImageSharp.Processing; using Xunit; using static SixLabors.ImageSharp.Tests.TestImages.Pbm; @@ -18,9 +17,11 @@ namespace SixLabors.ImageSharp.Tests.Formats.Pbm [InlineData(BlackAndWhitePlain, PbmColorType.BlackAndWhite)] [InlineData(BlackAndWhiteBinary, PbmColorType.BlackAndWhite)] [InlineData(GrayscalePlain, PbmColorType.Grayscale)] + [InlineData(GrayscalePlainMagick, PbmColorType.Grayscale)] [InlineData(GrayscaleBinary, PbmColorType.Grayscale)] [InlineData(GrayscaleBinaryWide, PbmColorType.Grayscale)] [InlineData(RgbPlain, PbmColorType.Rgb)] + [InlineData(RgbPlainMagick, PbmColorType.Rgb)] [InlineData(RgbBinary, PbmColorType.Rgb)] public void ImageLoadCanDecode(string imagePath, PbmColorType expectedColorType) { @@ -42,6 +43,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Pbm [InlineData(BlackAndWhitePlain)] [InlineData(BlackAndWhiteBinary)] [InlineData(GrayscalePlain)] + [InlineData(GrayscalePlainMagick)] [InlineData(GrayscaleBinary)] [InlineData(GrayscaleBinaryWide)] public void ImageLoadL8CanDecode(string imagePath) @@ -59,6 +61,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Pbm [Theory] [InlineData(RgbPlain)] + [InlineData(RgbPlainMagick)] [InlineData(RgbBinary)] public void ImageLoadRgb24CanDecode(string imagePath) { diff --git a/tests/ImageSharp.Tests/Formats/Pbm/PbmEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Pbm/PbmEncoderTests.cs index dcc63618c..44fab1617 100644 --- a/tests/ImageSharp.Tests/Formats/Pbm/PbmEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Pbm/PbmEncoderTests.cs @@ -93,24 +93,20 @@ namespace SixLabors.ImageSharp.Tests.Formats.Pbm public void PbmEncoder_P4_Works(TestImageProvider provider) where TPixel : unmanaged, IPixel => TestPbmEncoderCore(provider, PbmColorType.BlackAndWhite, PbmEncoding.Binary); - /* Disabled as Magick throws an error reading the input image [Theory] - [WithFile(GrayscalePlain, PixelTypes.Rgb24)] + [WithFile(GrayscalePlainMagick, PixelTypes.Rgb24)] public void PbmEncoder_P2_Works(TestImageProvider provider) where TPixel : unmanaged, IPixel => TestPbmEncoderCore(provider, PbmColorType.Grayscale, PbmEncoding.Plain); - */ [Theory] [WithFile(GrayscaleBinary, PixelTypes.Rgb24)] public void PbmEncoder_P5_Works(TestImageProvider provider) where TPixel : unmanaged, IPixel => TestPbmEncoderCore(provider, PbmColorType.Grayscale, PbmEncoding.Binary); - /* Disabled as Magick throws an error reading the input image [Theory] - [WithFile(RgbPlain, PixelTypes.Rgb24)] + [WithFile(RgbPlainMagick, PixelTypes.Rgb24)] public void PbmEncoder_P3_Works(TestImageProvider provider) where TPixel : unmanaged, IPixel => TestPbmEncoderCore(provider, PbmColorType.Rgb, PbmEncoding.Plain); - */ [Theory] [WithFile(RgbBinary, PixelTypes.Rgb24)] diff --git a/tests/ImageSharp.Tests/Formats/Pbm/PbmRoundTripTests.cs b/tests/ImageSharp.Tests/Formats/Pbm/PbmRoundTripTests.cs index 9521ee7e9..190972535 100644 --- a/tests/ImageSharp.Tests/Formats/Pbm/PbmRoundTripTests.cs +++ b/tests/ImageSharp.Tests/Formats/Pbm/PbmRoundTripTests.cs @@ -18,6 +18,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Pbm [InlineData(BlackAndWhiteBinary)] [InlineData(GrayscalePlain)] [InlineData(GrayscalePlainNormalized)] + [InlineData(GrayscalePlainMagick)] [InlineData(GrayscaleBinary)] public void PbmGrayscaleImageCanRoundTrip(string imagePath) { @@ -38,6 +39,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Pbm [Theory] [InlineData(RgbPlain)] [InlineData(RgbPlainNormalized)] + [InlineData(RgbPlainMagick)] [InlineData(RgbBinary)] public void PbmColorImageCanRoundTrip(string imagePath) { diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index 444be63a2..930b550a2 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -875,9 +875,11 @@ namespace SixLabors.ImageSharp.Tests public const string GrayscaleBinaryWide = "Pbm/Gene-UP WebSocket RunImageMask.pgm"; public const string GrayscalePlain = "Pbm/grayscale_plain.pgm"; public const string GrayscalePlainNormalized = "Pbm/grayscale_plain_normalized.pgm"; + public const string GrayscalePlainMagick = "Pbm/grayscale_plain_magick.pgm"; public const string RgbBinary = "Pbm/00000_00000.ppm"; public const string RgbPlain = "Pbm/rgb_plain.ppm"; public const string RgbPlainNormalized = "Pbm/rgb_plain_normalized.ppm"; + public const string RgbPlainMagick = "Pbm/rgb_plain_magick.ppm"; } } } diff --git a/tests/Images/Input/Pbm/grayscale_plain_magick.pgm b/tests/Images/Input/Pbm/grayscale_plain_magick.pgm new file mode 100644 index 000000000..fe1bb28b3 --- /dev/null +++ b/tests/Images/Input/Pbm/grayscale_plain_magick.pgm @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ec652ee7ea1a82d8ea2fd344670ab9aee2c2f52af86458d9991754204e1fc2bb +size 464 diff --git a/tests/Images/Input/Pbm/rgb_plain_magick.ppm b/tests/Images/Input/Pbm/rgb_plain_magick.ppm new file mode 100644 index 000000000..ee88eb7f3 --- /dev/null +++ b/tests/Images/Input/Pbm/rgb_plain_magick.ppm @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7f38a31162f31e77f5ad80da968a386b2cbccc6998a88a4c6b311b48919119a1 +size 149 From 093e1ae946a6df6138b381ca97fb3ad65dd58568 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Sun, 5 Dec 2021 17:42:00 +0100 Subject: [PATCH 42/65] Add missing using --- .../TestUtilities/ImageComparison/ImageComparingUtils.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ImageComparingUtils.cs b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ImageComparingUtils.cs index 7eae5938f..cbf38f308 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ImageComparingUtils.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ImageComparingUtils.cs @@ -25,7 +25,7 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison } var testFile = TestFile.Create(path); - Image magickImage = DecodeWithMagick(Configuration.Default, new FileInfo(testFile.FullPath)); + using Image magickImage = DecodeWithMagick(Configuration.Default, new FileInfo(testFile.FullPath)); if (useExactComparer) { ImageComparer.Exact.VerifySimilarity(magickImage, image); From f09641c06b1f77de8234883aeb3e6ca4bc84962b Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Sun, 5 Dec 2021 17:46:10 +0100 Subject: [PATCH 43/65] Cleanup --- src/ImageSharp/Formats/Pbm/PbmDecoderCore.cs | 2 +- src/ImageSharp/Formats/Pbm/PbmEncoder.cs | 4 ++-- src/ImageSharp/Formats/Pbm/PbmFormat.cs | 2 +- src/ImageSharp/Formats/Pbm/PbmMetadata.cs | 5 +---- src/ImageSharp/Formats/Pbm/PlainDecoder.cs | 6 +++--- tests/ImageSharp.Tests/Formats/Pbm/PbmEncoderTests.cs | 7 +++---- 6 files changed, 11 insertions(+), 15 deletions(-) diff --git a/src/ImageSharp/Formats/Pbm/PbmDecoderCore.cs b/src/ImageSharp/Formats/Pbm/PbmDecoderCore.cs index b2be74ea1..8bac0bfd1 100644 --- a/src/ImageSharp/Formats/Pbm/PbmDecoderCore.cs +++ b/src/ImageSharp/Formats/Pbm/PbmDecoderCore.cs @@ -115,7 +115,7 @@ namespace SixLabors.ImageSharp.Formats.Pbm this.Encoding = PbmEncoding.Plain; break; case '4': - // Binary PBM format: 1 component per pixel, 8 picels per byte. + // Binary PBM format: 1 component per pixel, 8 pixels per byte. this.ColorType = PbmColorType.BlackAndWhite; this.Encoding = PbmEncoding.Binary; break; diff --git a/src/ImageSharp/Formats/Pbm/PbmEncoder.cs b/src/ImageSharp/Formats/Pbm/PbmEncoder.cs index fe0f7f9f1..7984dddac 100644 --- a/src/ImageSharp/Formats/Pbm/PbmEncoder.cs +++ b/src/ImageSharp/Formats/Pbm/PbmEncoder.cs @@ -13,9 +13,9 @@ namespace SixLabors.ImageSharp.Formats.Pbm /// Image encoder for writing an image to a stream as PGM, PBM or PPM bitmap. These images are from /// the family of PNM images. /// - /// The PNM formats are a faily simple image format. They share a plain text header, consisting of: + /// The PNM formats are a fairly simple image format. They share a plain text header, consisting of: /// signature, width, height and max_pixel_value only. The pixels follow thereafter and can be in - /// plain text decimals seperated by spaces, or binary encoded. + /// plain text decimals separated by spaces, or binary encoded. /// /// /// PBM diff --git a/src/ImageSharp/Formats/Pbm/PbmFormat.cs b/src/ImageSharp/Formats/Pbm/PbmFormat.cs index 35aa9cf8c..5ffb49652 100644 --- a/src/ImageSharp/Formats/Pbm/PbmFormat.cs +++ b/src/ImageSharp/Formats/Pbm/PbmFormat.cs @@ -17,7 +17,7 @@ namespace SixLabors.ImageSharp.Formats.Pbm /// /// Gets the current instance. /// - public static PbmFormat Instance { get; } = new PbmFormat(); + public static PbmFormat Instance { get; } = new(); /// public string Name => "PBM"; diff --git a/src/ImageSharp/Formats/Pbm/PbmMetadata.cs b/src/ImageSharp/Formats/Pbm/PbmMetadata.cs index b29cd27c2..869b1b06d 100644 --- a/src/ImageSharp/Formats/Pbm/PbmMetadata.cs +++ b/src/ImageSharp/Formats/Pbm/PbmMetadata.cs @@ -11,10 +11,7 @@ namespace SixLabors.ImageSharp.Formats.Pbm /// /// Initializes a new instance of the class. /// - public PbmMetadata() - { - this.MaxPixelValue = this.ColorType == PbmColorType.BlackAndWhite ? 1 : 255; - } + public PbmMetadata() => this.MaxPixelValue = this.ColorType == PbmColorType.BlackAndWhite ? 1 : 255; /// /// Initializes a new instance of the class. diff --git a/src/ImageSharp/Formats/Pbm/PlainDecoder.cs b/src/ImageSharp/Formats/Pbm/PlainDecoder.cs index dc5350bdd..4521f9b64 100644 --- a/src/ImageSharp/Formats/Pbm/PlainDecoder.cs +++ b/src/ImageSharp/Formats/Pbm/PlainDecoder.cs @@ -14,8 +14,8 @@ namespace SixLabors.ImageSharp.Formats.Pbm /// internal class PlainDecoder { - private static L8 white = new L8(255); - private static L8 black = new L8(0); + private static readonly L8 White = new(255); + private static readonly L8 Black = new(0); /// /// Decode the specified pixels. @@ -184,7 +184,7 @@ namespace SixLabors.ImageSharp.Formats.Pbm { int value = stream.ReadDecimal(); stream.SkipWhitespaceAndComments(); - rowSpan[x] = value == 0 ? white : black; + rowSpan[x] = value == 0 ? White : Black; } Span pixelSpan = pixels.GetRowSpan(y); diff --git a/tests/ImageSharp.Tests/Formats/Pbm/PbmEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Pbm/PbmEncoderTests.cs index 44fab1617..2ca49a39d 100644 --- a/tests/ImageSharp.Tests/Formats/Pbm/PbmEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Pbm/PbmEncoderTests.cs @@ -4,7 +4,6 @@ using System.IO; using SixLabors.ImageSharp.Formats.Pbm; using SixLabors.ImageSharp.PixelFormats; -using SixLabors.ImageSharp.Tests.Formats.Tga; using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison; using Xunit; using static SixLabors.ImageSharp.Tests.TestImages.Pbm; @@ -17,7 +16,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Pbm public class PbmEncoderTests { public static readonly TheoryData ColorType = - new TheoryData + new() { PbmColorType.BlackAndWhite, PbmColorType.Grayscale, @@ -25,7 +24,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Pbm }; public static readonly TheoryData PbmColorTypeFiles = - new TheoryData + new() { { BlackAndWhiteBinary, PbmColorType.BlackAndWhite }, { BlackAndWhitePlain, PbmColorType.BlackAndWhite }, @@ -67,7 +66,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Pbm Encoding = PbmEncoding.Plain }; - TestFile testFile = TestFile.Create(imagePath); + var testFile = TestFile.Create(imagePath); using (Image input = testFile.CreateRgba32Image()) { using (var memStream = new MemoryStream()) From 1f6a503b9b3e57480cb73ae9f1218143228802bd Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Wed, 8 Dec 2021 13:05:47 +0100 Subject: [PATCH 44/65] Add SSE2 version of Vp8_Sse16X16 and Vp8_Sse16X8 --- .../Formats/Webp/Lossy/LossyUtils.cs | 72 ++++++++++++++++++- 1 file changed, 70 insertions(+), 2 deletions(-) diff --git a/src/ImageSharp/Formats/Webp/Lossy/LossyUtils.cs b/src/ImageSharp/Formats/Webp/Lossy/LossyUtils.cs index af5f136fa..69ce6c7f9 100644 --- a/src/ImageSharp/Formats/Webp/Lossy/LossyUtils.cs +++ b/src/ImageSharp/Formats/Webp/Lossy/LossyUtils.cs @@ -40,11 +40,33 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy // Note: method name in libwebp reference implementation is called VP8SSE16x16. [MethodImpl(InliningOptions.ShortMethod)] - public static int Vp8_Sse16X16(Span a, Span b) => Vp8_SseNxN(a, b, 16, 16); + public static int Vp8_Sse16X16(Span a, Span b) + { +#if SUPPORTS_RUNTIME_INTRINSICS + if (Sse2.IsSupported) + { + return Vp8_Sse16xN_Sse2(a, b, 8); + } +#endif + { + return Vp8_SseNxN(a, b, 16, 16); + } + } // Note: method name in libwebp reference implementation is called VP8SSE16x8. [MethodImpl(InliningOptions.ShortMethod)] - public static int Vp8_Sse16X8(Span a, Span b) => Vp8_SseNxN(a, b, 16, 8); + public static int Vp8_Sse16X8(Span a, Span b) + { +#if SUPPORTS_RUNTIME_INTRINSICS + if (Sse2.IsSupported) + { + return Vp8_Sse16xN_Sse2(a, b, 4); + } +#endif + { + return Vp8_SseNxN(a, b, 16, 8); + } + } // Note: method name in libwebp reference implementation is called VP8SSE4x4. [MethodImpl(InliningOptions.ShortMethod)] @@ -146,6 +168,52 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy return count; } +#if SUPPORTS_RUNTIME_INTRINSICS + [MethodImpl(InliningOptions.ShortMethod)] + private static int Vp8_Sse16xN_Sse2(Span a, Span b, int numPairs) + { + Vector128 sum = Vector128.Zero; + int offset = 0; + for (int i = 0; i < numPairs; i++) + { + // Load values. + ref byte aRef = ref MemoryMarshal.GetReference(a); + ref byte bRef = ref MemoryMarshal.GetReference(b); + Vector128 a0 = Unsafe.As>(ref Unsafe.Add(ref aRef, offset)); + Vector128 b0 = Unsafe.As>(ref Unsafe.Add(ref bRef, offset)); + Vector128 a1 = Unsafe.As>(ref Unsafe.Add(ref aRef, offset + WebpConstants.Bps)); + Vector128 b1 = Unsafe.As>(ref Unsafe.Add(ref bRef, offset + WebpConstants.Bps)); + + Vector128 sum1 = SubtractAndAccumulate(a0, b0); + Vector128 sum2 = SubtractAndAccumulate(a1, b1); + sum = Sse2.Add(sum, Sse2.Add(sum1, sum2)); + + offset += 2 * WebpConstants.Bps; + } + + return Numerics.ReduceSum(sum); + } + + [MethodImpl(InliningOptions.ShortMethod)] + private static Vector128 SubtractAndAccumulate(Vector128 a, Vector128 b) + { + // Take abs(a-b) in 8b. + Vector128 ab = Sse2.SubtractSaturate(a, b); + Vector128 ba = Sse2.SubtractSaturate(b, a); + Vector128 absAb = Sse2.Or(ab, ba); + + // Zero-extend to 16b. + Vector128 c0 = Sse2.UnpackLow(absAb, Vector128.Zero); + Vector128 c1 = Sse2.UnpackHigh(absAb, Vector128.Zero); + + // Multiply with self. + Vector128 sum1 = Sse2.MultiplyAddAdjacent(c0.AsInt16(), c0.AsInt16()); + Vector128 sum2 = Sse2.MultiplyAddAdjacent(c1.AsInt16(), c1.AsInt16()); + + return Sse2.Add(sum1, sum2); + } +#endif + [MethodImpl(InliningOptions.ShortMethod)] public static void Vp8Copy4X4(Span src, Span dst) => Copy(src, dst, 4, 4); From 1e2278b13ce9da5bebda9b261aa5f50c1c2b5531 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Wed, 8 Dec 2021 13:36:52 +0100 Subject: [PATCH 45/65] Add tests for Sse16X16 and Sse16X8 --- .../Formats/WebP/LossyUtilsTests.cs | 136 ++++++++++++++++++ 1 file changed, 136 insertions(+) diff --git a/tests/ImageSharp.Tests/Formats/WebP/LossyUtilsTests.cs b/tests/ImageSharp.Tests/Formats/WebP/LossyUtilsTests.cs index aaffac443..9625008ca 100644 --- a/tests/ImageSharp.Tests/Formats/WebP/LossyUtilsTests.cs +++ b/tests/ImageSharp.Tests/Formats/WebP/LossyUtilsTests.cs @@ -76,6 +76,124 @@ namespace SixLabors.ImageSharp.Tests.Formats.Webp Assert.True(expected.SequenceEqual(dst)); } + private static void RunVp8Sse16X16Test() + { + // arrange + byte[] a = + { + 154, 154, 151, 151, 149, 148, 151, 157, 163, 163, 154, 132, 102, 98, 104, 108, 107, 104, 104, 103, + 101, 106, 123, 119, 170, 171, 172, 171, 168, 175, 171, 173, 151, 151, 149, 150, 147, 147, 146, 159, + 164, 165, 154, 129, 92, 90, 101, 105, 104, 103, 104, 101, 100, 105, 123, 117, 172, 172, 172, 168, + 170, 177, 170, 175, 151, 149, 150, 150, 147, 147, 156, 161, 161, 161, 151, 126, 93, 90, 102, 107, + 104, 103, 104, 101, 104, 104, 122, 117, 172, 172, 170, 168, 170, 177, 172, 175, 150, 149, 152, 151, + 148, 151, 160, 159, 157, 157, 148, 133, 96, 90, 103, 107, 104, 104, 101, 100, 102, 102, 121, 117, + 170, 170, 169, 171, 171, 179, 173, 175, 149, 151, 152, 151, 148, 154, 162, 157, 154, 154, 151, 132, + 92, 89, 101, 108, 104, 102, 101, 101, 103, 103, 123, 118, 171, 168, 177, 173, 171, 178, 172, 176, + 152, 152, 152, 151, 154, 162, 161, 155, 149, 157, 156, 129, 92, 87, 101, 107, 102, 100, 107, 100, + 101, 102, 123, 118, 170, 175, 182, 172, 171, 179, 173, 175, 152, 151, 154, 155, 160, 162, 161, 153, + 150, 156, 153, 129, 92, 91, 102, 106, 100, 109, 115, 99, 101, 102, 124, 120, 171, 179, 178, 172, + 171, 181, 171, 173, 154, 154, 154, 162, 160, 158, 156, 152, 153, 157, 151, 128, 86, 86, 102, 105, + 102, 122, 114, 99, 101, 102, 125, 120, 178, 173, 177, 172, 171, 180, 172, 173, 154, 152, 158, 163, + 150, 148, 148, 156, 151, 158, 152, 129, 87, 87, 101, 105, 204, 204, 204, 204, 204, 204, 204, 204, + 204, 204, 204, 204, 204, 204, 204, 204, 154, 151, 165, 156, 141, 137, 146, 158, 152, 159, 152, 133, + 90, 88, 99, 106, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, + 154, 160, 164, 150, 126, 127, 149, 159, 155, 161, 153, 131, 84, 86, 97, 103, 204, 204, 204, 204, + 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 157, 167, 157, 137, 102, 128, 155, 161, + 157, 159, 154, 134, 84, 82, 97, 102, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, + 204, 204, 204, 204, 163, 163, 150, 113, 78, 132, 156, 162, 159, 160, 154, 132, 83, 78, 91, 97, 204, + 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 163, 157, 137, 80, 78, + 131, 154, 163, 157, 159, 149, 131, 82, 77, 94, 100, 204, 204, 204, 204, 204, 204, 204, 204, 204, + 204, 204, 204, 204, 204, 204, 204, 159, 151, 108, 72, 88, 132, 156, 162, 159, 157, 151, 130, 79, 78, + 95, 102, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 151, 130, + 82, 82, 89, 134, 154, 161, 161, 157, 152, 129, 81, 77, 95, 102, 204, 204, 204, 204, 204, 204, 204, + 204, 204, 204, 204, 204, 204, 204, 204, 204 + }; + + byte[] b = + { + 150, 150, 150, 150, 146, 149, 152, 154, 164, 166, 154, 132, 99, 92, 106, 112, 204, 204, 204, 204, + 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 150, 150, 150, 150, 146, 149, 152, 154, + 161, 164, 151, 130, 93, 86, 100, 106, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, + 204, 204, 204, 204, 150, 150, 150, 150, 146, 149, 152, 154, 158, 161, 148, 127, 93, 86, 100, 106, + 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 150, 150, 150, 150, + 146, 149, 152, 154, 156, 159, 146, 125, 99, 92, 106, 112, 204, 204, 204, 204, 204, 204, 204, 204, + 204, 204, 204, 204, 204, 204, 204, 204, 148, 148, 148, 148, 149, 158, 162, 159, 155, 155, 153, 129, + 94, 87, 101, 106, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, + 151, 151, 151, 151, 152, 159, 161, 156, 155, 155, 153, 129, 94, 87, 101, 106, 204, 204, 204, 204, + 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 154, 154, 154, 154, 156, 161, 159, 152, + 155, 155, 153, 129, 94, 87, 101, 106, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, + 204, 204, 204, 204, 156, 156, 156, 156, 159, 162, 158, 149, 155, 155, 153, 129, 94, 87, 101, 106, + 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 152, 153, 157, 162, + 150, 149, 149, 151, 155, 160, 150, 131, 91, 90, 104, 104, 204, 204, 204, 204, 204, 204, 204, 204, + 204, 204, 204, 204, 204, 204, 204, 204, 152, 156, 158, 157, 140, 137, 145, 159, 155, 160, 150, 131, + 89, 88, 102, 101, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, + 153, 161, 160, 149, 118, 128, 147, 162, 155, 160, 150, 131, 86, 85, 99, 98, 204, 204, 204, 204, 204, + 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 154, 165, 161, 144, 96, 128, 154, 159, 155, + 160, 150, 131, 83, 82, 97, 96, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, + 204, 204, 161, 160, 149, 105, 78, 127, 156, 170, 156, 156, 154, 130, 81, 77, 95, 102, 204, 204, 204, + 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 160, 160, 133, 85, 81, 129, 155, + 167, 156, 156, 154, 130, 81, 77, 95, 102, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, + 204, 204, 204, 204, 204, 156, 147, 109, 76, 85, 130, 153, 163, 156, 156, 154, 130, 81, 77, 95, 102, + 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 152, 128, 87, 83, + 88, 132, 152, 159, 156, 156, 154, 130, 81, 77, 95, 102, 204, 204, 204, 204, 204, 204, 204, 204, 204, + 204, 204, 204, 204, 204, 204, 204 + }; + + int expected = 2063; + + // act + int actual = LossyUtils.Vp8_Sse16X16(a, b); + + // assert + Assert.Equal(expected, actual); + } + + private static void RunVp8Sse16X8Test() + { + // arrange + byte[] a = + { + 107, 104, 104, 103, 101, 106, 123, 119, 170, 171, 172, 171, 168, 175, 171, 173, 151, 151, 149, 150, + 147, 147, 146, 159, 164, 165, 154, 129, 92, 90, 101, 105, 104, 103, 104, 101, 100, 105, 123, 117, + 172, 172, 172, 168, 170, 177, 170, 175, 151, 149, 150, 150, 147, 147, 156, 161, 161, 161, 151, 126, + 93, 90, 102, 107, 104, 103, 104, 101, 104, 104, 122, 117, 172, 172, 170, 168, 170, 177, 172, 175, + 150, 149, 152, 151, 148, 151, 160, 159, 157, 157, 148, 133, 96, 90, 103, 107, 104, 104, 101, 100, + 102, 102, 121, 117, 170, 170, 169, 171, 171, 179, 173, 175, 149, 151, 152, 151, 148, 154, 162, 157, + 154, 154, 151, 132, 92, 89, 101, 108, 104, 102, 101, 101, 103, 103, 123, 118, 171, 168, 177, 173, + 171, 178, 172, 176, 152, 152, 152, 151, 154, 162, 161, 155, 149, 157, 156, 129, 92, 87, 101, 107, + 102, 100, 107, 100, 101, 102, 123, 118, 170, 175, 182, 172, 171, 179, 173, 175, 152, 151, 154, 155, + 160, 162, 161, 153, 150, 156, 153, 129, 92, 91, 102, 106, 100, 109, 115, 99, 101, 102, 124, 120, + 171, 179, 178, 172, 171, 181, 171, 173, 154, 154, 154, 162, 160, 158, 156, 152, 153, 157, 151, 128, + 86, 86, 102, 105, 102, 122, 114, 99, 101, 102, 125, 120, 178, 173, 177, 172, 171, 180, 172, 173, + 154, 152, 158, 163, 150, 148, 148, 156, 151, 158, 152, 129, 87, 87, 101, 105 + }; + + byte[] b = + { + 103, 103, 103, 103, 101, 106, 122, 114, 171, 171, 171, 171, 171, 177, 169, 175, 150, 150, 150, 150, + 146, 149, 152, 154, 161, 164, 151, 130, 93, 86, 100, 106, 103, 103, 103, 103, 101, 106, 122, 114, + 171, 171, 171, 171, 171, 177, 169, 175, 150, 150, 150, 150, 146, 149, 152, 154, 158, 161, 148, 127, + 93, 86, 100, 106, 103, 103, 103, 103, 101, 106, 122, 114, 171, 171, 171, 171, 171, 177, 169, 175, + 150, 150, 150, 150, 146, 149, 152, 154, 156, 159, 146, 125, 99, 92, 106, 112, 103, 103, 103, 103, + 101, 106, 122, 114, 171, 171, 171, 171, 171, 177, 169, 175, 148, 148, 148, 148, 149, 158, 162, 159, + 155, 155, 153, 129, 94, 87, 101, 106, 102, 100, 100, 102, 100, 101, 120, 122, 170, 176, 176, 170, + 174, 180, 171, 177, 151, 151, 151, 151, 152, 159, 161, 156, 155, 155, 153, 129, 94, 87, 101, 106, + 102, 105, 105, 102, 100, 101, 120, 122, 170, 176, 176, 170, 174, 180, 171, 177, 154, 154, 154, 154, + 156, 161, 159, 152, 155, 155, 153, 129, 94, 87, 101, 106, 102, 112, 112, 102, 100, 101, 120, 122, + 170, 176, 176, 170, 174, 180, 171, 177, 156, 156, 156, 156, 159, 162, 158, 149, 155, 155, 153, 129, + 94, 87, 101, 106, 102, 117, 117, 102, 100, 101, 120, 122, 170, 176, 176, 170, 174, 180, 171, 177, + 152, 153, 157, 162, 150, 149, 149, 151, 155, 160, 150, 131, 91, 90, 104, 104 + }; + + int expected = 749; + + // act + int actual = LossyUtils.Vp8_Sse16X8(a, b); + + // assert + Assert.Equal(expected, actual); + } + private static void RunVp8Sse4X4Test() { // arrange @@ -168,6 +286,12 @@ namespace SixLabors.ImageSharp.Tests.Formats.Webp [Fact] public void RunTransformOne_Works() => RunTransformOneTest(); + [Fact] + public void Vp8Sse16X16_Works() => RunVp8Sse16X16Test(); + + [Fact] + public void Vp8Sse16X8_Works() => RunVp8Sse16X8Test(); + [Fact] public void Vp8Sse4X4_Works() => RunVp8Sse4X4Test(); @@ -190,6 +314,18 @@ namespace SixLabors.ImageSharp.Tests.Formats.Webp [Fact] public void TransformOne_WithoutHardwareIntrinsics_Works() => FeatureTestRunner.RunWithHwIntrinsicsFeature(RunTransformOneTest, HwIntrinsics.DisableHWIntrinsic); + [Fact] + public void Vp8Sse16X16_WithHardwareIntrinsics_Works() => FeatureTestRunner.RunWithHwIntrinsicsFeature(RunVp8Sse16X16Test, HwIntrinsics.AllowAll); + + [Fact] + public void Vp8Sse16X16_WithoutSSE2_Works() => FeatureTestRunner.RunWithHwIntrinsicsFeature(RunVp8Sse16X16Test, HwIntrinsics.DisableSSE2); + + [Fact] + public void Vp8Sse16X8_WithHardwareIntrinsics_Works() => FeatureTestRunner.RunWithHwIntrinsicsFeature(RunVp8Sse16X8Test, HwIntrinsics.AllowAll); + + [Fact] + public void Vp8Sse16X8_WithoutSSE2_Works() => FeatureTestRunner.RunWithHwIntrinsicsFeature(RunVp8Sse16X8Test, HwIntrinsics.DisableSSE2); + [Fact] public void Vp8Sse4X4_WithHardwareIntrinsics_Works() => FeatureTestRunner.RunWithHwIntrinsicsFeature(RunVp8Sse4X4Test, HwIntrinsics.AllowAll); From 3d00c68a721383aca8155f3d73ad0bc7b0613044 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Wed, 8 Dec 2021 14:03:48 +0100 Subject: [PATCH 46/65] Add AVX2 version of Vp8_Sse16X16 and Vp8_Sse16X8 --- .../Formats/Webp/Lossy/LossyUtils.cs | 62 +++++++++++++++++++ .../Formats/WebP/LossyUtilsTests.cs | 6 ++ 2 files changed, 68 insertions(+) diff --git a/src/ImageSharp/Formats/Webp/Lossy/LossyUtils.cs b/src/ImageSharp/Formats/Webp/Lossy/LossyUtils.cs index 69ce6c7f9..abaf72089 100644 --- a/src/ImageSharp/Formats/Webp/Lossy/LossyUtils.cs +++ b/src/ImageSharp/Formats/Webp/Lossy/LossyUtils.cs @@ -43,6 +43,11 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy public static int Vp8_Sse16X16(Span a, Span b) { #if SUPPORTS_RUNTIME_INTRINSICS + if (Avx2.IsSupported) + { + return Vp8_Sse16xN_Avx2(a, b, 4); + } + if (Sse2.IsSupported) { return Vp8_Sse16xN_Sse2(a, b, 8); @@ -58,6 +63,11 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy public static int Vp8_Sse16X8(Span a, Span b) { #if SUPPORTS_RUNTIME_INTRINSICS + if (Avx2.IsSupported) + { + return Vp8_Sse16xN_Avx2(a, b, 2); + } + if (Sse2.IsSupported) { return Vp8_Sse16xN_Sse2(a, b, 4); @@ -194,6 +204,39 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy return Numerics.ReduceSum(sum); } + [MethodImpl(InliningOptions.ShortMethod)] + private static int Vp8_Sse16xN_Avx2(Span a, Span b, int numPairs) + { + Vector256 sum = Vector256.Zero; + int offset = 0; + for (int i = 0; i < numPairs; i++) + { + // Load values. + ref byte aRef = ref MemoryMarshal.GetReference(a); + ref byte bRef = ref MemoryMarshal.GetReference(b); + var a0 = Vector256.Create( + Unsafe.As>(ref Unsafe.Add(ref aRef, offset)), + Unsafe.As>(ref Unsafe.Add(ref aRef, offset + WebpConstants.Bps))); + var b0 = Vector256.Create( + Unsafe.As>(ref Unsafe.Add(ref bRef, offset)), + Unsafe.As>(ref Unsafe.Add(ref bRef, offset + WebpConstants.Bps))); + var a1 = Vector256.Create( + Unsafe.As>(ref Unsafe.Add(ref aRef, offset + (2 * WebpConstants.Bps))), + Unsafe.As>(ref Unsafe.Add(ref aRef, offset + (3 * WebpConstants.Bps)))); + var b1 = Vector256.Create( + Unsafe.As>(ref Unsafe.Add(ref bRef, offset + (2 * WebpConstants.Bps))), + Unsafe.As>(ref Unsafe.Add(ref bRef, offset + (3 * WebpConstants.Bps)))); + + Vector256 sum1 = SubtractAndAccumulate(a0, b0); + Vector256 sum2 = SubtractAndAccumulate(a1, b1); + sum = Avx2.Add(sum, Avx2.Add(sum1, sum2)); + + offset += 4 * WebpConstants.Bps; + } + + return Numerics.ReduceSum(sum); + } + [MethodImpl(InliningOptions.ShortMethod)] private static Vector128 SubtractAndAccumulate(Vector128 a, Vector128 b) { @@ -212,6 +255,25 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy return Sse2.Add(sum1, sum2); } + + [MethodImpl(InliningOptions.ShortMethod)] + private static Vector256 SubtractAndAccumulate(Vector256 a, Vector256 b) + { + // Take abs(a-b) in 8b. + Vector256 ab = Avx2.SubtractSaturate(a, b); + Vector256 ba = Avx2.SubtractSaturate(b, a); + Vector256 absAb = Avx2.Or(ab, ba); + + // Zero-extend to 16b. + Vector256 c0 = Avx2.UnpackLow(absAb, Vector256.Zero); + Vector256 c1 = Avx2.UnpackHigh(absAb, Vector256.Zero); + + // Multiply with self. + Vector256 sum1 = Avx2.MultiplyAddAdjacent(c0.AsInt16(), c0.AsInt16()); + Vector256 sum2 = Avx2.MultiplyAddAdjacent(c1.AsInt16(), c1.AsInt16()); + + return Avx2.Add(sum1, sum2); + } #endif [MethodImpl(InliningOptions.ShortMethod)] diff --git a/tests/ImageSharp.Tests/Formats/WebP/LossyUtilsTests.cs b/tests/ImageSharp.Tests/Formats/WebP/LossyUtilsTests.cs index 9625008ca..cc5f1b4c2 100644 --- a/tests/ImageSharp.Tests/Formats/WebP/LossyUtilsTests.cs +++ b/tests/ImageSharp.Tests/Formats/WebP/LossyUtilsTests.cs @@ -320,12 +320,18 @@ namespace SixLabors.ImageSharp.Tests.Formats.Webp [Fact] public void Vp8Sse16X16_WithoutSSE2_Works() => FeatureTestRunner.RunWithHwIntrinsicsFeature(RunVp8Sse16X16Test, HwIntrinsics.DisableSSE2); + [Fact] + public void Vp8Sse16X16_WithoutAVX2_Works() => FeatureTestRunner.RunWithHwIntrinsicsFeature(RunVp8Sse16X16Test, HwIntrinsics.DisableAVX2); + [Fact] public void Vp8Sse16X8_WithHardwareIntrinsics_Works() => FeatureTestRunner.RunWithHwIntrinsicsFeature(RunVp8Sse16X8Test, HwIntrinsics.AllowAll); [Fact] public void Vp8Sse16X8_WithoutSSE2_Works() => FeatureTestRunner.RunWithHwIntrinsicsFeature(RunVp8Sse16X8Test, HwIntrinsics.DisableSSE2); + [Fact] + public void Vp8Sse16X8_WithoutAVX2_Works() => FeatureTestRunner.RunWithHwIntrinsicsFeature(RunVp8Sse16X8Test, HwIntrinsics.DisableAVX2); + [Fact] public void Vp8Sse4X4_WithHardwareIntrinsics_Works() => FeatureTestRunner.RunWithHwIntrinsicsFeature(RunVp8Sse4X4Test, HwIntrinsics.AllowAll); From 2a48c941afb70b8d33f186171129e8fa4beaf625 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Wed, 8 Dec 2021 20:01:50 +0100 Subject: [PATCH 47/65] Add AVX2 version of CollectHistogram --- .../Formats/Webp/Lossy/Vp8Histogram.cs | 44 +++++++++++++++++-- 1 file changed, 40 insertions(+), 4 deletions(-) diff --git a/src/ImageSharp/Formats/Webp/Lossy/Vp8Histogram.cs b/src/ImageSharp/Formats/Webp/Lossy/Vp8Histogram.cs index d384302b9..f679fcb13 100644 --- a/src/ImageSharp/Formats/Webp/Lossy/Vp8Histogram.cs +++ b/src/ImageSharp/Formats/Webp/Lossy/Vp8Histogram.cs @@ -3,6 +3,11 @@ using System; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +#if SUPPORTS_RUNTIME_INTRINSICS +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; +#endif namespace SixLabors.ImageSharp.Formats.Webp.Lossy { @@ -19,6 +24,10 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy /// private const int MaxCoeffThresh = 31; +#if SUPPORTS_RUNTIME_INTRINSICS + private static readonly Vector256 MaxCoeffThreshVec = Vector256.Create((short)MaxCoeffThresh); +#endif + private int maxValue; private int lastNonZero; @@ -52,11 +61,38 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy Vp8Encoding.FTransform(reference.Slice(WebpLookupTables.Vp8DspScan[j]), pred.Slice(WebpLookupTables.Vp8DspScan[j]), this.output, this.scratch); // Convert coefficients to bin. - for (int k = 0; k < 16; ++k) +#if SUPPORTS_RUNTIME_INTRINSICS + if (Avx2.IsSupported) { - int v = Math.Abs(this.output[k]) >> 3; - int clippedValue = ClipMax(v, MaxCoeffThresh); - ++this.distribution[clippedValue]; + // Load. + ref short outputRef = ref MemoryMarshal.GetReference(this.output); + Vector256 out0 = Unsafe.As>(ref outputRef); + + // v = abs(out) >> 3 + Vector256 abs0 = Avx2.Abs(out0.AsInt16()); + Vector256 v0 = Avx2.ShiftRightArithmetic(abs0.AsInt16(), 3); + + // bin = min(v, MAX_COEFF_THRESH) + Vector256 min0 = Avx2.Min(v0, MaxCoeffThreshVec); + + // Store. + Unsafe.As>(ref outputRef) = min0; + + // Convert coefficients to bin. + for (int k = 0; k < 16; ++k) + { + ++this.distribution[this.output[k]]; + } + } + else +#endif + { + for (int k = 0; k < 16; ++k) + { + int v = Math.Abs(this.output[k]) >> 3; + int clippedValue = ClipMax(v, MaxCoeffThresh); + ++this.distribution[clippedValue]; + } } } From 5f2b207d15403d57066c338f30fb8973d8e76bd3 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Wed, 8 Dec 2021 20:40:03 +0100 Subject: [PATCH 48/65] Add collect histogram tests --- .../Formats/WebP/Vp8HistogramTests.cs | 111 ++++++++++++++++++ 1 file changed, 111 insertions(+) diff --git a/tests/ImageSharp.Tests/Formats/WebP/Vp8HistogramTests.cs b/tests/ImageSharp.Tests/Formats/WebP/Vp8HistogramTests.cs index 4ff42f4ee..693626755 100644 --- a/tests/ImageSharp.Tests/Formats/WebP/Vp8HistogramTests.cs +++ b/tests/ImageSharp.Tests/Formats/WebP/Vp8HistogramTests.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using SixLabors.ImageSharp.Formats.Webp.Lossy; +using SixLabors.ImageSharp.Tests.TestUtilities; using Xunit; namespace SixLabors.ImageSharp.Tests.Formats.Webp @@ -67,6 +68,108 @@ namespace SixLabors.ImageSharp.Tests.Formats.Webp } } + private static void RunCollectHistogramTest() + { + // arrange + var histogram = new Vp8Histogram(); + + byte[] reference = + { + 154, 154, 151, 151, 149, 148, 151, 157, 163, 163, 154, 132, 102, 98, 104, 108, 107, 104, 104, 103, + 101, 106, 123, 119, 170, 171, 172, 171, 168, 175, 171, 173, 151, 151, 149, 150, 147, 147, 146, 159, + 164, 165, 154, 129, 92, 90, 101, 105, 104, 103, 104, 101, 100, 105, 123, 117, 172, 172, 172, 168, + 170, 177, 170, 175, 151, 149, 150, 150, 147, 147, 156, 161, 161, 161, 151, 126, 93, 90, 102, 107, + 104, 103, 104, 101, 104, 104, 122, 117, 172, 172, 170, 168, 170, 177, 172, 175, 150, 149, 152, 151, + 148, 151, 160, 159, 157, 157, 148, 133, 96, 90, 103, 107, 104, 104, 101, 100, 102, 102, 121, 117, + 170, 170, 169, 171, 171, 179, 173, 175, 149, 151, 152, 151, 148, 154, 162, 157, 154, 154, 151, 132, + 92, 89, 101, 108, 104, 102, 101, 101, 103, 103, 123, 118, 171, 168, 177, 173, 171, 178, 172, 176, + 152, 152, 152, 151, 154, 162, 161, 155, 149, 157, 156, 129, 92, 87, 101, 107, 102, 100, 107, 100, + 101, 102, 123, 118, 170, 175, 182, 172, 171, 179, 173, 175, 152, 151, 154, 155, 160, 162, 161, 153, + 150, 156, 153, 129, 92, 91, 102, 106, 100, 109, 115, 99, 101, 102, 124, 120, 171, 179, 178, 172, + 171, 181, 171, 173, 154, 154, 154, 162, 160, 158, 156, 152, 153, 157, 151, 128, 86, 86, 102, 105, + 102, 122, 114, 99, 101, 102, 125, 120, 178, 173, 177, 172, 171, 180, 172, 173, 154, 152, 158, 163, + 150, 148, 148, 156, 151, 158, 152, 129, 87, 87, 101, 105, 204, 204, 204, 204, 204, 204, 204, 204, + 204, 204, 204, 204, 204, 204, 204, 204, 154, 151, 165, 156, 141, 137, 146, 158, 152, 159, 152, 133, + 90, 88, 99, 106, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, + 154, 160, 164, 150, 126, 127, 149, 159, 155, 161, 153, 131, 84, 86, 97, 103, 204, 204, 204, 204, + 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 157, 167, 157, 137, 102, 128, 155, 161, + 157, 159, 154, 134, 84, 82, 97, 102, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, + 204, 204, 204, 204, 163, 163, 150, 113, 78, 132, 156, 162, 159, 160, 154, 132, 83, 78, 91, 97, 204, + 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 163, 157, 137, 80, 78, + 131, 154, 163, 157, 159, 149, 131, 82, 77, 94, 100, 204, 204, 204, 204, 204, 204, 204, 204, 204, + 204, 204, 204, 204, 204, 204, 204, 159, 151, 108, 72, 88, 132, 156, 162, 159, 157, 151, 130, 79, 78, + 95, 102, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 151, 130, + 82, 82, 89, 134, 154, 161, 161, 157, 152, 129, 81, 77, 95, 102, 204, 204, 204, 204, 204, 204, 204, + 204, 204, 204, 204, 204, 204, 204, 204, 204 + }; + byte[] pred = + { + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 129, 129, 129, 129, + 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, + 129, 129, 129, 129, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 129, 129, 129, 129, 129, 129, 129, 129, + 129, 129, 129, 129, 129, 129, 129, 129, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 129, 129, 129, 129, + 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, + 129, 129, 129, 129, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 129, 129, 129, 129, 129, 129, 129, 129, + 129, 129, 129, 129, 129, 129, 129, 129, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 129, 129, 129, 129, + 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, + 129, 129, 129, 129, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 129, 129, 129, 129, 129, 129, 129, 129, + 129, 129, 129, 129, 129, 129, 129, 129, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 129, 129, 129, 129, + 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, + 129, 129, 129, 129, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 129, 129, 129, 129, 129, 129, 129, 129, + 129, 129, 129, 129, 129, 129, 129, 129, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 129, 129, 129, 129, + 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, + 129, 129, 129, 129, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 129, 129, 129, 129, 129, 129, 129, 129, + 129, 129, 129, 129, 129, 129, 129, 129, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 129, 129, 129, 129, + 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, + 129, 129, 129, 129, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 129, 129, 129, 129, 129, 129, 129, 129, + 129, 129, 129, 129, 129, 129, 129, 129, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 129, 129, 129, 129, + 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, + 129, 129, 129, 129 + }; + int expectedAlpha = 146; + + // act + histogram.CollectHistogram(reference, pred, 0, 10); + int actualAlpha = histogram.GetAlpha(); + + // assert + Assert.Equal(expectedAlpha, actualAlpha); + } + + [Fact] + public void RunCollectHistogramTest_Works() => RunCollectHistogramTest(); + [Fact] public void GetAlpha_WithEmptyHistogram_Works() { @@ -111,5 +214,13 @@ namespace SixLabors.ImageSharp.Tests.Formats.Webp // assert Assert.Equal(1054, alpha); } + +#if SUPPORTS_RUNTIME_INTRINSICS + [Fact] + public void CollectHistogramTest_WithHardwareIntrinsics_Works() => FeatureTestRunner.RunWithHwIntrinsicsFeature(RunCollectHistogramTest, HwIntrinsics.AllowAll); + + [Fact] + public void CollectHistogramTest_WithoutHardwareIntrinsics_Works() => FeatureTestRunner.RunWithHwIntrinsicsFeature(RunCollectHistogramTest, HwIntrinsics.DisableHWIntrinsic); +#endif } } From f6301d4b679cc6fa7319858a2a7a2238f45cd6a5 Mon Sep 17 00:00:00 2001 From: Ynse Hoornenborg Date: Wed, 8 Dec 2021 21:45:04 +0100 Subject: [PATCH 49/65] Refactor Pbm option enums --- src/ImageSharp/Formats/Pbm/BinaryDecoder.cs | 12 ++--- src/ImageSharp/Formats/Pbm/BinaryEncoder.cs | 8 +-- .../Formats/Pbm/IPbmEncoderOptions.cs | 4 +- .../Formats/Pbm/PbmComponentType.cs | 26 ++++++++++ src/ImageSharp/Formats/Pbm/PbmDecoderCore.cs | 34 +++++++++---- src/ImageSharp/Formats/Pbm/PbmEncoder.cs | 4 +- src/ImageSharp/Formats/Pbm/PbmEncoderCore.cs | 16 +++--- src/ImageSharp/Formats/Pbm/PbmMetadata.cs | 9 ++-- src/ImageSharp/Formats/Pbm/PlainDecoder.cs | 8 +-- src/ImageSharp/Formats/Pbm/PlainEncoder.cs | 8 +-- .../Formats/Pbm/PbmDecoderTests.cs | 50 ++++++++++--------- .../Formats/Pbm/PbmMetadataTests.cs | 20 ++++---- 12 files changed, 123 insertions(+), 76 deletions(-) create mode 100644 src/ImageSharp/Formats/Pbm/PbmComponentType.cs diff --git a/src/ImageSharp/Formats/Pbm/BinaryDecoder.cs b/src/ImageSharp/Formats/Pbm/BinaryDecoder.cs index 2a171456a..a469ced8a 100644 --- a/src/ImageSharp/Formats/Pbm/BinaryDecoder.cs +++ b/src/ImageSharp/Formats/Pbm/BinaryDecoder.cs @@ -14,8 +14,8 @@ namespace SixLabors.ImageSharp.Formats.Pbm /// internal class BinaryDecoder { - private static L8 white = new L8(255); - private static L8 black = new L8(0); + private static L8 white = new(255); + private static L8 black = new(0); /// /// Decode the specified pixels. @@ -25,16 +25,16 @@ namespace SixLabors.ImageSharp.Formats.Pbm /// The pixel array to encode into. /// The stream to read the data from. /// The ColorType to decode. - /// The maximum expected pixel value + /// Data type of the pixles components. /// /// Thrown if an invalid combination of setting is requested. /// - public static void Process(Configuration configuration, Buffer2D pixels, BufferedReadStream stream, PbmColorType colorType, int maxPixelValue) + public static void Process(Configuration configuration, Buffer2D pixels, BufferedReadStream stream, PbmColorType colorType, PbmComponentType componentType) where TPixel : unmanaged, IPixel { if (colorType == PbmColorType.Grayscale) { - if (maxPixelValue < 256) + if (componentType == PbmComponentType.Byte) { ProcessGrayscale(configuration, pixels, stream); } @@ -45,7 +45,7 @@ namespace SixLabors.ImageSharp.Formats.Pbm } else if (colorType == PbmColorType.Rgb) { - if (maxPixelValue < 256) + if (componentType == PbmComponentType.Byte) { ProcessRgb(configuration, pixels, stream); } diff --git a/src/ImageSharp/Formats/Pbm/BinaryEncoder.cs b/src/ImageSharp/Formats/Pbm/BinaryEncoder.cs index 626026726..8b32c18c2 100644 --- a/src/ImageSharp/Formats/Pbm/BinaryEncoder.cs +++ b/src/ImageSharp/Formats/Pbm/BinaryEncoder.cs @@ -22,16 +22,16 @@ namespace SixLabors.ImageSharp.Formats.Pbm /// The bytestream to write to. /// The input image. /// The ColorType to use. - /// The maximum expected pixel value + /// Data type of the pixles components. /// /// Thrown if an invalid combination of setting is requested. /// - public static void WritePixels(Configuration configuration, Stream stream, ImageFrame image, PbmColorType colorType, int maxPixelValue) + public static void WritePixels(Configuration configuration, Stream stream, ImageFrame image, PbmColorType colorType, PbmComponentType componentType) where TPixel : unmanaged, IPixel { if (colorType == PbmColorType.Grayscale) { - if (maxPixelValue < 256) + if (componentType == PbmComponentType.Byte) { WriteGrayscale(configuration, stream, image); } @@ -42,7 +42,7 @@ namespace SixLabors.ImageSharp.Formats.Pbm } else if (colorType == PbmColorType.Rgb) { - if (maxPixelValue < 256) + if (componentType == PbmComponentType.Byte) { WriteRgb(configuration, stream, image); } diff --git a/src/ImageSharp/Formats/Pbm/IPbmEncoderOptions.cs b/src/ImageSharp/Formats/Pbm/IPbmEncoderOptions.cs index c5c409ec8..988d9e560 100644 --- a/src/ImageSharp/Formats/Pbm/IPbmEncoderOptions.cs +++ b/src/ImageSharp/Formats/Pbm/IPbmEncoderOptions.cs @@ -19,8 +19,8 @@ namespace SixLabors.ImageSharp.Formats.Pbm PbmColorType? ColorType { get; } /// - /// Gets the maximum pixel value, per component. + /// Gets the Data Type of the pixel components. /// - int? MaxPixelValue { get; } + PbmComponentType? ComponentType { get; } } } diff --git a/src/ImageSharp/Formats/Pbm/PbmComponentType.cs b/src/ImageSharp/Formats/Pbm/PbmComponentType.cs new file mode 100644 index 000000000..26272021c --- /dev/null +++ b/src/ImageSharp/Formats/Pbm/PbmComponentType.cs @@ -0,0 +1,26 @@ +// Copyright (c) Six Labors. +// Licensed under the Apache License, Version 2.0. + +namespace SixLabors.ImageSharp.Formats.Pbm +{ + /// + /// The data type of the components of the pixels. + /// + public enum PbmComponentType : byte + { + /// + /// Single bit per pixel, exclusively for . + /// + Bit = 0, + + /// + /// 8 bits unsigned integer per component. + /// + Byte = 1, + + /// + /// 16 bits unsigned integer per component. + /// + Short = 2 + } +} diff --git a/src/ImageSharp/Formats/Pbm/PbmDecoderCore.cs b/src/ImageSharp/Formats/Pbm/PbmDecoderCore.cs index 8bac0bfd1..749fc0292 100644 --- a/src/ImageSharp/Formats/Pbm/PbmDecoderCore.cs +++ b/src/ImageSharp/Formats/Pbm/PbmDecoderCore.cs @@ -16,6 +16,8 @@ namespace SixLabors.ImageSharp.Formats.Pbm /// internal sealed class PbmDecoderCore : IImageDecoderInternals { + private int maxPixelValue; + /// /// Initializes a new instance of the class. /// @@ -36,9 +38,9 @@ namespace SixLabors.ImageSharp.Formats.Pbm public Size PixelSize { get; private set; } /// - /// Gets the maximum pixel value + /// Gets the component data type /// - public int MaxPixelValue { get; private set; } + public PbmComponentType ComponentType { get; private set; } /// /// Gets the Encoding of pixels @@ -53,7 +55,7 @@ namespace SixLabors.ImageSharp.Formats.Pbm /// Size IImageDecoderInternals.Dimensions => this.PixelSize; - private bool NeedsUpscaling => this.ColorType != PbmColorType.BlackAndWhite && this.MaxPixelValue is not 255 and not 65535; + private bool NeedsUpscaling => this.ColorType != PbmColorType.BlackAndWhite && this.maxPixelValue is not 255 and not 65535; /// public Image Decode(BufferedReadStream stream, CancellationToken cancellationToken) @@ -79,7 +81,8 @@ namespace SixLabors.ImageSharp.Formats.Pbm { this.ProcessHeader(stream); - int bitsPerPixel = this.MaxPixelValue > 255 ? 16 : 8; + // BlackAndWhite pixels are encoded into a byte. + int bitsPerPixel = this.ComponentType == PbmComponentType.Short ? 16 : 8; return new ImageInfo(new PixelTypeInfo(bitsPerPixel), this.PixelSize.Width, this.PixelSize.Height, this.Metadata); } @@ -143,12 +146,21 @@ namespace SixLabors.ImageSharp.Formats.Pbm stream.SkipWhitespaceAndComments(); if (this.ColorType != PbmColorType.BlackAndWhite) { - this.MaxPixelValue = stream.ReadDecimal(); + this.maxPixelValue = stream.ReadDecimal(); + if (this.maxPixelValue > 255) + { + this.ComponentType = PbmComponentType.Short; + } + else + { + this.ComponentType = PbmComponentType.Byte; + } + stream.SkipWhitespaceAndComments(); } else { - this.MaxPixelValue = 1; + this.ComponentType = PbmComponentType.Bit; } this.PixelSize = new Size(width, height); @@ -156,7 +168,7 @@ namespace SixLabors.ImageSharp.Formats.Pbm PbmMetadata meta = this.Metadata.GetPbmMetadata(); meta.Encoding = this.Encoding; meta.ColorType = this.ColorType; - meta.MaxPixelValue = this.MaxPixelValue; + meta.ComponentType = this.ComponentType; } private void ProcessPixels(BufferedReadStream stream, Buffer2D pixels) @@ -164,19 +176,19 @@ namespace SixLabors.ImageSharp.Formats.Pbm { if (this.Encoding == PbmEncoding.Binary) { - BinaryDecoder.Process(this.Configuration, pixels, stream, this.ColorType, this.MaxPixelValue); + BinaryDecoder.Process(this.Configuration, pixels, stream, this.ColorType, this.ComponentType); } else { - PlainDecoder.Process(this.Configuration, pixels, stream, this.ColorType, this.MaxPixelValue); + PlainDecoder.Process(this.Configuration, pixels, stream, this.ColorType, this.ComponentType); } } private void ProcessUpscaling(Image image) where TPixel : unmanaged, IPixel { - int maxAllocationValue = (this.MaxPixelValue > 255) ? 65535 : 255; - float factor = maxAllocationValue / this.MaxPixelValue; + int maxAllocationValue = this.ComponentType == PbmComponentType.Short ? 65535 : 255; + float factor = maxAllocationValue / this.maxPixelValue; image.Mutate(x => x.Brightness(factor)); } } diff --git a/src/ImageSharp/Formats/Pbm/PbmEncoder.cs b/src/ImageSharp/Formats/Pbm/PbmEncoder.cs index 7984dddac..75d666063 100644 --- a/src/ImageSharp/Formats/Pbm/PbmEncoder.cs +++ b/src/ImageSharp/Formats/Pbm/PbmEncoder.cs @@ -46,9 +46,9 @@ namespace SixLabors.ImageSharp.Formats.Pbm public PbmColorType? ColorType { get; set; } /// - /// Gets or sets the maximum pixel value, per component. + /// Gets or sets the data type of the pixels components. /// - public int? MaxPixelValue { get; set; } + public PbmComponentType? ComponentType { get; set; } /// public void Encode(Image image, Stream stream) diff --git a/src/ImageSharp/Formats/Pbm/PbmEncoderCore.cs b/src/ImageSharp/Formats/Pbm/PbmEncoderCore.cs index 158786e3c..9d1f39edf 100644 --- a/src/ImageSharp/Formats/Pbm/PbmEncoderCore.cs +++ b/src/ImageSharp/Formats/Pbm/PbmEncoderCore.cs @@ -42,7 +42,7 @@ namespace SixLabors.ImageSharp.Formats.Pbm /// /// Gets the maximum pixel value, per component. /// - private int maxPixelValue; + private PbmComponentType componentType; /// /// Initializes a new instance of the class. @@ -87,8 +87,11 @@ namespace SixLabors.ImageSharp.Formats.Pbm this.colorType = this.options.ColorType ?? metadata.ColorType; if (this.colorType != PbmColorType.BlackAndWhite) { - this.maxPixelValue = this.options.MaxPixelValue ?? metadata.MaxPixelValue; - this.maxPixelValue = Math.Max(this.maxPixelValue, PbmConstants.MaxLength); + this.componentType = this.options.ComponentType ?? metadata.ComponentType; + } + else + { + this.componentType = PbmComponentType.Bit; } } @@ -151,7 +154,8 @@ namespace SixLabors.ImageSharp.Formats.Pbm if (this.colorType != PbmColorType.BlackAndWhite) { - Utf8Formatter.TryFormat(this.maxPixelValue, buffer.Slice(written), out bytesWritten); + int maxPixelValue = this.componentType == PbmComponentType.Short ? 65535 : 255; + Utf8Formatter.TryFormat(maxPixelValue, buffer.Slice(written), out bytesWritten); written += bytesWritten; buffer[written++] = NewLine; } @@ -172,11 +176,11 @@ namespace SixLabors.ImageSharp.Formats.Pbm { if (this.encoding == PbmEncoding.Plain) { - PlainEncoder.WritePixels(this.configuration, stream, image, this.colorType, this.maxPixelValue); + PlainEncoder.WritePixels(this.configuration, stream, image, this.colorType, this.componentType); } else { - BinaryEncoder.WritePixels(this.configuration, stream, image, this.colorType, this.maxPixelValue); + BinaryEncoder.WritePixels(this.configuration, stream, image, this.colorType, this.componentType); } } } diff --git a/src/ImageSharp/Formats/Pbm/PbmMetadata.cs b/src/ImageSharp/Formats/Pbm/PbmMetadata.cs index 869b1b06d..a00ae46de 100644 --- a/src/ImageSharp/Formats/Pbm/PbmMetadata.cs +++ b/src/ImageSharp/Formats/Pbm/PbmMetadata.cs @@ -11,7 +11,8 @@ namespace SixLabors.ImageSharp.Formats.Pbm /// /// Initializes a new instance of the class. /// - public PbmMetadata() => this.MaxPixelValue = this.ColorType == PbmColorType.BlackAndWhite ? 1 : 255; + public PbmMetadata() => + this.ComponentType = this.ColorType == PbmColorType.BlackAndWhite ? PbmComponentType.Bit : PbmComponentType.Byte; /// /// Initializes a new instance of the class. @@ -21,7 +22,7 @@ namespace SixLabors.ImageSharp.Formats.Pbm { this.Encoding = other.Encoding; this.ColorType = other.ColorType; - this.MaxPixelValue = other.MaxPixelValue; + this.ComponentType = other.ComponentType; } /// @@ -35,9 +36,9 @@ namespace SixLabors.ImageSharp.Formats.Pbm public PbmColorType ColorType { get; set; } = PbmColorType.Grayscale; /// - /// Gets or sets the maximum pixel value. + /// Gets or sets the data type of the pixel components. /// - public int MaxPixelValue { get; set; } + public PbmComponentType ComponentType { get; set; } /// public IDeepCloneable DeepClone() => new PbmMetadata(this); diff --git a/src/ImageSharp/Formats/Pbm/PlainDecoder.cs b/src/ImageSharp/Formats/Pbm/PlainDecoder.cs index 4521f9b64..a9e90d788 100644 --- a/src/ImageSharp/Formats/Pbm/PlainDecoder.cs +++ b/src/ImageSharp/Formats/Pbm/PlainDecoder.cs @@ -25,13 +25,13 @@ namespace SixLabors.ImageSharp.Formats.Pbm /// The pixel array to encode into. /// The stream to read the data from. /// The ColorType to decode. - /// The maximum expected pixel value - public static void Process(Configuration configuration, Buffer2D pixels, BufferedReadStream stream, PbmColorType colorType, int maxPixelValue) + /// Data type of the pixles components. + public static void Process(Configuration configuration, Buffer2D pixels, BufferedReadStream stream, PbmColorType colorType, PbmComponentType componentType) where TPixel : unmanaged, IPixel { if (colorType == PbmColorType.Grayscale) { - if (maxPixelValue < 256) + if (componentType == PbmComponentType.Byte) { ProcessGrayscale(configuration, pixels, stream); } @@ -42,7 +42,7 @@ namespace SixLabors.ImageSharp.Formats.Pbm } else if (colorType == PbmColorType.Rgb) { - if (maxPixelValue < 256) + if (componentType == PbmComponentType.Byte) { ProcessRgb(configuration, pixels, stream); } diff --git a/src/ImageSharp/Formats/Pbm/PlainEncoder.cs b/src/ImageSharp/Formats/Pbm/PlainEncoder.cs index 8d534b7a9..75e6f56e9 100644 --- a/src/ImageSharp/Formats/Pbm/PlainEncoder.cs +++ b/src/ImageSharp/Formats/Pbm/PlainEncoder.cs @@ -36,13 +36,13 @@ namespace SixLabors.ImageSharp.Formats.Pbm /// The bytestream to write to. /// The input image. /// The ColorType to use. - /// The maximum expected pixel value - public static void WritePixels(Configuration configuration, Stream stream, ImageFrame image, PbmColorType colorType, int maxPixelValue) + /// Data type of the pixles components. + public static void WritePixels(Configuration configuration, Stream stream, ImageFrame image, PbmColorType colorType, PbmComponentType componentType) where TPixel : unmanaged, IPixel { if (colorType == PbmColorType.Grayscale) { - if (maxPixelValue < 256) + if (componentType == PbmComponentType.Byte) { WriteGrayscale(configuration, stream, image); } @@ -53,7 +53,7 @@ namespace SixLabors.ImageSharp.Formats.Pbm } else if (colorType == PbmColorType.Rgb) { - if (maxPixelValue < 256) + if (componentType == PbmComponentType.Byte) { WriteRgb(configuration, stream, image); } diff --git a/tests/ImageSharp.Tests/Formats/Pbm/PbmDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Pbm/PbmDecoderTests.cs index 51bf61d23..97237bca5 100644 --- a/tests/ImageSharp.Tests/Formats/Pbm/PbmDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Pbm/PbmDecoderTests.cs @@ -14,16 +14,16 @@ namespace SixLabors.ImageSharp.Tests.Formats.Pbm public class PbmDecoderTests { [Theory] - [InlineData(BlackAndWhitePlain, PbmColorType.BlackAndWhite)] - [InlineData(BlackAndWhiteBinary, PbmColorType.BlackAndWhite)] - [InlineData(GrayscalePlain, PbmColorType.Grayscale)] - [InlineData(GrayscalePlainMagick, PbmColorType.Grayscale)] - [InlineData(GrayscaleBinary, PbmColorType.Grayscale)] - [InlineData(GrayscaleBinaryWide, PbmColorType.Grayscale)] - [InlineData(RgbPlain, PbmColorType.Rgb)] - [InlineData(RgbPlainMagick, PbmColorType.Rgb)] - [InlineData(RgbBinary, PbmColorType.Rgb)] - public void ImageLoadCanDecode(string imagePath, PbmColorType expectedColorType) + [InlineData(BlackAndWhitePlain, PbmColorType.BlackAndWhite, PbmComponentType.Bit)] + [InlineData(BlackAndWhiteBinary, PbmColorType.BlackAndWhite, PbmComponentType.Bit)] + [InlineData(GrayscalePlain, PbmColorType.Grayscale, PbmComponentType.Byte)] + [InlineData(GrayscalePlainMagick, PbmColorType.Grayscale, PbmComponentType.Byte)] + [InlineData(GrayscaleBinary, PbmColorType.Grayscale, PbmComponentType.Byte)] + [InlineData(GrayscaleBinaryWide, PbmColorType.Grayscale, PbmComponentType.Short)] + [InlineData(RgbPlain, PbmColorType.Rgb, PbmComponentType.Byte)] + [InlineData(RgbPlainMagick, PbmColorType.Rgb, PbmComponentType.Byte)] + [InlineData(RgbBinary, PbmColorType.Rgb, PbmComponentType.Byte)] + public void ImageLoadCanDecode(string imagePath, PbmColorType expectedColorType, PbmComponentType expectedComponentType) { // Arrange var testFile = TestFile.Create(imagePath); @@ -34,9 +34,10 @@ namespace SixLabors.ImageSharp.Tests.Formats.Pbm // Assert Assert.NotNull(image); - PbmMetadata bitmapMetadata = image.Metadata.GetPbmMetadata(); - Assert.NotNull(bitmapMetadata); - Assert.Equal(expectedColorType, bitmapMetadata.ColorType); + PbmMetadata metadata = image.Metadata.GetPbmMetadata(); + Assert.NotNull(metadata); + Assert.Equal(expectedColorType, metadata.ColorType); + Assert.Equal(expectedComponentType, metadata.ComponentType); } [Theory] @@ -77,21 +78,22 @@ namespace SixLabors.ImageSharp.Tests.Formats.Pbm } [Theory] - [WithFile(BlackAndWhitePlain, PixelTypes.L8, true)] - [WithFile(BlackAndWhiteBinary, PixelTypes.L8, true)] - [WithFile(GrayscalePlain, PixelTypes.L8, true)] - [WithFile(GrayscalePlainNormalized, PixelTypes.L8, true)] - [WithFile(GrayscaleBinary, PixelTypes.L8, true)] - [WithFile(GrayscaleBinaryWide, PixelTypes.L16, true)] - [WithFile(RgbPlain, PixelTypes.Rgb24, false)] - [WithFile(RgbPlainNormalized, PixelTypes.Rgb24, false)] - [WithFile(RgbBinary, PixelTypes.Rgb24, false)] - public void DecodeReferenceImage(TestImageProvider provider, bool isGrayscale) + [WithFile(BlackAndWhitePlain, PixelTypes.L8, "pbm")] + [WithFile(BlackAndWhiteBinary, PixelTypes.L8, "pbm")] + [WithFile(GrayscalePlain, PixelTypes.L8, "pgm")] + [WithFile(GrayscalePlainNormalized, PixelTypes.L8, "pgm")] + [WithFile(GrayscaleBinary, PixelTypes.L8, "pgm")] + [WithFile(GrayscaleBinaryWide, PixelTypes.L16, "pgm")] + [WithFile(RgbPlain, PixelTypes.Rgb24, "ppm")] + [WithFile(RgbPlainNormalized, PixelTypes.Rgb24, "ppm")] + [WithFile(RgbBinary, PixelTypes.Rgb24, "ppm")] + public void DecodeReferenceImage(TestImageProvider provider, string extension) where TPixel : unmanaged, IPixel { using Image image = provider.GetImage(); - image.DebugSave(provider); + image.DebugSave(provider, extension: extension); + bool isGrayscale = extension is "pgm" or "pbm"; image.CompareToReferenceOutput(provider, grayscale: isGrayscale); } } diff --git a/tests/ImageSharp.Tests/Formats/Pbm/PbmMetadataTests.cs b/tests/ImageSharp.Tests/Formats/Pbm/PbmMetadataTests.cs index 00b4f443d..7915d224a 100644 --- a/tests/ImageSharp.Tests/Formats/Pbm/PbmMetadataTests.cs +++ b/tests/ImageSharp.Tests/Formats/Pbm/PbmMetadataTests.cs @@ -20,8 +20,10 @@ namespace SixLabors.ImageSharp.Tests.Formats.Pbm var clone = (PbmMetadata)meta.DeepClone(); clone.ColorType = PbmColorType.Rgb; + clone.ComponentType = PbmComponentType.Short; Assert.False(meta.ColorType.Equals(clone.ColorType)); + Assert.False(meta.ComponentType.Equals(clone.ComponentType)); } [Theory] @@ -63,14 +65,14 @@ namespace SixLabors.ImageSharp.Tests.Formats.Pbm } [Theory] - [InlineData(BlackAndWhitePlain, 1)] - [InlineData(BlackAndWhiteBinary, 1)] - [InlineData(GrayscaleBinary, 255)] - [InlineData(GrayscaleBinaryWide, 65535)] - [InlineData(GrayscalePlain, 15)] - [InlineData(RgbBinary, 255)] - [InlineData(RgbPlain, 15)] - public void Identify_DetectsCorrectMaxPixelValue(string imagePath, int expectedMaxPixelValue) + [InlineData(BlackAndWhitePlain, PbmComponentType.Bit)] + [InlineData(BlackAndWhiteBinary, PbmComponentType.Bit)] + [InlineData(GrayscaleBinary, PbmComponentType.Byte)] + [InlineData(GrayscaleBinaryWide, PbmComponentType.Short)] + [InlineData(GrayscalePlain, PbmComponentType.Byte)] + [InlineData(RgbBinary, PbmComponentType.Byte)] + [InlineData(RgbPlain, PbmComponentType.Byte)] + public void Identify_DetectsCorrectComponentType(string imagePath, PbmComponentType expectedComponentType) { var testFile = TestFile.Create(imagePath); using var stream = new MemoryStream(testFile.Bytes, false); @@ -78,7 +80,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Pbm Assert.NotNull(imageInfo); PbmMetadata bitmapMetadata = imageInfo.Metadata.GetPbmMetadata(); Assert.NotNull(bitmapMetadata); - Assert.Equal(expectedMaxPixelValue, bitmapMetadata.MaxPixelValue); + Assert.Equal(expectedComponentType, bitmapMetadata.ComponentType); } } } From 1ae1d8ed6675f4b5d1812b892461edc5b977025e Mon Sep 17 00:00:00 2001 From: Brian Popow <38701097+brianpopow@users.noreply.github.com> Date: Thu, 9 Dec 2021 14:19:52 +0100 Subject: [PATCH 50/65] Use nint for offset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Günther Foidl --- src/ImageSharp/Formats/Webp/Lossy/LossyUtils.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ImageSharp/Formats/Webp/Lossy/LossyUtils.cs b/src/ImageSharp/Formats/Webp/Lossy/LossyUtils.cs index abaf72089..1b7e5633f 100644 --- a/src/ImageSharp/Formats/Webp/Lossy/LossyUtils.cs +++ b/src/ImageSharp/Formats/Webp/Lossy/LossyUtils.cs @@ -183,7 +183,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy private static int Vp8_Sse16xN_Sse2(Span a, Span b, int numPairs) { Vector128 sum = Vector128.Zero; - int offset = 0; + nint offset = 0; for (int i = 0; i < numPairs; i++) { // Load values. @@ -208,7 +208,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy private static int Vp8_Sse16xN_Avx2(Span a, Span b, int numPairs) { Vector256 sum = Vector256.Zero; - int offset = 0; + nint offset = 0; for (int i = 0; i < numPairs; i++) { // Load values. From 8e1c3fa6bfab40d00d4edabf5147679ee3d1d3c3 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Thu, 9 Dec 2021 14:23:46 +0100 Subject: [PATCH 51/65] Move GetReference outside of the loop --- src/ImageSharp/Formats/Webp/Lossy/LossyUtils.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ImageSharp/Formats/Webp/Lossy/LossyUtils.cs b/src/ImageSharp/Formats/Webp/Lossy/LossyUtils.cs index 1b7e5633f..8938ede0a 100644 --- a/src/ImageSharp/Formats/Webp/Lossy/LossyUtils.cs +++ b/src/ImageSharp/Formats/Webp/Lossy/LossyUtils.cs @@ -184,11 +184,11 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy { Vector128 sum = Vector128.Zero; nint offset = 0; + ref byte aRef = ref MemoryMarshal.GetReference(a); + ref byte bRef = ref MemoryMarshal.GetReference(b); for (int i = 0; i < numPairs; i++) { // Load values. - ref byte aRef = ref MemoryMarshal.GetReference(a); - ref byte bRef = ref MemoryMarshal.GetReference(b); Vector128 a0 = Unsafe.As>(ref Unsafe.Add(ref aRef, offset)); Vector128 b0 = Unsafe.As>(ref Unsafe.Add(ref bRef, offset)); Vector128 a1 = Unsafe.As>(ref Unsafe.Add(ref aRef, offset + WebpConstants.Bps)); @@ -209,11 +209,11 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy { Vector256 sum = Vector256.Zero; nint offset = 0; + ref byte aRef = ref MemoryMarshal.GetReference(a); + ref byte bRef = ref MemoryMarshal.GetReference(b); for (int i = 0; i < numPairs; i++) { // Load values. - ref byte aRef = ref MemoryMarshal.GetReference(a); - ref byte bRef = ref MemoryMarshal.GetReference(b); var a0 = Vector256.Create( Unsafe.As>(ref Unsafe.Add(ref aRef, offset)), Unsafe.As>(ref Unsafe.Add(ref aRef, offset + WebpConstants.Bps))); From dd051e2248bc67880981fa48194a90a08add5eff Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Thu, 9 Dec 2021 20:03:05 +0100 Subject: [PATCH 52/65] Remove RunSerial from tests --- .../Formats/Bmp/BmpDecoderTests.cs | 1 - .../Formats/Bmp/BmpEncoderTests.cs | 7 +++---- .../Formats/GeneralFormatTests.cs | 8 +++----- .../Formats/Gif/GifDecoderTests.cs | 3 +-- .../Formats/Gif/GifEncoderTests.cs | 3 +-- .../Formats/Gif/GifMetadataTests.cs | 5 ++--- .../Formats/Jpg/JpegDecoderTests.cs | 3 +-- .../Formats/Jpg/JpegEncoderTests.cs | 13 ++++++------- .../Formats/Png/PngDecoderTests.cs | 3 +-- .../Formats/Png/PngEncoderTests.cs | 19 +++++++++---------- .../Formats/Tga/TgaDecoderTests.cs | 3 +-- .../Formats/Tga/TgaEncoderTests.cs | 5 ++--- .../Formats/Tiff/TiffDecoderTests.cs | 5 ++--- .../Formats/Tiff/TiffEncoderTests.cs | 1 - .../Formats/Tiff/TiffMetadataTests.cs | 3 +-- .../Formats/WebP/WebpDecoderTests.cs | 1 - .../Formats/WebP/WebpEncoderTests.cs | 1 - 17 files changed, 33 insertions(+), 51 deletions(-) diff --git a/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs index 4e6dc36dc..f85bc78fc 100644 --- a/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs @@ -19,7 +19,6 @@ using static SixLabors.ImageSharp.Tests.TestImages.Bmp; // ReSharper disable InconsistentNaming namespace SixLabors.ImageSharp.Tests.Formats.Bmp { - [Collection("RunSerial")] [Trait("Format", "Bmp")] public class BmpDecoderTests { diff --git a/tests/ImageSharp.Tests/Formats/Bmp/BmpEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Bmp/BmpEncoderTests.cs index d645f0b60..073cf5fcf 100644 --- a/tests/ImageSharp.Tests/Formats/Bmp/BmpEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Bmp/BmpEncoderTests.cs @@ -17,19 +17,18 @@ using static SixLabors.ImageSharp.Tests.TestImages.Bmp; // ReSharper disable InconsistentNaming namespace SixLabors.ImageSharp.Tests.Formats.Bmp { - [Collection("RunSerial")] [Trait("Format", "Bmp")] public class BmpEncoderTests { public static readonly TheoryData BitsPerPixel = - new TheoryData + new() { BmpBitsPerPixel.Pixel24, BmpBitsPerPixel.Pixel32 }; public static readonly TheoryData RatioFiles = - new TheoryData + new() { { Car, 3780, 3780, PixelResolutionUnit.PixelsPerMeter }, { V5Header, 3780, 3780, PixelResolutionUnit.PixelsPerMeter }, @@ -37,7 +36,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Bmp }; public static readonly TheoryData BmpBitsPerPixelFiles = - new TheoryData + new() { { Bit1, BmpBitsPerPixel.Pixel1 }, { Bit4, BmpBitsPerPixel.Pixel4 }, diff --git a/tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs b/tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs index 26eff2650..73c332f66 100644 --- a/tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs +++ b/tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs @@ -8,7 +8,6 @@ using System.Linq; using System.Reflection; using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.Formats.Png; -using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Processing.Processors.Quantization; @@ -16,7 +15,6 @@ using Xunit; namespace SixLabors.ImageSharp.Tests.Formats { - [Collection("RunSerial")] public class GeneralFormatTests { /// @@ -34,7 +32,7 @@ namespace SixLabors.ImageSharp.Tests.Formats /// /// The collection of image files to test against. /// - protected static readonly List Files = new List + protected static readonly List Files = new() { TestFile.Create(TestImages.Jpeg.Baseline.Calliphora), TestFile.Create(TestImages.Bmp.Car), @@ -85,8 +83,8 @@ namespace SixLabors.ImageSharp.Tests.Formats } public static readonly TheoryData QuantizerNames = - new TheoryData - { + new() + { nameof(KnownQuantizers.Octree), nameof(KnownQuantizers.WebSafe), nameof(KnownQuantizers.Werner), diff --git a/tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs index 824ca535b..6bf606ac9 100644 --- a/tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs @@ -17,13 +17,12 @@ using Xunit; // ReSharper disable InconsistentNaming namespace SixLabors.ImageSharp.Tests.Formats.Gif { - [Collection("RunSerial")] [Trait("Format", "Gif")] public class GifDecoderTests { private const PixelTypes TestPixelTypes = PixelTypes.Rgba32 | PixelTypes.RgbaVector | PixelTypes.Argb32; - private static GifDecoder GifDecoder => new GifDecoder(); + private static GifDecoder GifDecoder => new(); public static readonly string[] MultiFrameTestFiles = { diff --git a/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs index 00d43b6ff..cb24de81b 100644 --- a/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs @@ -13,7 +13,6 @@ using Xunit; // ReSharper disable InconsistentNaming namespace SixLabors.ImageSharp.Tests.Formats.Gif { - [Collection("RunSerial")] [Trait("Format", "Gif")] public class GifEncoderTests { @@ -21,7 +20,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Gif private static readonly ImageComparer ValidatorComparer = ImageComparer.TolerantPercentage(0.0015F); public static readonly TheoryData RatioFiles = - new TheoryData + new() { { TestImages.Gif.Rings, (int)ImageMetadata.DefaultHorizontalResolution, (int)ImageMetadata.DefaultVerticalResolution, PixelResolutionUnit.PixelsPerInch }, { TestImages.Gif.Ratio1x4, 1, 4, PixelResolutionUnit.AspectRatio }, diff --git a/tests/ImageSharp.Tests/Formats/Gif/GifMetadataTests.cs b/tests/ImageSharp.Tests/Formats/Gif/GifMetadataTests.cs index 59f7ebb74..5699b4741 100644 --- a/tests/ImageSharp.Tests/Formats/Gif/GifMetadataTests.cs +++ b/tests/ImageSharp.Tests/Formats/Gif/GifMetadataTests.cs @@ -12,12 +12,11 @@ using Xunit; namespace SixLabors.ImageSharp.Tests.Formats.Gif { - [Collection("RunSerial")] [Trait("Format", "Gif")] public class GifMetadataTests { public static readonly TheoryData RatioFiles = - new TheoryData + new() { { TestImages.Gif.Rings, (int)ImageMetadata.DefaultHorizontalResolution, (int)ImageMetadata.DefaultVerticalResolution, PixelResolutionUnit.PixelsPerInch }, { TestImages.Gif.Ratio1x4, 1, 4, PixelResolutionUnit.AspectRatio }, @@ -25,7 +24,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Gif }; public static readonly TheoryData RepeatFiles = - new TheoryData + new() { { TestImages.Gif.Cheers, 0 }, { TestImages.Gif.Receipt, 1 }, diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs index dcdfc3e42..08d8d9038 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs @@ -21,8 +21,7 @@ using Xunit.Abstractions; namespace SixLabors.ImageSharp.Tests.Formats.Jpg { // TODO: Scatter test cases into multiple test classes - [Collection("RunSerial")] - [Trait("Format", "Jpg")] + [Trait("Format", "Jpg")] public partial class JpegDecoderTests { public const PixelTypes CommonNonDefaultPixelTypes = PixelTypes.Rgba32 | PixelTypes.Argb32 | PixelTypes.Bgr24 | PixelTypes.RgbaVector; diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs index 62952f537..18eae9fbd 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs @@ -19,23 +19,22 @@ using Xunit; namespace SixLabors.ImageSharp.Tests.Formats.Jpg { - [Collection("RunSerial")] [Trait("Format", "Jpg")] public class JpegEncoderTests { - private static JpegEncoder JpegEncoder => new JpegEncoder(); + private static JpegEncoder JpegEncoder => new(); - private static JpegDecoder JpegDecoder => new JpegDecoder(); + private static JpegDecoder JpegDecoder => new(); public static readonly TheoryData QualityFiles = - new TheoryData + new() { { TestImages.Jpeg.Baseline.Calliphora, 80 }, { TestImages.Jpeg.Progressive.Fb, 75 } }; public static readonly TheoryData BitsPerPixel_Quality = - new TheoryData + new() { { JpegColorType.YCbCrRatio420, 40 }, { JpegColorType.YCbCrRatio420, 60 }, @@ -49,7 +48,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg }; public static readonly TheoryData Grayscale_Quality = - new TheoryData + new() { { 40 }, { 60 }, @@ -57,7 +56,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg }; public static readonly TheoryData RatioFiles = - new TheoryData + new() { { TestImages.Jpeg.Baseline.Ratio1x1, 1, 1, PixelResolutionUnit.AspectRatio }, { TestImages.Jpeg.Baseline.Snake, 300, 300, PixelResolutionUnit.PixelsPerInch }, diff --git a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs index 9fc4d03dd..543a544d0 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs @@ -16,13 +16,12 @@ using Xunit; // ReSharper disable InconsistentNaming namespace SixLabors.ImageSharp.Tests.Formats.Png { - [Collection("RunSerial")] [Trait("Format", "Png")] public partial class PngDecoderTests { private const PixelTypes PixelTypes = Tests.PixelTypes.Rgba32 | Tests.PixelTypes.RgbaVector | Tests.PixelTypes.Argb32; - private static PngDecoder PngDecoder => new PngDecoder(); + private static PngDecoder PngDecoder => new(); public static readonly string[] CommonTestImages = { diff --git a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs index 9e99dded8..3cc879d6b 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs @@ -15,21 +15,20 @@ using Xunit; namespace SixLabors.ImageSharp.Tests.Formats.Png { - [Collection("RunSerial")] [Trait("Format", "Png")] public partial class PngEncoderTests { - private static PngEncoder PngEncoder => new PngEncoder(); + private static PngEncoder PngEncoder => new(); public static readonly TheoryData PngBitDepthFiles = - new TheoryData + new() { { TestImages.Png.Rgb48Bpp, PngBitDepth.Bit16 }, { TestImages.Png.Bpp1, PngBitDepth.Bit1 } }; public static readonly TheoryData PngTrnsFiles = - new TheoryData + new() { { TestImages.Png.Gray1BitTrans, PngBitDepth.Bit1, PngColorType.Grayscale }, { TestImages.Png.Gray2BitTrans, PngBitDepth.Bit2, PngColorType.Grayscale }, @@ -43,7 +42,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png /// /// All types except Palette /// - public static readonly TheoryData PngColorTypes = new TheoryData + public static readonly TheoryData PngColorTypes = new() { PngColorType.RgbWithAlpha, PngColorType.Rgb, @@ -51,7 +50,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png PngColorType.GrayscaleWithAlpha, }; - public static readonly TheoryData PngFilterMethods = new TheoryData + public static readonly TheoryData PngFilterMethods = new() { PngFilterMethod.None, PngFilterMethod.Sub, @@ -65,7 +64,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png /// All types except Palette /// public static readonly TheoryData CompressionLevels - = new TheoryData + = new() { PngCompressionLevel.Level0, PngCompressionLevel.Level1, @@ -79,12 +78,12 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png PngCompressionLevel.Level9, }; - public static readonly TheoryData PaletteSizes = new TheoryData + public static readonly TheoryData PaletteSizes = new() { 30, 55, 100, 201, 255 }; - public static readonly TheoryData PaletteLargeOnly = new TheoryData + public static readonly TheoryData PaletteLargeOnly = new() { 80, 100, 120, 230 }; @@ -96,7 +95,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png }; public static readonly TheoryData RatioFiles = - new TheoryData + new() { { TestImages.Png.Splash, 11810, 11810, PixelResolutionUnit.PixelsPerMeter }, { TestImages.Png.Ratio1x4, 1, 4, PixelResolutionUnit.AspectRatio }, diff --git a/tests/ImageSharp.Tests/Formats/Tga/TgaDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Tga/TgaDecoderTests.cs index 1c53ff6a1..ffe7a048c 100644 --- a/tests/ImageSharp.Tests/Formats/Tga/TgaDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tga/TgaDecoderTests.cs @@ -15,11 +15,10 @@ using static SixLabors.ImageSharp.Tests.TestImages.Tga; // ReSharper disable InconsistentNaming namespace SixLabors.ImageSharp.Tests.Formats.Tga { - [Collection("RunSerial")] [Trait("Format", "Tga")] public class TgaDecoderTests { - private static TgaDecoder TgaDecoder => new TgaDecoder(); + private static TgaDecoder TgaDecoder => new(); [Theory] [WithFile(Gray8BitTopLeft, PixelTypes.Rgba32)] diff --git a/tests/ImageSharp.Tests/Formats/Tga/TgaEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Tga/TgaEncoderTests.cs index 4c768a1a5..642f53c0b 100644 --- a/tests/ImageSharp.Tests/Formats/Tga/TgaEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tga/TgaEncoderTests.cs @@ -11,19 +11,18 @@ using static SixLabors.ImageSharp.Tests.TestImages.Tga; // ReSharper disable InconsistentNaming namespace SixLabors.ImageSharp.Tests.Formats.Tga { - [Collection("RunSerial")] [Trait("Format", "Tga")] public class TgaEncoderTests { public static readonly TheoryData BitsPerPixel = - new TheoryData + new() { TgaBitsPerPixel.Pixel24, TgaBitsPerPixel.Pixel32 }; public static readonly TheoryData TgaBitsPerPixelFiles = - new TheoryData + new() { { Gray8BitBottomLeft, TgaBitsPerPixel.Pixel8 }, { Bit16BottomLeft, TgaBitsPerPixel.Pixel16 }, diff --git a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs index 4a13bbe62..b7bd5275d 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs @@ -15,15 +15,14 @@ using static SixLabors.ImageSharp.Tests.TestImages.Tiff; namespace SixLabors.ImageSharp.Tests.Formats.Tiff { - [Collection("RunSerial")] [Trait("Format", "Tiff")] public class TiffDecoderTests { public static readonly string[] MultiframeTestImages = Multiframes; - private static TiffDecoder TiffDecoder => new TiffDecoder(); + private static TiffDecoder TiffDecoder => new(); - private static MagickReferenceDecoder ReferenceDecoder => new MagickReferenceDecoder(); + private static MagickReferenceDecoder ReferenceDecoder => new(); [Theory] [WithFile(RgbUncompressedTiled, PixelTypes.Rgba32)] diff --git a/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderTests.cs index d85ed16a7..aded52cd9 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderTests.cs @@ -11,7 +11,6 @@ using static SixLabors.ImageSharp.Tests.TestImages.Tiff; namespace SixLabors.ImageSharp.Tests.Formats.Tiff { - [Collection("RunSerial")] [Trait("Format", "Tiff")] public class TiffEncoderTests : TiffEncoderBaseTester { diff --git a/tests/ImageSharp.Tests/Formats/Tiff/TiffMetadataTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/TiffMetadataTests.cs index cdd9616a7..64c029b44 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/TiffMetadataTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tiff/TiffMetadataTests.cs @@ -16,11 +16,10 @@ using static SixLabors.ImageSharp.Tests.TestImages.Tiff; namespace SixLabors.ImageSharp.Tests.Formats.Tiff { - [Collection("RunSerial")] [Trait("Format", "Tiff")] public class TiffMetadataTests { - private static TiffDecoder TiffDecoder => new TiffDecoder(); + private static TiffDecoder TiffDecoder => new(); [Fact] public void TiffMetadata_CloneIsDeep() diff --git a/tests/ImageSharp.Tests/Formats/WebP/WebpDecoderTests.cs b/tests/ImageSharp.Tests/Formats/WebP/WebpDecoderTests.cs index 2cbeff2ce..22342e612 100644 --- a/tests/ImageSharp.Tests/Formats/WebP/WebpDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/WebP/WebpDecoderTests.cs @@ -12,7 +12,6 @@ using static SixLabors.ImageSharp.Tests.TestImages.Webp; // ReSharper disable InconsistentNaming namespace SixLabors.ImageSharp.Tests.Formats.Webp { - [Collection("RunSerial")] [Trait("Format", "Webp")] public class WebpDecoderTests { diff --git a/tests/ImageSharp.Tests/Formats/WebP/WebpEncoderTests.cs b/tests/ImageSharp.Tests/Formats/WebP/WebpEncoderTests.cs index ec0040a46..607d4c764 100644 --- a/tests/ImageSharp.Tests/Formats/WebP/WebpEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/WebP/WebpEncoderTests.cs @@ -11,7 +11,6 @@ using static SixLabors.ImageSharp.Tests.TestImages.Webp; namespace SixLabors.ImageSharp.Tests.Formats.Webp { - [Collection("RunSerial")] [Trait("Format", "Webp")] public class WebpEncoderTests { From 749452503b6a7f638a1adf31b391a577569c4080 Mon Sep 17 00:00:00 2001 From: Ynse Hoornenborg Date: Fri, 10 Dec 2021 13:25:14 +0100 Subject: [PATCH 53/65] Write EOF indicated for plain encoding --- src/ImageSharp/Formats/Pbm/PlainEncoder.cs | 3 +++ tests/ImageSharp.Tests/Formats/Pbm/PbmEncoderTests.cs | 8 +++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/ImageSharp/Formats/Pbm/PlainEncoder.cs b/src/ImageSharp/Formats/Pbm/PlainEncoder.cs index 75e6f56e9..2868922ea 100644 --- a/src/ImageSharp/Formats/Pbm/PlainEncoder.cs +++ b/src/ImageSharp/Formats/Pbm/PlainEncoder.cs @@ -66,6 +66,9 @@ namespace SixLabors.ImageSharp.Formats.Pbm { WriteBlackAndWhite(configuration, stream, image); } + + // Write EOF indicator, as some encoders expect it. + stream.WriteByte(Space); } private static void WriteGrayscale(Configuration configuration, Stream stream, ImageFrame image) diff --git a/tests/ImageSharp.Tests/Formats/Pbm/PbmEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Pbm/PbmEncoderTests.cs index 2ca49a39d..e9b496ce4 100644 --- a/tests/ImageSharp.Tests/Formats/Pbm/PbmEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Pbm/PbmEncoderTests.cs @@ -72,7 +72,13 @@ namespace SixLabors.ImageSharp.Tests.Formats.Pbm using (var memStream = new MemoryStream()) { input.Save(memStream, options); - memStream.Position = 0; + + // EOF indicator for plain is a Space. + memStream.Seek(-1, SeekOrigin.End); + int lastByte = memStream.ReadByte(); + Assert.Equal(0x20, lastByte); + + memStream.Seek(0, SeekOrigin.Begin); using (var output = Image.Load(memStream)) { PbmMetadata meta = output.Metadata.GetPbmMetadata(); From b2bc25c89f2d825a9c4a7d8c38cfade34a93e890 Mon Sep 17 00:00:00 2001 From: Ynse Hoornenborg Date: Fri, 10 Dec 2021 13:49:55 +0100 Subject: [PATCH 54/65] No need to await async PbmDecoder methods --- src/ImageSharp/Formats/Pbm/PbmDecoder.cs | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/ImageSharp/Formats/Pbm/PbmDecoder.cs b/src/ImageSharp/Formats/Pbm/PbmDecoder.cs index 62cef176d..c00e4affe 100644 --- a/src/ImageSharp/Formats/Pbm/PbmDecoder.cs +++ b/src/ImageSharp/Formats/Pbm/PbmDecoder.cs @@ -54,9 +54,8 @@ namespace SixLabors.ImageSharp.Formats.Pbm } /// - public async Task DecodeAsync(Configuration configuration, Stream stream, CancellationToken cancellationToken) - => await this.DecodeAsync(configuration, stream, cancellationToken) - .ConfigureAwait(false); + public Task DecodeAsync(Configuration configuration, Stream stream, CancellationToken cancellationToken) + => this.DecodeAsync(configuration, stream, cancellationToken); /// public IImageInfo Identify(Configuration configuration, Stream stream) @@ -68,16 +67,12 @@ namespace SixLabors.ImageSharp.Formats.Pbm } /// - public async Task IdentifyAsync(Configuration configuration, Stream stream, CancellationToken cancellationToken) + public Task IdentifyAsync(Configuration configuration, Stream stream, CancellationToken cancellationToken) { Guard.NotNull(stream, nameof(stream)); - // The introduction of a local variable that refers to an object the implements - // IDisposable means you must use async/await, where the compiler generates the - // state machine and a continuation. var decoder = new PbmDecoderCore(configuration); - return await decoder.IdentifyAsync(configuration, stream, cancellationToken) - .ConfigureAwait(false); + return decoder.IdentifyAsync(configuration, stream, cancellationToken); } } } From efece702028311256169fd15196225fa172c8596 Mon Sep 17 00:00:00 2001 From: Ynse Hoornenborg Date: Fri, 10 Dec 2021 14:05:59 +0100 Subject: [PATCH 55/65] Partial revert of b2bc25c --- src/ImageSharp/Formats/Pbm/PbmDecoder.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/ImageSharp/Formats/Pbm/PbmDecoder.cs b/src/ImageSharp/Formats/Pbm/PbmDecoder.cs index c00e4affe..2eebbb1d9 100644 --- a/src/ImageSharp/Formats/Pbm/PbmDecoder.cs +++ b/src/ImageSharp/Formats/Pbm/PbmDecoder.cs @@ -54,8 +54,9 @@ namespace SixLabors.ImageSharp.Formats.Pbm } /// - public Task DecodeAsync(Configuration configuration, Stream stream, CancellationToken cancellationToken) - => this.DecodeAsync(configuration, stream, cancellationToken); + public async Task DecodeAsync(Configuration configuration, Stream stream, CancellationToken cancellationToken) + => await this.DecodeAsync(configuration, stream, cancellationToken) + .ConfigureAwait(false); /// public IImageInfo Identify(Configuration configuration, Stream stream) From 3730a0259ad12432277e82e62d77cc799dee18f3 Mon Sep 17 00:00:00 2001 From: Ynse Hoornenborg Date: Fri, 10 Dec 2021 14:34:51 +0100 Subject: [PATCH 56/65] Fix build after merge --- src/ImageSharp/Formats/Pbm/BinaryDecoder.cs | 10 +++++----- src/ImageSharp/Formats/Pbm/BinaryEncoder.cs | 15 ++++++++++----- src/ImageSharp/Formats/Pbm/PlainDecoder.cs | 10 +++++----- src/ImageSharp/Formats/Pbm/PlainEncoder.cs | 15 ++++++++++----- .../ImageComparison/ImageComparingUtils.cs | 4 ++-- 5 files changed, 32 insertions(+), 22 deletions(-) diff --git a/src/ImageSharp/Formats/Pbm/BinaryDecoder.cs b/src/ImageSharp/Formats/Pbm/BinaryDecoder.cs index a469ced8a..33af30434 100644 --- a/src/ImageSharp/Formats/Pbm/BinaryDecoder.cs +++ b/src/ImageSharp/Formats/Pbm/BinaryDecoder.cs @@ -73,7 +73,7 @@ namespace SixLabors.ImageSharp.Formats.Pbm for (int y = 0; y < height; y++) { stream.Read(rowSpan); - Span pixelSpan = pixels.GetRowSpan(y); + Span pixelSpan = pixels.DangerousGetRowSpan(y); PixelOperations.Instance.FromL8Bytes( configuration, rowSpan, @@ -95,7 +95,7 @@ namespace SixLabors.ImageSharp.Formats.Pbm for (int y = 0; y < height; y++) { stream.Read(rowSpan); - Span pixelSpan = pixels.GetRowSpan(y); + Span pixelSpan = pixels.DangerousGetRowSpan(y); PixelOperations.Instance.FromL16Bytes( configuration, rowSpan, @@ -117,7 +117,7 @@ namespace SixLabors.ImageSharp.Formats.Pbm for (int y = 0; y < height; y++) { stream.Read(rowSpan); - Span pixelSpan = pixels.GetRowSpan(y); + Span pixelSpan = pixels.DangerousGetRowSpan(y); PixelOperations.Instance.FromRgb24Bytes( configuration, rowSpan, @@ -139,7 +139,7 @@ namespace SixLabors.ImageSharp.Formats.Pbm for (int y = 0; y < height; y++) { stream.Read(rowSpan); - Span pixelSpan = pixels.GetRowSpan(y); + Span pixelSpan = pixels.DangerousGetRowSpan(y); PixelOperations.Instance.FromRgb48Bytes( configuration, rowSpan, @@ -183,7 +183,7 @@ namespace SixLabors.ImageSharp.Formats.Pbm } } - Span pixelSpan = pixels.GetRowSpan(y); + Span pixelSpan = pixels.DangerousGetRowSpan(y); PixelOperations.Instance.FromL8( configuration, rowSpan, diff --git a/src/ImageSharp/Formats/Pbm/BinaryEncoder.cs b/src/ImageSharp/Formats/Pbm/BinaryEncoder.cs index 8b32c18c2..332ab9b50 100644 --- a/src/ImageSharp/Formats/Pbm/BinaryEncoder.cs +++ b/src/ImageSharp/Formats/Pbm/BinaryEncoder.cs @@ -62,13 +62,14 @@ namespace SixLabors.ImageSharp.Formats.Pbm { int width = image.Width; int height = image.Height; + Buffer2D pixelBuffer = image.PixelBuffer; MemoryAllocator allocator = configuration.MemoryAllocator; using IMemoryOwner row = allocator.Allocate(width); Span rowSpan = row.GetSpan(); for (int y = 0; y < height; y++) { - Span pixelSpan = image.GetPixelRowSpan(y); + Span pixelSpan = pixelBuffer.DangerousGetRowSpan(y); PixelOperations.Instance.ToL8Bytes( configuration, @@ -86,13 +87,14 @@ namespace SixLabors.ImageSharp.Formats.Pbm const int bytesPerPixel = 2; int width = image.Width; int height = image.Height; + Buffer2D pixelBuffer = image.PixelBuffer; MemoryAllocator allocator = configuration.MemoryAllocator; using IMemoryOwner row = allocator.Allocate(width * bytesPerPixel); Span rowSpan = row.GetSpan(); for (int y = 0; y < height; y++) { - Span pixelSpan = image.GetPixelRowSpan(y); + Span pixelSpan = pixelBuffer.DangerousGetRowSpan(y); PixelOperations.Instance.ToL16Bytes( configuration, @@ -110,13 +112,14 @@ namespace SixLabors.ImageSharp.Formats.Pbm const int bytesPerPixel = 3; int width = image.Width; int height = image.Height; + Buffer2D pixelBuffer = image.PixelBuffer; MemoryAllocator allocator = configuration.MemoryAllocator; using IMemoryOwner row = allocator.Allocate(width * bytesPerPixel); Span rowSpan = row.GetSpan(); for (int y = 0; y < height; y++) { - Span pixelSpan = image.GetPixelRowSpan(y); + Span pixelSpan = pixelBuffer.DangerousGetRowSpan(y); PixelOperations.Instance.ToRgb24Bytes( configuration, @@ -134,13 +137,14 @@ namespace SixLabors.ImageSharp.Formats.Pbm const int bytesPerPixel = 6; int width = image.Width; int height = image.Height; + Buffer2D pixelBuffer = image.PixelBuffer; MemoryAllocator allocator = configuration.MemoryAllocator; using IMemoryOwner row = allocator.Allocate(width * bytesPerPixel); Span rowSpan = row.GetSpan(); for (int y = 0; y < height; y++) { - Span pixelSpan = image.GetPixelRowSpan(y); + Span pixelSpan = pixelBuffer.DangerousGetRowSpan(y); PixelOperations.Instance.ToRgb48Bytes( configuration, @@ -157,6 +161,7 @@ namespace SixLabors.ImageSharp.Formats.Pbm { int width = image.Width; int height = image.Height; + Buffer2D pixelBuffer = image.PixelBuffer; MemoryAllocator allocator = configuration.MemoryAllocator; using IMemoryOwner row = allocator.Allocate(width); Span rowSpan = row.GetSpan(); @@ -165,7 +170,7 @@ namespace SixLabors.ImageSharp.Formats.Pbm int startBit = 0; for (int y = 0; y < height; y++) { - Span pixelSpan = image.GetPixelRowSpan(y); + Span pixelSpan = pixelBuffer.DangerousGetRowSpan(y); PixelOperations.Instance.ToL8( configuration, diff --git a/src/ImageSharp/Formats/Pbm/PlainDecoder.cs b/src/ImageSharp/Formats/Pbm/PlainDecoder.cs index a9e90d788..aeb527dd2 100644 --- a/src/ImageSharp/Formats/Pbm/PlainDecoder.cs +++ b/src/ImageSharp/Formats/Pbm/PlainDecoder.cs @@ -75,7 +75,7 @@ namespace SixLabors.ImageSharp.Formats.Pbm rowSpan[x] = new L8(value); } - Span pixelSpan = pixels.GetRowSpan(y); + Span pixelSpan = pixels.DangerousGetRowSpan(y); PixelOperations.Instance.FromL8( configuration, rowSpan, @@ -101,7 +101,7 @@ namespace SixLabors.ImageSharp.Formats.Pbm rowSpan[x] = new L16(value); } - Span pixelSpan = pixels.GetRowSpan(y); + Span pixelSpan = pixels.DangerousGetRowSpan(y); PixelOperations.Instance.FromL16( configuration, rowSpan, @@ -131,7 +131,7 @@ namespace SixLabors.ImageSharp.Formats.Pbm rowSpan[x] = new Rgb24(red, green, blue); } - Span pixelSpan = pixels.GetRowSpan(y); + Span pixelSpan = pixels.DangerousGetRowSpan(y); PixelOperations.Instance.FromRgb24( configuration, rowSpan, @@ -161,7 +161,7 @@ namespace SixLabors.ImageSharp.Formats.Pbm rowSpan[x] = new Rgb48(red, green, blue); } - Span pixelSpan = pixels.GetRowSpan(y); + Span pixelSpan = pixels.DangerousGetRowSpan(y); PixelOperations.Instance.FromRgb48( configuration, rowSpan, @@ -187,7 +187,7 @@ namespace SixLabors.ImageSharp.Formats.Pbm rowSpan[x] = value == 0 ? White : Black; } - Span pixelSpan = pixels.GetRowSpan(y); + Span pixelSpan = pixels.DangerousGetRowSpan(y); PixelOperations.Instance.FromL8( configuration, rowSpan, diff --git a/src/ImageSharp/Formats/Pbm/PlainEncoder.cs b/src/ImageSharp/Formats/Pbm/PlainEncoder.cs index 2868922ea..a64ae38a7 100644 --- a/src/ImageSharp/Formats/Pbm/PlainEncoder.cs +++ b/src/ImageSharp/Formats/Pbm/PlainEncoder.cs @@ -76,6 +76,7 @@ namespace SixLabors.ImageSharp.Formats.Pbm { int width = image.Width; int height = image.Height; + Buffer2D pixelBuffer = image.PixelBuffer; MemoryAllocator allocator = configuration.MemoryAllocator; using IMemoryOwner row = allocator.Allocate(width); Span rowSpan = row.GetSpan(); @@ -84,7 +85,7 @@ namespace SixLabors.ImageSharp.Formats.Pbm for (int y = 0; y < height; y++) { - Span pixelSpan = image.GetPixelRowSpan(y); + Span pixelSpan = pixelBuffer.DangerousGetRowSpan(y); PixelOperations.Instance.ToL8( configuration, pixelSpan, @@ -108,6 +109,7 @@ namespace SixLabors.ImageSharp.Formats.Pbm { int width = image.Width; int height = image.Height; + Buffer2D pixelBuffer = image.PixelBuffer; MemoryAllocator allocator = configuration.MemoryAllocator; using IMemoryOwner row = allocator.Allocate(width); Span rowSpan = row.GetSpan(); @@ -116,7 +118,7 @@ namespace SixLabors.ImageSharp.Formats.Pbm for (int y = 0; y < height; y++) { - Span pixelSpan = image.GetPixelRowSpan(y); + Span pixelSpan = pixelBuffer.DangerousGetRowSpan(y); PixelOperations.Instance.ToL16( configuration, pixelSpan, @@ -140,6 +142,7 @@ namespace SixLabors.ImageSharp.Formats.Pbm { int width = image.Width; int height = image.Height; + Buffer2D pixelBuffer = image.PixelBuffer; MemoryAllocator allocator = configuration.MemoryAllocator; using IMemoryOwner row = allocator.Allocate(width); Span rowSpan = row.GetSpan(); @@ -148,7 +151,7 @@ namespace SixLabors.ImageSharp.Formats.Pbm for (int y = 0; y < height; y++) { - Span pixelSpan = image.GetPixelRowSpan(y); + Span pixelSpan = pixelBuffer.DangerousGetRowSpan(y); PixelOperations.Instance.ToRgb24( configuration, pixelSpan, @@ -178,6 +181,7 @@ namespace SixLabors.ImageSharp.Formats.Pbm { int width = image.Width; int height = image.Height; + Buffer2D pixelBuffer = image.PixelBuffer; MemoryAllocator allocator = configuration.MemoryAllocator; using IMemoryOwner row = allocator.Allocate(width); Span rowSpan = row.GetSpan(); @@ -186,7 +190,7 @@ namespace SixLabors.ImageSharp.Formats.Pbm for (int y = 0; y < height; y++) { - Span pixelSpan = image.GetPixelRowSpan(y); + Span pixelSpan = pixelBuffer.DangerousGetRowSpan(y); PixelOperations.Instance.ToRgb48( configuration, pixelSpan, @@ -216,6 +220,7 @@ namespace SixLabors.ImageSharp.Formats.Pbm { int width = image.Width; int height = image.Height; + Buffer2D pixelBuffer = image.PixelBuffer; MemoryAllocator allocator = configuration.MemoryAllocator; using IMemoryOwner row = allocator.Allocate(width); Span rowSpan = row.GetSpan(); @@ -224,7 +229,7 @@ namespace SixLabors.ImageSharp.Formats.Pbm for (int y = 0; y < height; y++) { - Span pixelSpan = image.GetPixelRowSpan(y); + Span pixelSpan = pixelBuffer.DangerousGetRowSpan(y); PixelOperations.Instance.ToL8( configuration, pixelSpan, diff --git a/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ImageComparingUtils.cs b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ImageComparingUtils.cs index 4de1b9a19..1801d6b59 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ImageComparingUtils.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ImageComparingUtils.cs @@ -8,9 +8,9 @@ using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison; using Xunit; -namespace SixLabors.ImageSharp.Tests.Formats.Tga +namespace SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison { - public static class TgaTestUtils + public static class ImageComparingUtils { public static void CompareWithReferenceDecoder( TestImageProvider provider, From 364bbbb5f79038848d78b13b07ee7e56d6619c36 Mon Sep 17 00:00:00 2001 From: Dmitry Pentin Date: Sat, 11 Dec 2021 09:33:37 +0300 Subject: [PATCH 57/65] Fixed old runtimes remote executor tests --- shared-infrastructure | 2 +- .../Formats/Jpg/JpegColorConverterTests.cs | 20 ++++++++++++------- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/shared-infrastructure b/shared-infrastructure index a042aba17..59ce17f5a 160000 --- a/shared-infrastructure +++ b/shared-infrastructure @@ -1 +1 @@ -Subproject commit a042aba176cdb840d800c6ed4cfe41a54fb7b1e3 +Subproject commit 59ce17f5a4e1f956811133f41add7638e74c2836 diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs index f1e3684de..a5414ba1d 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs @@ -24,12 +24,18 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg private const int TestBufferLength = 40; - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new(epsilon: Precision); +#if SUPPORTS_RUNTIME_INTRINSICS + private static readonly HwIntrinsics IntrinsicsConfig = HwIntrinsics.AllowAll | HwIntrinsics.DisableAVX; +#else + private static readonly HwIntrinsics IntrinsicsConfig = HwIntrinsics.AllowAll; +#endif - public static readonly TheoryData Seeds = new() { 1, 2, 3 }; + private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new(epsilon: Precision); private static readonly ColorSpaceConverter ColorSpaceConverter = new(); + public static readonly TheoryData Seeds = new() { 1, 2, 3 }; + public JpegColorConverterTests(ITestOutputHelper output) { this.Output = output; @@ -107,7 +113,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg FeatureTestRunner.RunWithHwIntrinsicsFeature( RunTest, seed, - HwIntrinsics.AllowAll | HwIntrinsics.DisableAVX); + IntrinsicsConfig); static void RunTest(string arg) => ValidateConversion( @@ -144,7 +150,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg FeatureTestRunner.RunWithHwIntrinsicsFeature( RunTest, seed, - HwIntrinsics.AllowAll | HwIntrinsics.DisableAVX); + IntrinsicsConfig); static void RunTest(string arg) => ValidateConversion( @@ -181,7 +187,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg FeatureTestRunner.RunWithHwIntrinsicsFeature( RunTest, seed, - HwIntrinsics.AllowAll | HwIntrinsics.DisableAVX); + IntrinsicsConfig); static void RunTest(string arg) => ValidateConversion( @@ -218,7 +224,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg FeatureTestRunner.RunWithHwIntrinsicsFeature( RunTest, seed, - HwIntrinsics.AllowAll | HwIntrinsics.DisableAVX); + IntrinsicsConfig); static void RunTest(string arg) => ValidateConversion( @@ -255,7 +261,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg FeatureTestRunner.RunWithHwIntrinsicsFeature( RunTest, seed, - HwIntrinsics.AllowAll | HwIntrinsics.DisableAVX); + IntrinsicsConfig); static void RunTest(string arg) => ValidateConversion( From 7a9357c1166d401377293d905c5a5a9e02d3269c Mon Sep 17 00:00:00 2001 From: Dmitry Pentin Date: Sat, 11 Dec 2021 09:36:51 +0300 Subject: [PATCH 58/65] Small qol fixes --- .../Formats/Jpg/JpegColorConverterTests.cs | 50 ++++++++----------- 1 file changed, 21 insertions(+), 29 deletions(-) diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs index a5414ba1d..91f87610e 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs @@ -18,7 +18,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg [Trait("Format", "Jpg")] public class JpegColorConverterTests { - private static readonly float MaxColorChannelValue = 255f; + private const float MaxColorChannelValue = 255f; private const float Precision = 0.1F / 255; @@ -122,13 +122,6 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg FeatureTestRunner.Deserialize(arg)); } -#if SUPPORTS_RUNTIME_INTRINSICS - [Theory] - [MemberData(nameof(Seeds))] - public void FromYCbCrAvx2(int seed) => - this.TestConverter(new JpegColorConverterBase.FromYCbCrAvx(8), 3, seed); -#endif - [Theory] [MemberData(nameof(Seeds))] public void FromCmykBasic(int seed) => @@ -159,13 +152,6 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg FeatureTestRunner.Deserialize(arg)); } -#if SUPPORTS_RUNTIME_INTRINSICS - [Theory] - [MemberData(nameof(Seeds))] - public void FromCmykAvx2(int seed) => - this.TestConverter(new JpegColorConverterBase.FromCmykAvx(8), 4, seed); -#endif - [Theory] [MemberData(nameof(Seeds))] public void FromGrayscaleBasic(int seed) => @@ -196,13 +182,6 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg FeatureTestRunner.Deserialize(arg)); } -#if SUPPORTS_RUNTIME_INTRINSICS - [Theory] - [MemberData(nameof(Seeds))] - public void FromGrayscaleAvx2(int seed) => - this.TestConverter(new JpegColorConverterBase.FromGrayscaleAvx(8), 1, seed); -#endif - [Theory] [MemberData(nameof(Seeds))] public void FromRgbBasic(int seed) => @@ -233,13 +212,6 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg FeatureTestRunner.Deserialize(arg)); } -#if SUPPORTS_RUNTIME_INTRINSICS - [Theory] - [MemberData(nameof(Seeds))] - public void FromRgbAvx2(int seed) => - this.TestConverter(new JpegColorConverterBase.FromRgbAvx(8), 3, seed); -#endif - [Theory] [MemberData(nameof(Seeds))] public void FromYccKBasic(int seed) => @@ -271,6 +243,26 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg } #if SUPPORTS_RUNTIME_INTRINSICS + [Theory] + [MemberData(nameof(Seeds))] + public void FromYCbCrAvx2(int seed) => + this.TestConverter(new JpegColorConverterBase.FromYCbCrAvx(8), 3, seed); + + [Theory] + [MemberData(nameof(Seeds))] + public void FromCmykAvx2(int seed) => + this.TestConverter(new JpegColorConverterBase.FromCmykAvx(8), 4, seed); + + [Theory] + [MemberData(nameof(Seeds))] + public void FromGrayscaleAvx2(int seed) => + this.TestConverter(new JpegColorConverterBase.FromGrayscaleAvx(8), 1, seed); + + [Theory] + [MemberData(nameof(Seeds))] + public void FromRgbAvx2(int seed) => + this.TestConverter(new JpegColorConverterBase.FromRgbAvx(8), 3, seed); + [Theory] [MemberData(nameof(Seeds))] public void FromYccKAvx2(int seed) => From 816c754657acfea4d6f8a381da0a714819d82716 Mon Sep 17 00:00:00 2001 From: Dmitry Pentin Date: Sat, 11 Dec 2021 09:38:00 +0300 Subject: [PATCH 59/65] Removed obsolete Vector4Pair --- src/ImageSharp/Common/Tuples/Vector4Pair.cs | 82 --------------------- 1 file changed, 82 deletions(-) delete mode 100644 src/ImageSharp/Common/Tuples/Vector4Pair.cs diff --git a/src/ImageSharp/Common/Tuples/Vector4Pair.cs b/src/ImageSharp/Common/Tuples/Vector4Pair.cs deleted file mode 100644 index 6294a6177..000000000 --- a/src/ImageSharp/Common/Tuples/Vector4Pair.cs +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Apache License, Version 2.0. - -using System.Numerics; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -namespace SixLabors.ImageSharp.Tuples -{ - /// - /// Its faster to process multiple Vector4-s together, so let's pair them! - /// On AVX2 this pair should be convertible to of ! - /// TODO: Investigate defining this as union with an Octet.OfSingle type. - /// - [StructLayout(LayoutKind.Sequential)] - internal struct Vector4Pair - { - public Vector4 A; - - public Vector4 B; - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void MultiplyInplace(float value) - { - this.A *= value; - this.B *= value; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void AddInplace(Vector4 value) - { - this.A += value; - this.B += value; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void AddInplace(ref Vector4Pair other) - { - this.A += other.A; - this.B += other.B; - } - - /// . - /// Downscale method, specific to Jpeg color conversion. Works only if Vector{float}.Count == 4! /// TODO: Move it somewhere else. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void RoundAndDownscalePreVector8(float downscaleFactor) - { - ref Vector a = ref Unsafe.As>(ref this.A); - a = a.FastRound(); - - ref Vector b = ref Unsafe.As>(ref this.B); - b = b.FastRound(); - - // Downscale by 1/factor - var scale = new Vector4(1 / downscaleFactor); - this.A *= scale; - this.B *= scale; - } - - /// - /// AVX2-only Downscale method, specific to Jpeg color conversion. - /// TODO: Move it somewhere else. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void RoundAndDownscaleVector8(float downscaleFactor) - { - ref Vector self = ref Unsafe.As>(ref this); - Vector v = self; - v = v.FastRound(); - - // Downscale by 1/factor - v *= new Vector(1 / downscaleFactor); - self = v; - } - - public override string ToString() - { - return $"{nameof(Vector4Pair)}({this.A}, {this.B})"; - } - } -} From 21cf5b42c17e59147db51abeaa7b90672d69d339 Mon Sep 17 00:00:00 2001 From: Dmitry Pentin Date: Sat, 11 Dec 2021 09:56:49 +0300 Subject: [PATCH 60/65] Fixed merging errors --- .../ColorConverters/JpegColorConverterBase.cs | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterBase.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterBase.cs index 5537113a3..808ca687b 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterBase.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterBase.cs @@ -206,12 +206,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters this.ComponentCount = componentBuffers.Count; - this.Component0 = componentBuffers[0].GetRowSpan(row); + this.Component0 = componentBuffers[0].DangerousGetRowSpan(row); // In case of grayscale, Component1 and Component2 point to Component0 memory area - this.Component1 = this.ComponentCount > 1 ? componentBuffers[1].GetRowSpan(row) : this.Component0; - this.Component2 = this.ComponentCount > 2 ? componentBuffers[2].GetRowSpan(row) : this.Component0; - this.Component3 = this.ComponentCount > 3 ? componentBuffers[3].GetRowSpan(row) : Span.Empty; + this.Component1 = this.ComponentCount > 1 ? componentBuffers[1].DangerousGetRowSpan(row) : this.Component0; + this.Component2 = this.ComponentCount > 2 ? componentBuffers[2].DangerousGetRowSpan(row) : this.Component0; + this.Component3 = this.ComponentCount > 3 ? componentBuffers[3].DangerousGetRowSpan(row) : Span.Empty; } /// @@ -223,12 +223,14 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { DebugGuard.MustBeGreaterThan(processors.Count, 0, nameof(processors)); - this.Component0 = componentBuffers[0].DangerousGetRowSpan(row); + this.ComponentCount = processors.Count; + + this.Component0 = processors[0].GetColorBufferRowSpan(row); // In case of grayscale, Component1 and Component2 point to Component0 memory area - this.Component1 = this.ComponentCount > 1 ? componentBuffers[1].DangerousGetRowSpan(row) : this.Component0; - this.Component2 = this.ComponentCount > 2 ? componentBuffers[2].DangerousGetRowSpan(row) : this.Component0; - this.Component3 = this.ComponentCount > 3 ? componentBuffers[3].DangerousGetRowSpan(row) : Span.Empty; + this.Component1 = this.ComponentCount > 1 ? processors[1].GetColorBufferRowSpan(row) : this.Component0; + this.Component2 = this.ComponentCount > 2 ? processors[2].GetColorBufferRowSpan(row) : this.Component0; + this.Component3 = this.ComponentCount > 3 ? processors[3].GetColorBufferRowSpan(row) : Span.Empty; } internal ComponentValues( From 94735822f597bd2289da9d36560ade86d8d51ce0 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Sat, 11 Dec 2021 15:56:33 +0100 Subject: [PATCH 61/65] Add ActiveIssue attribute to AllocateSingleMemoryOwner_Finalization_ReturnsToPool --- .../Allocators/UniformUnmanagedPoolMemoryAllocatorTests.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/ImageSharp.Tests/Memory/Allocators/UniformUnmanagedPoolMemoryAllocatorTests.cs b/tests/ImageSharp.Tests/Memory/Allocators/UniformUnmanagedPoolMemoryAllocatorTests.cs index 80c8cc6a0..c4bb03d02 100644 --- a/tests/ImageSharp.Tests/Memory/Allocators/UniformUnmanagedPoolMemoryAllocatorTests.cs +++ b/tests/ImageSharp.Tests/Memory/Allocators/UniformUnmanagedPoolMemoryAllocatorTests.cs @@ -1,4 +1,4 @@ -// Copyright (c) Six Labors. +// Copyright (c) Six Labors. // Licensed under the Apache License, Version 2.0. using System; @@ -310,6 +310,7 @@ namespace SixLabors.ImageSharp.Tests.Memory.Allocators } } + [ActiveIssue("https://github.com/SixLabors/ImageSharp/issues/1887", TestPlatforms.OSX)] [Theory] [InlineData(300)] // Group of single SharedArrayPoolBuffer [InlineData(600)] // Group of single UniformUnmanagedMemoryPool buffer From 36105c902d5aef3ba6f60e11b2e8c26daf0c4117 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sun, 12 Dec 2021 23:39:41 +1100 Subject: [PATCH 62/65] Remove netstandard 1.3 target --- README.md | 2 +- .../Tiff/Compression/Compressors/DeflateCompressor.cs | 7 ------- src/ImageSharp/ImageSharp.csproj | 6 +++--- 3 files changed, 4 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index ab16bbb76..fdf14b496 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ ImageSharp is a new, fully featured, fully managed, cross-platform, 2D graphics ImageSharp is designed from the ground up to be flexible and extensible. The library provides API endpoints for common image processing operations and the building blocks to allow for the development of additional operations. -Built against [.NET Standard 1.3](https://docs.microsoft.com/en-us/dotnet/standard/net-standard), ImageSharp can be used in device, cloud, and embedded/IoT scenarios. +Built against [.NET Standard 2.0](https://docs.microsoft.com/en-us/dotnet/standard/net-standard), ImageSharp can be used in device, cloud, and embedded/IoT scenarios. ## License diff --git a/src/ImageSharp/Formats/Tiff/Compression/Compressors/DeflateCompressor.cs b/src/ImageSharp/Formats/Tiff/Compression/Compressors/DeflateCompressor.cs index 225036f90..c240c06ef 100644 --- a/src/ImageSharp/Formats/Tiff/Compression/Compressors/DeflateCompressor.cs +++ b/src/ImageSharp/Formats/Tiff/Compression/Compressors/DeflateCompressor.cs @@ -43,15 +43,8 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Compressors } int size = (int)this.memoryStream.Position; - -#if !NETSTANDARD1_3 byte[] buffer = this.memoryStream.GetBuffer(); this.Output.Write(buffer, 0, size); -#else - this.memoryStream.SetLength(size); - this.memoryStream.Position = 0; - this.memoryStream.CopyTo(this.Output); -#endif } /// diff --git a/src/ImageSharp/ImageSharp.csproj b/src/ImageSharp/ImageSharp.csproj index afe10b1f9..0a75c06db 100644 --- a/src/ImageSharp/ImageSharp.csproj +++ b/src/ImageSharp/ImageSharp.csproj @@ -23,12 +23,12 @@ - net6.0;net5.0;netcoreapp3.1;netcoreapp2.1;netstandard2.1;netstandard2.0;netstandard1.3;net472 + net6.0;net5.0;netcoreapp3.1;netcoreapp2.1;netstandard2.1;netstandard2.0;net472 - net5.0;netcoreapp3.1;netcoreapp2.1;netstandard2.1;netstandard2.0;netstandard1.3;net472 + net5.0;netcoreapp3.1;netcoreapp2.1;netstandard2.1;netstandard2.0;net472 @@ -38,7 +38,7 @@ - netcoreapp3.1;netcoreapp2.1;netstandard2.1;netstandard2.0;netstandard1.3;net472 + netcoreapp3.1;netcoreapp2.1;netstandard2.1;netstandard2.0;net472 From d7ff98b19b08640c3c4e8dccc858ce397c4d3f26 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Sun, 12 Dec 2021 14:29:12 +0100 Subject: [PATCH 63/65] Add ActiveIssue attribute to AllocateMemoryGroup_Finalization_ReturnsToPool test --- .../Allocators/UniformUnmanagedPoolMemoryAllocatorTests.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/ImageSharp.Tests/Memory/Allocators/UniformUnmanagedPoolMemoryAllocatorTests.cs b/tests/ImageSharp.Tests/Memory/Allocators/UniformUnmanagedPoolMemoryAllocatorTests.cs index c4bb03d02..13bf98b50 100644 --- a/tests/ImageSharp.Tests/Memory/Allocators/UniformUnmanagedPoolMemoryAllocatorTests.cs +++ b/tests/ImageSharp.Tests/Memory/Allocators/UniformUnmanagedPoolMemoryAllocatorTests.cs @@ -253,6 +253,7 @@ namespace SixLabors.ImageSharp.Tests.Memory.Allocators } } + [ActiveIssue("https://github.com/SixLabors/ImageSharp/issues/1887", TestPlatforms.OSX)] [Theory] [InlineData(300)] // Group of single SharedArrayPoolBuffer [InlineData(600)] // Group of single UniformUnmanagedMemoryPool buffer From bae4feef1b915a65bec3fb8542a349c9bced454b Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Sun, 12 Dec 2021 14:51:31 +0100 Subject: [PATCH 64/65] Change skipping tests on OSX --- .../UniformUnmanagedPoolMemoryAllocatorTests.cs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/tests/ImageSharp.Tests/Memory/Allocators/UniformUnmanagedPoolMemoryAllocatorTests.cs b/tests/ImageSharp.Tests/Memory/Allocators/UniformUnmanagedPoolMemoryAllocatorTests.cs index 13bf98b50..45a7cc278 100644 --- a/tests/ImageSharp.Tests/Memory/Allocators/UniformUnmanagedPoolMemoryAllocatorTests.cs +++ b/tests/ImageSharp.Tests/Memory/Allocators/UniformUnmanagedPoolMemoryAllocatorTests.cs @@ -253,13 +253,18 @@ namespace SixLabors.ImageSharp.Tests.Memory.Allocators } } - [ActiveIssue("https://github.com/SixLabors/ImageSharp/issues/1887", TestPlatforms.OSX)] [Theory] [InlineData(300)] // Group of single SharedArrayPoolBuffer [InlineData(600)] // Group of single UniformUnmanagedMemoryPool buffer [InlineData(1200)] // Group of two UniformUnmanagedMemoryPool buffers public void AllocateMemoryGroup_Finalization_ReturnsToPool(int length) { + if (TestEnvironment.IsOSX) + { + // Skip on OSX: https://github.com/SixLabors/ImageSharp/issues/1887 + return; + } + if (!TestEnvironment.RunsOnCI) { // This may fail in local runs resulting in high memory load. @@ -311,12 +316,17 @@ namespace SixLabors.ImageSharp.Tests.Memory.Allocators } } - [ActiveIssue("https://github.com/SixLabors/ImageSharp/issues/1887", TestPlatforms.OSX)] [Theory] [InlineData(300)] // Group of single SharedArrayPoolBuffer [InlineData(600)] // Group of single UniformUnmanagedMemoryPool buffer public void AllocateSingleMemoryOwner_Finalization_ReturnsToPool(int length) { + if (TestEnvironment.IsOSX) + { + // Skip on OSX: https://github.com/SixLabors/ImageSharp/issues/1887 + return; + } + if (!TestEnvironment.RunsOnCI) { // This may fail in local runs resulting in high memory load. From 1afcb4cd84b072316c287fc1dc216bc23c097835 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 13 Dec 2021 09:53:44 +1100 Subject: [PATCH 65/65] Update Guard.cs --- src/ImageSharp/Common/Helpers/Guard.cs | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/ImageSharp/Common/Helpers/Guard.cs b/src/ImageSharp/Common/Helpers/Guard.cs index 0b5cc21cb..0f6efcb3c 100644 --- a/src/ImageSharp/Common/Helpers/Guard.cs +++ b/src/ImageSharp/Common/Helpers/Guard.cs @@ -2,9 +2,6 @@ // Licensed under the Apache License, Version 2.0. using System; -#if NETSTANDARD1_3 -using System.Reflection; -#endif using System.Runtime.CompilerServices; using SixLabors.ImageSharp; @@ -22,11 +19,7 @@ namespace SixLabors [MethodImpl(InliningOptions.ShortMethod)] public static void MustBeValueType(TValue value, string parameterName) { - if (value.GetType() -#if NETSTANDARD1_3 - .GetTypeInfo() -#endif - .IsValueType) + if (value.GetType().IsValueType) { return; }