From 065cb1ca459362fe1aaa6bb8e1afad4491c8515f Mon Sep 17 00:00:00 2001 From: Ynse Hoornenborg Date: Wed, 17 Nov 2021 20:34:26 +0100 Subject: [PATCH 01/29] 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 6ad20713d1..800b693260 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 8f0b4a86f2..4d7af89a58 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 1a470fa31f..a141a58b07 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 471287006f..c560b1b78f 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/29] 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 6ad20713d1..800b693260 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 8f0b4a86f2..4d7af89a58 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 1a470fa31f..a141a58b07 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 471287006f..c560b1b78f 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/29] 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 3961cc6c57..e41e38f7fa 100644 --- a/src/ImageSharp/Advanced/AotCompilerTools.cs +++ b/src/ImageSharp/Advanced/AotCompilerTools.cs @@ -10,6 +10,7 @@ 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 @@ private static void AotCompileImageEncoderInternals() 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 @@ private static void AotCompileImageDecoderInternals() 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 @@ private static void AotCompileImageEncoders() AotCompileImageEncoder(); AotCompileImageEncoder(); AotCompileImageEncoder(); + AotCompileImageEncoder(); AotCompileImageEncoder(); AotCompileImageEncoder(); AotCompileImageEncoder(); @@ -251,6 +255,7 @@ private static void AotCompileImageDecoders() AotCompileImageDecoder(); AotCompileImageDecoder(); AotCompileImageDecoder(); + AotCompileImageDecoder(); AotCompileImageDecoder(); AotCompileImageDecoder(); AotCompileImageDecoder(); diff --git a/src/ImageSharp/Configuration.cs b/src/ImageSharp/Configuration.cs index ea9524827f..4b7333de07 100644 --- a/src/ImageSharp/Configuration.cs +++ b/src/ImageSharp/Configuration.cs @@ -8,6 +8,7 @@ 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 @@ public void Configure(IConfigurationModule configuration) /// /// /// . + /// . /// . /// . /// . @@ -188,6 +190,7 @@ public void Configure(IConfigurationModule configuration) 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 c5237f2bc7..a6a65aef62 100644 --- a/src/ImageSharp/Formats/ImageExtensions.Save.cs +++ b/src/ImageSharp/Formats/ImageExtensions.Save.cs @@ -10,6 +10,7 @@ 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 @@ public static Task SaveAsJpegAsync(this Image source, Stream stream, JpegEncoder 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 874f3ab0dc..c4a00b37cb 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 0000000000..1c86b2bd85 --- /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 0000000000..1233c87fcb --- /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 0000000000..054731b483 --- /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 0000000000..c5c409ec8c --- /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 0000000000..cce8fb3187 --- /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 0000000000..827f19344b --- /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 0000000000..172bda667f --- /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 0000000000..0aa9b706ae --- /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 0000000000..640ec38234 --- /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 0000000000..31969af477 --- /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 0000000000..21565d1610 --- /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 0000000000..527ceb8eed --- /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 0000000000..be7fb909f3 --- /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 0000000000..35aa9cf8c7 --- /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 0000000000..943424dc9c --- /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 0000000000..b29cd27c26 --- /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 0000000000..bf2b10e1d7 --- /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 0000000000..d90eaf73f1 --- /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 0000000000..9851afee0a --- /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 800b693260..a0a45e8aa0 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 803babdfa5..104f07c40e 100644 --- a/tests/ImageSharp.Tests/ConfigurationTests.cs +++ b/tests/ImageSharp.Tests/ConfigurationTests.cs @@ -21,7 +21,7 @@ public class ConfigurationTests 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 bf13a9097d..eeb77da674 100644 --- a/tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs +++ b/tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs @@ -136,6 +136,11 @@ public void ImageCanConvertFormat() 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 @@ public void ImageShouldPreservePixelByteOrderWhenSerialized() } [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 5cd70b1001..05a7a3be87 100644 --- a/tests/ImageSharp.Tests/Formats/ImageFormatManagerTests.cs +++ b/tests/ImageSharp.Tests/Formats/ImageFormatManagerTests.cs @@ -9,6 +9,7 @@ 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 @@ public ImageFormatManagerTests() [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 @@ 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.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 0000000000..6ab0cf22fa --- /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 0000000000..4ff3593877 --- /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 0000000000..339cc4a5c1 --- /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 0000000000..00b4f443dd --- /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 0000000000..7b701fe3d6 --- /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 0000000000..391e8c054e --- /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 8bb121349f..f21f2c916f 100644 --- a/tests/ImageSharp.Tests/Image/ImageTests.SaveAsync.cs +++ b/tests/ImageSharp.Tests/Image/ImageTests.SaveAsync.cs @@ -71,6 +71,7 @@ public async Task SetEncoding() } [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 @@ public async Task ThrowsWhenDisposed() } [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 e003649135..67f947ff55 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -866,5 +866,16 @@ public static class Tiff 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 4b374b21f6..fe512f9dcf 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.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 @@ private static Configuration CreateDefaultConfiguration() 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 0000000000..3211887623 --- /dev/null +++ b/tests/Images/Input/Pbm/00000_00000.ppm @@ -0,0 +1,4 @@ +P6 +29 30 +255 +KNPJLNVWTl^U�tr�nr�yy������������������s������ɻ���������ܫ��mp�CA�RVbmY[aKOPDKKAEDBCBSTVPPRZYT�k_��{�YQ�UZϧ�������������~����Ѱ���Ɋ������������ʇ��R?�NQ�[ug\kTQVIMNLNKPPNNNPVUV]Z[�xz�kf�D6������������������������ڹŕ�y������������ݩ��bk�bh�berZ[^SSHJHIJENNJJKM[SSn\d�u��QP�[G��������������㾵����������������������������ؐ��FO�L9�oc}`ZKHBIJCIOJGJG`QH�b`�sw�IH�rk�������������ϸ���������د�ң�Θ�ˎ��y�����^m�JH�6"�RH�nnULJIKHP]\EJBxfT��u�aX�A@�Y_Ӂ��tu�jk�``�XV�PN�LJ�HE�D@�A=�?;�>:y=9m=8x>7�?1�S=�LD�fkSPRJJJiknemp�ml����B6�A=�@D�AE�CG�EJ�HO�HN�HN�KN�OO�UW�[_�cl�ky�]`�rk�rl�so�rj�qf}KHw_cHJJLIFh__����������{l�mg�rt�w{�}����ɉ�؎�䐟���쟵Ս��|��lalVPcQOZML_KJeJKTGKEEDJHBPLJ�������������o�|x�eq�_kxbo�}t��t��tt�``�LL�MP�OT�dk�y��iq�go```YYPWWRXVTRNNIFHIGGHGDJJH��Ȼ����і��oq�\f�J\|f_ryXt�]��S^�J;�A9�HG�ON�IH�C<�F8�JP�To�w|whXXZPRSOLLJKKKJJJGGFMMJ������������Zt�E^�F_�{`��Rh�FK�ei�_cԓ����������˔��eu�SZ�A@�\_�hpW\^LPMLOMMONIKIGGDKJF��o��pjeZ���Zw�L^�]c��W��L\�Y>�wvޮ����������������ڳ�ً��aC�BC}Pqe_nTSQOSQSURLLHNMGZWRţ~|kMWWJ��[|�T^�xl��a~�LV�ldŎ�˱���������խý���zy��}�с��MQ�PZyhl]WW\a`Y[YPOLVSO[VQ�ǎ�wWJJ:z��`��de��u��PO�MRԝ������m�wP��m�ǟ�������}��h�ڝ��Ya�G:�qkvabkpp^a_QRPSSQ\[V�����aVUGv��m��sl��t��@>�gk��٣�ƺ������vW�p^�kf©����zo����|��?9�UT�kmbhhY]\RUTRTT`b`��r��^daTw�����u��t��@<ʁ����������ȾǕ�y˶��n�������v�ճ�۠��@A�WY�mq]abX[ZUXXSUVZ\\|�s��qvpm}~�|���~��x~}@<̔�������������������vq~������~w�ǭ�Ƙ�}AA�Z[�orX[[WZVUXTTWS[^Zlrthjndciffnhjf��w�}s�D@�pv�����󚗳lu���������������rx�ѵ�ϑ��?>�^_�jmVVTYZSVYQZ]T^aX�������������������lg�HH�X[��é��l[[�}������Ĉ��u��k�����۽ʺkl�>4�RN�fg[YWZZUZ]W]`Y^aZ��ĭ�ë���������������cg�AA�tq֨���t~wj�������µ�ļ����������EO�S?�yor]\_\Z[[XWYUZ[V]]X��­�����������nvkxq�y�YO�F8ɉt�̰������������������⡰�_g�ck�hplfjYTU^Z[a`bUWWUURXUQ���������������l�vSk]�n^�q]�[B�E*ʆh�������������������cK�]cyX|YThTRV^^cWX_SUXOQPSUR�|Y}}db|gI`O���j�{Jm^OS?�fO�y_�\K�@7�RT�dr����khӇ�裷Ä��hk�]hkSeTOYPPSZ^bNQWLORHMNIQO����U?OduO���l�Kp`J_Fsw]�d����`l�NR�MI}MF�QG�VN�oi����s��jzcVWOKLRRT[_cMOUSTXJNQNUT�oĮ�X^:DO4���m��NveFlNNrUYx]b|l��|�jd���ha�zt�z�������~�lkz[Y`NKPOORTXZLNOOOOMPPNTR��L�yWgnUW]M������\|je�^c}]h~bn�g��m��u��y��}��}�}{������|w�ljy\[iMLUJJOPRRQRNRRNRSOQTP��o|qkshjkd�����������������������z}�y}�y���z��iprnnhuoqup{okvjiuRS[FFJJJJOOKMNJNNI[[W���z�py|suvvruoothmrdkq`inbhmcgfekcKTKdla���}��[cinma������smugcm]Z`JHKKIIUTP^^Yab[cgc[_c[bgJUYDHKMJLTLM^QU]W^Z[`__bXVXJMNIRQLUQ�����Xaipmf������umphah]V[PKOLHH]ZWge_nqh`hbUTW_ek=JOAGLEDESOMc[^ZW`RSXZZ\cbhQR]LPVNTV������T_jfkh������nnmb^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 0000000000..a25b1d3505 --- /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 0000000000..fea8cafd0d --- /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 0000000000..ba4757248f --- /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 0000000000..ecd1b915c8 --- /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 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 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/29] 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 1c86b2bd85..c7a09a613e 100644 --- a/src/ImageSharp/Formats/Pbm/BinaryDecoder.cs +++ b/src/ImageSharp/Formats/Pbm/BinaryDecoder.cs @@ -176,6 +176,7 @@ private static void ProcessBlackAndWhite(Configuration configuration, Bu { 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/29] 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 a0a45e8aa0..6eed09b398 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 4d7af89a58..8f0b4a86f2 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 a141a58b07..1a470fa31f 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 c560b1b78f..471287006f 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/29] 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 c7a09a613e..8b6df295b2 100644 --- a/src/ImageSharp/Formats/Pbm/BinaryDecoder.cs +++ b/src/ImageSharp/Formats/Pbm/BinaryDecoder.cs @@ -171,7 +171,7 @@ private static void ProcessBlackAndWhite(Configuration configuration, Bu 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 1233c87fcb..2bcbaeef7c 100644 --- a/src/ImageSharp/Formats/Pbm/BinaryEncoder.cs +++ b/src/ImageSharp/Formats/Pbm/BinaryEncoder.cs @@ -60,8 +60,8 @@ public static void WritePixels(Configuration configuration, Stream strea 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 @@ private static void WriteGrayscale(Configuration configuration, Stream s 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 @@ private static void WriteWideGrayscale(Configuration configuration, Stre 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 @@ private static void WriteRgb(Configuration configuration, Stream stream, 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 @@ private static void WriteWideRgb(Configuration configuration, Stream str 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 @@ private static void WriteBlackAndWhite(Configuration configuration, Stre 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 054731b483..581d3e592b 100644 --- a/src/ImageSharp/Formats/Pbm/BufferedReadStreamExtensions.cs +++ b/src/ImageSharp/Formats/Pbm/BufferedReadStreamExtensions.cs @@ -51,7 +51,7 @@ public static int ReadDecimal(this BufferedReadStream stream) 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 0aa9b706ae..912ffaf856 100644 --- a/src/ImageSharp/Formats/Pbm/PbmConstants.cs +++ b/src/ImageSharp/Formats/Pbm/PbmConstants.cs @@ -18,11 +18,11 @@ internal static class PbmConstants /// /// 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 640ec38234..62cef176de 100644 --- a/src/ImageSharp/Formats/Pbm/PbmDecoder.cs +++ b/src/ImageSharp/Formats/Pbm/PbmDecoder.cs @@ -9,7 +9,23 @@ 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 31969af477..bd99a578aa 100644 --- a/src/ImageSharp/Formats/Pbm/PbmDecoderCore.cs +++ b/src/ImageSharp/Formats/Pbm/PbmDecoderCore.cs @@ -82,9 +82,9 @@ public IImageInfo Identify(BufferedReadStream stream, CancellationToken cancella /// 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 21565d1610..fe0f7f9f16 100644 --- a/src/ImageSharp/Formats/Pbm/PbmEncoder.cs +++ b/src/ImageSharp/Formats/Pbm/PbmEncoder.cs @@ -10,7 +10,28 @@ 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 527ceb8eed..eb1ba81401 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 @@ public void Encode(Image image, Stream stream, CancellationToken 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 @@ private void DeduceOptions(Image image) } } - 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 @@ private string DeduceSignature() // 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 943424dc9c..15bacc4de7 100644 --- a/src/ImageSharp/Formats/Pbm/PbmImageFormatDetector.cs +++ b/src/ImageSharp/Formats/Pbm/PbmImageFormatDetector.cs @@ -22,9 +22,12 @@ public sealed class PbmImageFormatDetector : IImageFormatDetector 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 d90eaf73f1..e362f8680f 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 @@ internal class PlainEncoder 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 @@ public static void WritePixels(Configuration configuration, Stream strea 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 @@ private static void WriteGrayscale(Configuration configuration, Stream s 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 @@ private static void WriteWideGrayscale(Configuration configuration, Stre 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 @@ private static void WriteRgb(Configuration configuration, Stream stream, 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 @@ private static void WriteWideRgb(Configuration configuration, Stream str 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 @@ private static void WriteBlackAndWhite(Configuration configuration, Stre 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 9851afee0a..0000000000 --- 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 4ff3593877..6c84fba9ee 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 @@ public class PbmDecoderTests [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 @@ public void PpmDecoder_CanDecode(string imagePath, PbmColorType expectedColorTyp 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 67f947ff55..444be63a24 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -874,8 +874,10 @@ public static class 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 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 0000000000..09bb074a3b --- /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 0000000000..d1f1515bb0 --- /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 0000000000..3722619230 --- /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 0000000000..9c86c2fc10 --- /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 0000000000..acf751c28e --- /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 0000000000..49cc74f3ff --- /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 0000000000..421a598493 --- /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 0000000000..fe03296296 --- /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 0000000000..6289315793 --- /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/29] 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 09bb074a3b..0000000000 --- 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 d1f1515bb0..0000000000 --- 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 3722619230..0000000000 --- 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 9c86c2fc10..0000000000 --- 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 acf751c28e..0000000000 --- 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 49cc74f3ff..0000000000 --- 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 421a598493..0000000000 --- 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/29] 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 0000000000..09bb074a3b --- /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 0000000000..d1f1515bb0 --- /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 0000000000..3722619230 --- /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 0000000000..9c86c2fc10 --- /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 0000000000..acf751c28e --- /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 0000000000..49cc74f3ff --- /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 0000000000..421a598493 --- /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/29] 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 09bb074a3b..0000000000 --- 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 d1f1515bb0..0000000000 --- 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 3722619230..0000000000 --- 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 9c86c2fc10..0000000000 --- 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 acf751c28e..0000000000 --- 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 49cc74f3ff..0000000000 --- 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 421a598493..0000000000 --- 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 3211887623..0000000000 --- a/tests/Images/Input/Pbm/00000_00000.ppm +++ /dev/null @@ -1,4 +0,0 @@ -P6 -29 30 -255 -KNPJLNVWTl^U�tr�nr�yy������������������s������ɻ���������ܫ��mp�CA�RVbmY[aKOPDKKAEDBCBSTVPPRZYT�k_��{�YQ�UZϧ�������������~����Ѱ���Ɋ������������ʇ��R?�NQ�[ug\kTQVIMNLNKPPNNNPVUV]Z[�xz�kf�D6������������������������ڹŕ�y������������ݩ��bk�bh�berZ[^SSHJHIJENNJJKM[SSn\d�u��QP�[G��������������㾵����������������������������ؐ��FO�L9�oc}`ZKHBIJCIOJGJG`QH�b`�sw�IH�rk�������������ϸ���������د�ң�Θ�ˎ��y�����^m�JH�6"�RH�nnULJIKHP]\EJBxfT��u�aX�A@�Y_Ӂ��tu�jk�``�XV�PN�LJ�HE�D@�A=�?;�>:y=9m=8x>7�?1�S=�LD�fkSPRJJJiknemp�ml����B6�A=�@D�AE�CG�EJ�HO�HN�HN�KN�OO�UW�[_�cl�ky�]`�rk�rl�so�rj�qf}KHw_cHJJLIFh__����������{l�mg�rt�w{�}����ɉ�؎�䐟���쟵Ս��|��lalVPcQOZML_KJeJKTGKEEDJHBPLJ�������������o�|x�eq�_kxbo�}t��t��tt�``�LL�MP�OT�dk�y��iq�go```YYPWWRXVTRNNIFHIGGHGDJJH��Ȼ����і��oq�\f�J\|f_ryXt�]��S^�J;�A9�HG�ON�IH�C<�F8�JP�To�w|whXXZPRSOLLJKKKJJJGGFMMJ������������Zt�E^�F_�{`��Rh�FK�ei�_cԓ����������˔��eu�SZ�A@�\_�hpW\^LPMLOMMONIKIGGDKJF��o��pjeZ���Zw�L^�]c��W��L\�Y>�wvޮ����������������ڳ�ً��aC�BC}Pqe_nTSQOSQSURLLHNMGZWRţ~|kMWWJ��[|�T^�xl��a~�LV�ldŎ�˱���������խý���zy��}�с��MQ�PZyhl]WW\a`Y[YPOLVSO[VQ�ǎ�wWJJ:z��`��de��u��PO�MRԝ������m�wP��m�ǟ�������}��h�ڝ��Ya�G:�qkvabkpp^a_QRPSSQ\[V�����aVUGv��m��sl��t��@>�gk��٣�ƺ������vW�p^�kf©����zo����|��?9�UT�kmbhhY]\RUTRTT`b`��r��^daTw�����u��t��@<ʁ����������ȾǕ�y˶��n�������v�ճ�۠��@A�WY�mq]abX[ZUXXSUVZ\\|�s��qvpm}~�|���~��x~}@<̔�������������������vq~������~w�ǭ�Ƙ�}AA�Z[�orX[[WZVUXTTWS[^Zlrthjndciffnhjf��w�}s�D@�pv�����󚗳lu���������������rx�ѵ�ϑ��?>�^_�jmVVTYZSVYQZ]T^aX�������������������lg�HH�X[��é��l[[�}������Ĉ��u��k�����۽ʺkl�>4�RN�fg[YWZZUZ]W]`Y^aZ��ĭ�ë���������������cg�AA�tq֨���t~wj�������µ�ļ����������EO�S?�yor]\_\Z[[XWYUZ[V]]X��­�����������nvkxq�y�YO�F8ɉt�̰������������������⡰�_g�ck�hplfjYTU^Z[a`bUWWUURXUQ���������������l�vSk]�n^�q]�[B�E*ʆh�������������������cK�]cyX|YThTRV^^cWX_SUXOQPSUR�|Y}}db|gI`O���j�{Jm^OS?�fO�y_�\K�@7�RT�dr����khӇ�裷Ä��hk�]hkSeTOYPPSZ^bNQWLORHMNIQO����U?OduO���l�Kp`J_Fsw]�d����`l�NR�MI}MF�QG�VN�oi����s��jzcVWOKLRRT[_cMOUSTXJNQNUT�oĮ�X^:DO4���m��NveFlNNrUYx]b|l��|�jd���ha�zt�z�������~�lkz[Y`NKPOORTXZLNOOOOMPPNTR��L�yWgnUW]M������\|je�^c}]h~bn�g��m��u��y��}��}�}{������|w�ljy\[iMLUJJOPRRQRNRRNRSOQTP��o|qkshjkd�����������������������z}�y}�y���z��iprnnhuoqup{okvjiuRS[FFJJJJOOKMNJNNI[[W���z�py|suvvruoothmrdkq`inbhmcgfekcKTKdla���}��[cinma������smugcm]Z`JHKKIIUTP^^Yab[cgc[_c[bgJUYDHKMJLTLM^QU]W^Z[`__bXVXJMNIRQLUQ�����Xaipmf������umphah]V[PKOLHH]ZWge_nqh`hbUTW_ek=JOAGLEDESOMc[^ZW`RSXZZ\cbhQR]LPVNTV������T_jfkh������nnmb^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 a25b1d3505..0000000000 --- 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 fea8cafd0d..0000000000 --- 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 ba4757248f..0000000000 --- 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 fe03296296..0000000000 --- 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 ecd1b915c8..0000000000 --- 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 6289315793..0000000000 --- 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/29] 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 0000000000..09bb074a3b --- /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 0000000000..d1f1515bb0 --- /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 0000000000..3722619230 --- /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 0000000000..9c86c2fc10 --- /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 0000000000..acf751c28e --- /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 0000000000..49cc74f3ff --- /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 0000000000..421a598493 --- /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 0000000000..3211887623 --- /dev/null +++ b/tests/Images/Input/Pbm/00000_00000.ppm @@ -0,0 +1,4 @@ +P6 +29 30 +255 +KNPJLNVWTl^U�tr�nr�yy������������������s������ɻ���������ܫ��mp�CA�RVbmY[aKOPDKKAEDBCBSTVPPRZYT�k_��{�YQ�UZϧ�������������~����Ѱ���Ɋ������������ʇ��R?�NQ�[ug\kTQVIMNLNKPPNNNPVUV]Z[�xz�kf�D6������������������������ڹŕ�y������������ݩ��bk�bh�berZ[^SSHJHIJENNJJKM[SSn\d�u��QP�[G��������������㾵����������������������������ؐ��FO�L9�oc}`ZKHBIJCIOJGJG`QH�b`�sw�IH�rk�������������ϸ���������د�ң�Θ�ˎ��y�����^m�JH�6"�RH�nnULJIKHP]\EJBxfT��u�aX�A@�Y_Ӂ��tu�jk�``�XV�PN�LJ�HE�D@�A=�?;�>:y=9m=8x>7�?1�S=�LD�fkSPRJJJiknemp�ml����B6�A=�@D�AE�CG�EJ�HO�HN�HN�KN�OO�UW�[_�cl�ky�]`�rk�rl�so�rj�qf}KHw_cHJJLIFh__����������{l�mg�rt�w{�}����ɉ�؎�䐟���쟵Ս��|��lalVPcQOZML_KJeJKTGKEEDJHBPLJ�������������o�|x�eq�_kxbo�}t��t��tt�``�LL�MP�OT�dk�y��iq�go```YYPWWRXVTRNNIFHIGGHGDJJH��Ȼ����і��oq�\f�J\|f_ryXt�]��S^�J;�A9�HG�ON�IH�C<�F8�JP�To�w|whXXZPRSOLLJKKKJJJGGFMMJ������������Zt�E^�F_�{`��Rh�FK�ei�_cԓ����������˔��eu�SZ�A@�\_�hpW\^LPMLOMMONIKIGGDKJF��o��pjeZ���Zw�L^�]c��W��L\�Y>�wvޮ����������������ڳ�ً��aC�BC}Pqe_nTSQOSQSURLLHNMGZWRţ~|kMWWJ��[|�T^�xl��a~�LV�ldŎ�˱���������խý���zy��}�с��MQ�PZyhl]WW\a`Y[YPOLVSO[VQ�ǎ�wWJJ:z��`��de��u��PO�MRԝ������m�wP��m�ǟ�������}��h�ڝ��Ya�G:�qkvabkpp^a_QRPSSQ\[V�����aVUGv��m��sl��t��@>�gk��٣�ƺ������vW�p^�kf©����zo����|��?9�UT�kmbhhY]\RUTRTT`b`��r��^daTw�����u��t��@<ʁ����������ȾǕ�y˶��n�������v�ճ�۠��@A�WY�mq]abX[ZUXXSUVZ\\|�s��qvpm}~�|���~��x~}@<̔�������������������vq~������~w�ǭ�Ƙ�}AA�Z[�orX[[WZVUXTTWS[^Zlrthjndciffnhjf��w�}s�D@�pv�����󚗳lu���������������rx�ѵ�ϑ��?>�^_�jmVVTYZSVYQZ]T^aX�������������������lg�HH�X[��é��l[[�}������Ĉ��u��k�����۽ʺkl�>4�RN�fg[YWZZUZ]W]`Y^aZ��ĭ�ë���������������cg�AA�tq֨���t~wj�������µ�ļ����������EO�S?�yor]\_\Z[[XWYUZ[V]]X��­�����������nvkxq�y�YO�F8ɉt�̰������������������⡰�_g�ck�hplfjYTU^Z[a`bUWWUURXUQ���������������l�vSk]�n^�q]�[B�E*ʆh�������������������cK�]cyX|YThTRV^^cWX_SUXOQPSUR�|Y}}db|gI`O���j�{Jm^OS?�fO�y_�\K�@7�RT�dr����khӇ�裷Ä��hk�]hkSeTOYPPSZ^bNQWLORHMNIQO����U?OduO���l�Kp`J_Fsw]�d����`l�NR�MI}MF�QG�VN�oi����s��jzcVWOKLRRT[_cMOUSTXJNQNUT�oĮ�X^:DO4���m��NveFlNNrUYx]b|l��|�jd���ha�zt�z�������~�lkz[Y`NKPOORTXZLNOOOOMPPNTR��L�yWgnUW]M������\|je�^c}]h~bn�g��m��u��y��}��}�}{������|w�ljy\[iMLUJJOPRRQRNRRNRSOQTP��o|qkshjkd�����������������������z}�y}�y���z��iprnnhuoqup{okvjiuRS[FFJJJJOOKMNJNNI[[W���z�py|suvvruoothmrdkq`inbhmcgfekcKTKdla���}��[cinma������smugcm]Z`JHKKIIUTP^^Yab[cgc[_c[bgJUYDHKMJLTLM^QU]W^Z[`__bXVXJMNIRQLUQ�����Xaipmf������umphah]V[PKOLHH]ZWge_nqh`hbUTW_ek=JOAGLEDESOMc[^ZW`RSXZZ\cbhQR]LPVNTV������T_jfkh������nnmb^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 0000000000..a25b1d3505 --- /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 0000000000..fea8cafd0d --- /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 0000000000..ba4757248f --- /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 0000000000..fe03296296 --- /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 0000000000..ecd1b915c8 --- /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 0000000000..6289315793 --- /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 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 9599efe5201dc516673000adecf1dd84b6976cf5 Mon Sep 17 00:00:00 2001 From: Ynse Hoornenborg Date: Mon, 29 Nov 2021 20:51:17 +0100 Subject: [PATCH 11/29] Update .gitattributes file --- .gitattributes | 8 ++++++-- shared-infrastructure | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/.gitattributes b/.gitattributes index 70ced69033..355b64dce1 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 a042aba176..59ce17f5a4 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/29] 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 e362f8680f..b67f0a077c 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 @@ private static void WriteGrayscale(Configuration configuration, Stream s 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 @@ private static void WriteWideGrayscale(Configuration configuration, Stre 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 @@ private static void WriteRgb(Configuration configuration, Stream stream, 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 @@ private static void WriteWideRgb(Configuration configuration, Stream str 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 @@ private static void WriteBlackAndWhite(Configuration configuration, Stre 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 87ce4e53e249b280a13ea06af49041a2309d7658 Mon Sep 17 00:00:00 2001 From: Ynse Hoornenborg Date: Wed, 1 Dec 2021 22:11:28 +0100 Subject: [PATCH 13/29] 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 eb1ba81401..158786e3ca 100644 --- a/src/ImageSharp/Formats/Pbm/PbmEncoderCore.cs +++ b/src/ImageSharp/Formats/Pbm/PbmEncoderCore.cs @@ -88,6 +88,7 @@ private void DeduceOptions(Image image) 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 b67f0a077c..2e7c60e5ee 100644 --- a/src/ImageSharp/Formats/Pbm/PlainEncoder.cs +++ b/src/ImageSharp/Formats/Pbm/PlainEncoder.cs @@ -76,7 +76,7 @@ private static void WriteGrayscale(Configuration configuration, Stream s 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 @@ private static void WriteWideGrayscale(Configuration configuration, Stre 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 @@ private static void WriteRgb(Configuration configuration, Stream stream, 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 @@ private static void WriteWideRgb(Configuration configuration, Stream str 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 @@ private static void WriteBlackAndWhite(Configuration configuration, Stre 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 6c84fba9ee..479db2ca57 100644 --- a/tests/ImageSharp.Tests/Formats/Pbm/PbmDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Pbm/PbmDecoderTests.cs @@ -84,6 +84,7 @@ public void DecodeReferenceImage(TestImageProvider provider, boo 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 391e8c054e..715a1e07e9 100644 --- a/tests/ImageSharp.Tests/Formats/Pbm/RoundTripTests.cs +++ b/tests/ImageSharp.Tests/Formats/Pbm/PbmRoundTripTests.cs @@ -11,8 +11,28 @@ 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 @@ private Image RoundTrip(Image originalImage) 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 7b701fe3d6..0000000000 --- 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 14/29] 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 715a1e07e9..1735efdce8 100644 --- a/tests/ImageSharp.Tests/Formats/Pbm/PbmRoundTripTests.cs +++ b/tests/ImageSharp.Tests/Formats/Pbm/PbmRoundTripTests.cs @@ -25,7 +25,7 @@ public void PbmGrayscaleImageCanRoundTrip(string imagePath) // Act using var originalImage = Image.Load(stream); - Image colorImage = originalImage.CloneAs(); + using Image colorImage = originalImage.CloneAs(); using Image encodedImage = this.RoundTrip(colorImage); // Assert From 26b3e664db2eb20d5ddb848dd0c01ea1b31c1c37 Mon Sep 17 00:00:00 2001 From: Ynse Hoornenborg Date: Fri, 3 Dec 2021 11:34:45 +0100 Subject: [PATCH 15/29] 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 bf2b10e1d7..9fa8e513e0 100644 --- a/src/ImageSharp/Formats/Pbm/PlainDecoder.cs +++ b/src/ImageSharp/Formats/Pbm/PlainDecoder.cs @@ -174,8 +174,8 @@ private static void ProcessBlackAndWhite(Configuration configuration, Bu 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 2e7c60e5ee..8d534b7a9a 100644 --- a/src/ImageSharp/Formats/Pbm/PlainEncoder.cs +++ b/src/ImageSharp/Formats/Pbm/PlainEncoder.cs @@ -230,7 +230,7 @@ private static void WriteBlackAndWhite(Configuration configuration, Stre 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 1735efdce8..cba75b2a01 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 16/29] 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 bd99a578aa..427ea15e8c 100644 --- a/src/ImageSharp/Formats/Pbm/PbmDecoderCore.cs +++ b/src/ImageSharp/Formats/Pbm/PbmDecoderCore.cs @@ -7,6 +7,7 @@ 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 @@ internal sealed class PbmDecoderCore : IImageDecoderInternals /// 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 @@ public Image Decode(BufferedReadStream stream, CancellationToken Buffer2D pixels = image.GetRootFramePixelBuffer(); this.ProcessPixels(stream, pixels); + if (this.NeedsUpscaling) + { + this.ProcessUpscaling(image); + } return image; } @@ -165,5 +187,13 @@ private void ProcessPixels(BufferedReadStream stream, Buffer2D p 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 479db2ca57..8b8e1a08ff 100644 --- a/tests/ImageSharp.Tests/Formats/Pbm/PbmDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Pbm/PbmDecoderTests.cs @@ -74,10 +74,13 @@ public void ImageLoadRgb24CanDecode(string imagePath) } [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 cba75b2a01..9521ee7e94 100644 --- a/tests/ImageSharp.Tests/Formats/Pbm/PbmRoundTripTests.cs +++ b/tests/ImageSharp.Tests/Formats/Pbm/PbmRoundTripTests.cs @@ -17,6 +17,7 @@ public class PbmRoundTripTests [InlineData(BlackAndWhitePlain)] [InlineData(BlackAndWhiteBinary)] [InlineData(GrayscalePlain)] + [InlineData(GrayscalePlainNormalized)] [InlineData(GrayscaleBinary)] public void PbmGrayscaleImageCanRoundTrip(string imagePath) { @@ -36,6 +37,7 @@ public void PbmGrayscaleImageCanRoundTrip(string imagePath) [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 0000000000..9c86c2fc10 --- /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 0000000000..421a598493 --- /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 284772c11cdd54a864a8a729282eef6404390204 Mon Sep 17 00:00:00 2001 From: Ynse Hoornenborg Date: Sat, 4 Dec 2021 21:06:20 +0100 Subject: [PATCH 17/29] 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 3211887623..f6e0857879 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^U�tr�nr�yy������������������s������ɻ���������ܫ��mp�CA�RVbmY[aKOPDKKAEDBCBSTVPPRZYT�k_��{�YQ�UZϧ�������������~����Ѱ���Ɋ������������ʇ��R?�NQ�[ug\kTQVIMNLNKPPNNNPVUV]Z[�xz�kf�D6������������������������ڹŕ�y������������ݩ��bk�bh�berZ[^SSHJHIJENNJJKM[SSn\d�u��QP�[G��������������㾵����������������������������ؐ��FO�L9�oc}`ZKHBIJCIOJGJG`QH�b`�sw�IH�rk�������������ϸ���������د�ң�Θ�ˎ��y�����^m�JH�6"�RH�nnULJIKHP]\EJBxfT��u�aX�A@�Y_Ӂ��tu�jk�``�XV�PN�LJ�HE�D@�A=�?;�>:y=9m=8x>7�?1�S=�LD�fkSPRJJJiknemp�ml����B6�A=�@D�AE�CG�EJ�HO�HN�HN�KN�OO�UW�[_�cl�ky�]`�rk�rl�so�rj�qf}KHw_cHJJLIFh__����������{l�mg�rt�w{�}����ɉ�؎�䐟���쟵Ս��|��lalVPcQOZML_KJeJKTGKEEDJHBPLJ�������������o�|x�eq�_kxbo�}t��t��tt�``�LL�MP�OT�dk�y��iq�go```YYPWWRXVTRNNIFHIGGHGDJJH��Ȼ����і��oq�\f�J\|f_ryXt�]��S^�J;�A9�HG�ON�IH�C<�F8�JP�To�w|whXXZPRSOLLJKKKJJJGGFMMJ������������Zt�E^�F_�{`��Rh�FK�ei�_cԓ����������˔��eu�SZ�A@�\_�hpW\^LPMLOMMONIKIGGDKJF��o��pjeZ���Zw�L^�]c��W��L\�Y>�wvޮ����������������ڳ�ً��aC�BC}Pqe_nTSQOSQSURLLHNMGZWRţ~|kMWWJ��[|�T^�xl��a~�LV�ldŎ�˱���������խý���zy��}�с��MQ�PZyhl]WW\a`Y[YPOLVSO[VQ�ǎ�wWJJ:z��`��de��u��PO�MRԝ������m�wP��m�ǟ�������}��h�ڝ��Ya�G:�qkvabkpp^a_QRPSSQ\[V�����aVUGv��m��sl��t��@>�gk��٣�ƺ������vW�p^�kf©����zo����|��?9�UT�kmbhhY]\RUTRTT`b`��r��^daTw�����u��t��@<ʁ����������ȾǕ�y˶��n�������v�ճ�۠��@A�WY�mq]abX[ZUXXSUVZ\\|�s��qvpm}~�|���~��x~}@<̔�������������������vq~������~w�ǭ�Ƙ�}AA�Z[�orX[[WZVUXTTWS[^Zlrthjndciffnhjf��w�}s�D@�pv�����󚗳lu���������������rx�ѵ�ϑ��?>�^_�jmVVTYZSVYQZ]T^aX�������������������lg�HH�X[��é��l[[�}������Ĉ��u��k�����۽ʺkl�>4�RN�fg[YWZZUZ]W]`Y^aZ��ĭ�ë���������������cg�AA�tq֨���t~wj�������µ�ļ����������EO�S?�yor]\_\Z[[XWYUZ[V]]X��­�����������nvkxq�y�YO�F8ɉt�̰������������������⡰�_g�ck�hplfjYTU^Z[a`bUWWUURXUQ���������������l�vSk]�n^�q]�[B�E*ʆh�������������������cK�]cyX|YThTRV^^cWX_SUXOQPSUR�|Y}}db|gI`O���j�{Jm^OS?�fO�y_�\K�@7�RT�dr����khӇ�裷Ä��hk�]hkSeTOYPPSZ^bNQWLORHMNIQO����U?OduO���l�Kp`J_Fsw]�d����`l�NR�MI}MF�QG�VN�oi����s��jzcVWOKLRRT[_cMOUSTXJNQNUT�oĮ�X^:DO4���m��NveFlNNrUYx]b|l��|�jd���ha�zt�z�������~�lkz[Y`NKPOORTXZLNOOOOMPPNTR��L�yWgnUW]M������\|je�^c}]h~bn�g��m��u��y��}��}�}{������|w�ljy\[iMLUJJOPRRQRNRRNRSOQTP��o|qkshjkd�����������������������z}�y}�y���z��iprnnhuoqup{okvjiuRS[FFJJJJOOKMNJNNI[[W���z�py|suvvruoothmrdkq`inbhmcgfekcKTKdla���}��[cinma������smugcm]Z`JHKKIIUTP^^Yab[cgc[_c[bgJUYDHKMJLTLM^QU]W^Z[`__bXVXJMNIRQLUQ�����Xaipmf������umphah]V[PKOLHH]ZWge_nqh`hbUTW_ek=JOAGLEDESOMc[^ZW`RSXZZ\cbhQR]LPVNTV������T_jfkh������nnmb^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 a25b1d3505..d07976894a 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 fea8cafd0d..9c92a99cc5 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 ba4757248f..fa521b5da9 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 fe03296296..96497d6057 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 ecd1b915c8..32472d0ce6 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 6289315793..3d7fbe241a 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 18/29] 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 427ea15e8c..1aeecc16ff 100644 --- a/src/ImageSharp/Formats/Pbm/PbmDecoderCore.cs +++ b/src/ImageSharp/Formats/Pbm/PbmDecoderCore.cs @@ -53,22 +53,7 @@ internal sealed class PbmDecoderCore : IImageDecoderInternals /// 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 19/29] 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 1aeecc16ff..b2be74ea14 100644 --- a/src/ImageSharp/Formats/Pbm/PbmDecoderCore.cs +++ b/src/ImageSharp/Formats/Pbm/PbmDecoderCore.cs @@ -94,8 +94,7 @@ private void ProcessHeader(BufferedReadStream stream) 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 @@ private void ProcessHeader(BufferedReadStream stream) // 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 20/29] 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 8b6df295b2..2a171456ad 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 @@ public static void Process(Configuration configuration, Buffer2D 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 @@ private static void ProcessGrayscale(Configuration configuration, Buffer 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 @@ private static void ProcessWideGrayscale(Configuration configuration, Bu 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 @@ private static void ProcessRgb(Configuration configuration, Buffer2D(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 @@ private static void ProcessBlackAndWhite(Configuration configuration, Bu 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 2bcbaeef7c..626026726b 100644 --- a/src/ImageSharp/Formats/Pbm/BinaryEncoder.cs +++ b/src/ImageSharp/Formats/Pbm/BinaryEncoder.cs @@ -83,9 +83,9 @@ private static void WriteGrayscale(Configuration configuration, Stream s 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 @@ private static void WriteWideGrayscale(Configuration configuration, Stre 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 @@ private static void WriteRgb(Configuration configuration, Stream stream, 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 9fa8e513e0..dc5350bdd9 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 @@ private static void ProcessBlackAndWhite(Configuration configuration, Bu 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 21/29] 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 339cc4a5c1..dcc63618cd 100644 --- a/tests/ImageSharp.Tests/Formats/Pbm/PbmEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Pbm/PbmEncoderTests.cs @@ -5,7 +5,7 @@ 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 @@ private static void TestPbmEncoderCore( 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 1c53ff6a1c..bd7a6e07a0 100644 --- a/tests/ImageSharp.Tests/Formats/Tga/TgaDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tga/TgaDecoderTests.cs @@ -29,7 +29,7 @@ public void TgaDecoder_CanDecode_Gray_WithTopLeftOrigin_8Bit(TestImagePr using (Image image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); } } @@ -41,7 +41,7 @@ public void TgaDecoder_CanDecode_Gray_WithBottomLeftOrigin_8Bit(TestImag using (Image image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); } } @@ -53,7 +53,7 @@ public void TgaDecoder_CanDecode_Gray_WithTopRightOrigin_8Bit(TestImageP using (Image image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); } } @@ -65,7 +65,7 @@ public void TgaDecoder_CanDecode_Gray_WithBottomRightOrigin_8Bit(TestIma using (Image image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); } } @@ -77,7 +77,7 @@ public void TgaDecoder_CanDecode_RunLengthEncoded_Gray_WithTopLeftOrigin_8Bit image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); } } @@ -89,7 +89,7 @@ public void TgaDecoder_CanDecode_RunLengthEncoded_Gray_WithTopRightOrigin_8Bit image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); } } @@ -101,7 +101,7 @@ public void TgaDecoder_CanDecode_RunLengthEncoded_Gray_WithBottomLeftOrigin_8Bit using (Image image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); } } @@ -113,7 +113,7 @@ public void TgaDecoder_CanDecode_RunLengthEncoded_Gray_WithBottomRightOrigin_8Bi using (Image image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); } } @@ -245,7 +245,7 @@ public void TgaDecoder_CanDecode_15Bit(TestImageProvider provide using (Image image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); } } @@ -257,7 +257,7 @@ public void TgaDecoder_CanDecode_RunLengthEncoded_15Bit(TestImageProvide using (Image image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); } } @@ -269,7 +269,7 @@ public void TgaDecoder_CanDecode_WithBottomLeftOrigin_16Bit(TestImagePro using (Image image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); } } @@ -281,7 +281,7 @@ public void TgaDecoder_CanDecode_RunLengthEncoded_WithPalette_16Bit(Test using (Image image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); } } @@ -293,7 +293,7 @@ public void TgaDecoder_CanDecode_WithTopLeftOrigin_24Bit(TestImageProvid using (Image image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); } } @@ -305,7 +305,7 @@ public void TgaDecoder_CanDecode_WithBottomLeftOrigin_24Bit(TestImagePro using (Image image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); } } @@ -317,7 +317,7 @@ public void TgaDecoder_CanDecode_WithTopRightOrigin_24Bit(TestImageProvi using (Image image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); } } @@ -329,7 +329,7 @@ public void TgaDecoder_CanDecode_WithBottomRightOrigin_24Bit(TestImagePr using (Image image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); } } @@ -341,7 +341,7 @@ public void TgaDecoder_CanDecode_RunLengthEncoded_WithTopLeftOrigin_24Bit image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); } } @@ -353,7 +353,7 @@ public void TgaDecoder_CanDecode_RunLengthEncoded_WithTopRightOrigin_24Bit image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); } } @@ -365,7 +365,7 @@ public void TgaDecoder_CanDecode_RunLengthEncoded_WithBottomRightOrigin_24Bit image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); } } @@ -377,7 +377,7 @@ public void TgaDecoder_CanDecode_Palette_WithTopLeftOrigin_24Bit(TestIma using (Image image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); } } @@ -389,7 +389,7 @@ public void TgaDecoder_CanDecode_WithTopLeftOrigin_32Bit(TestImageProvid using (Image image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); } } @@ -401,7 +401,7 @@ public void TgaDecoder_CanDecode_WithTopRightOrigin_32Bit(TestImageProvi using (Image image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); } } @@ -413,7 +413,7 @@ public void TgaDecoder_CanDecode_WithBottomLeftOrigin_32Bit(TestImagePro using (Image image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); } } @@ -425,7 +425,7 @@ public void TgaDecoder_CanDecode_WithBottomRightOrigin_32Bit(TestImagePr using (Image image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); } } @@ -437,7 +437,7 @@ public void TgaDecoder_CanDecode_RunLengthEncoded_WithBottomLeftOrigin_16Bit image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); } } @@ -449,7 +449,7 @@ public void TgaDecoder_CanDecode_RunLengthEncoded_WithBottomLeftOrigin_24Bit image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); } } @@ -461,7 +461,7 @@ public void TgaDecoder_CanDecode_RunLengthEncoded_WithTopLeftOrigin_32Bit image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); } } @@ -473,7 +473,7 @@ public void TgaDecoder_CanDecode_RunLengthEncoded_WithBottomLeftOrigin_32Bit image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); } } @@ -485,7 +485,7 @@ public void TgaDecoder_CanDecode_RunLengthEncoded_WithTopRightOrigin_32Bit image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); } } @@ -497,7 +497,7 @@ public void TgaDecoder_CanDecode_RunLengthEncoded_WithBottomRightOrigin_32Bit image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); } } @@ -509,7 +509,7 @@ public void TgaDecoder_CanDecode_RLE_Paletted_WithTopLeftOrigin_32Bit(Te using (Image image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); } } @@ -521,7 +521,7 @@ public void TgaDecoder_CanDecode_RLE_Paletted_WithBottomLeftOrigin_32Bit using (Image image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); } } @@ -533,7 +533,7 @@ public void TgaDecoder_CanDecode_RLE_WithTopRightOrigin_32Bit(TestImageP using (Image image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); } } @@ -545,7 +545,7 @@ public void TgaDecoder_CanDecode_RLE_Paletted_WithBottomRightOrigin_32Bit image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); } } @@ -557,7 +557,7 @@ public void TgaDecoder_CanDecode_WithPaletteBottomLeftOrigin_16Bit(TestI using (Image image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); } } @@ -569,7 +569,7 @@ public void TgaDecoder_CanDecode_WithPaletteTopLeftOrigin_24Bit(TestImag using (Image image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); } } @@ -581,7 +581,7 @@ public void TgaDecoder_CanDecode_WithPaletteTopRightOrigin_24Bit(TestIma using (Image image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); } } @@ -593,7 +593,7 @@ public void TgaDecoder_CanDecode_WithPaletteBottomLeftOrigin_24Bit(TestI using (Image image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); } } @@ -605,7 +605,7 @@ public void TgaDecoder_CanDecode_WithPaletteBottomRightOrigin_24Bit(Test using (Image image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); } } @@ -617,7 +617,7 @@ public void TgaDecoder_CanDecode_RLE_WithPaletteTopLeftOrigin_24Bit(Test using (Image image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); } } @@ -629,7 +629,7 @@ public void TgaDecoder_CanDecode_RLE_WithPaletteTopRightOrigin_24Bit(Tes using (Image image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); } } @@ -641,7 +641,7 @@ public void TgaDecoder_CanDecode_RLE_WithPaletteBottomLeftOrigin_24Bit(T using (Image image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); } } @@ -653,7 +653,7 @@ public void TgaDecoder_CanDecode_RLE_WithPaletteBottomRightOrigin_24Bit( using (Image image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); } } @@ -665,7 +665,7 @@ public void TgaDecoder_CanDecode_WithPalette_32Bit(TestImageProvider image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); } } @@ -677,7 +677,7 @@ public void TgaDecoder_CanDecode_WithPalette_WithBottomLeftOrigin_32Bit( using (Image image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); } } @@ -689,7 +689,7 @@ public void TgaDecoder_CanDecode_WithPalette_WithBottomRightOrigin_32Bit using (Image image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); } } @@ -701,7 +701,7 @@ public void TgaDecoder_CanDecode_WithPalette_WithTopRightOrigin_32Bit(Te using (Image image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); } } @@ -714,7 +714,7 @@ public void TgaDecoder_CanDecode_WhenAlphaBitsNotSet_16Bit(TestImageProv 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 4c768a1a51..da8ff8018e 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 @@ private static void TestTgaEncoderCore( 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 cdd9616a72..c912ae26bd 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 @@ public class TiffMetadataTests { 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 eacadae2ba..0000000000 --- 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 684d7791bf..bd8a48a447 100644 --- a/tests/ImageSharp.Tests/Formats/WebP/LosslessUtilsTests.cs +++ b/tests/ImageSharp.Tests/Formats/WebP/LosslessUtilsTests.cs @@ -229,7 +229,7 @@ private static void RunPredictor13Test() 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 c96777031b..7eae5938ff 100644 --- a/tests/ImageSharp.Tests/Formats/Tga/TgaTestUtils.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ImageComparingUtils.cs @@ -5,12 +5,11 @@ 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 22/29] 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 8b8e1a08ff..51bf61d230 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 @@ public class PbmDecoderTests [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 @@ public void ImageLoadCanDecode(string imagePath, PbmColorType expectedColorType) [InlineData(BlackAndWhitePlain)] [InlineData(BlackAndWhiteBinary)] [InlineData(GrayscalePlain)] + [InlineData(GrayscalePlainMagick)] [InlineData(GrayscaleBinary)] [InlineData(GrayscaleBinaryWide)] public void ImageLoadL8CanDecode(string imagePath) @@ -59,6 +61,7 @@ public void ImageLoadL8CanDecode(string imagePath) [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 dcc63618cd..44fab1617c 100644 --- a/tests/ImageSharp.Tests/Formats/Pbm/PbmEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Pbm/PbmEncoderTests.cs @@ -93,24 +93,20 @@ public void PbmEncoder_P1_Works(TestImageProvider provider) 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 9521ee7e94..190972535f 100644 --- a/tests/ImageSharp.Tests/Formats/Pbm/PbmRoundTripTests.cs +++ b/tests/ImageSharp.Tests/Formats/Pbm/PbmRoundTripTests.cs @@ -18,6 +18,7 @@ public class PbmRoundTripTests [InlineData(BlackAndWhiteBinary)] [InlineData(GrayscalePlain)] [InlineData(GrayscalePlainNormalized)] + [InlineData(GrayscalePlainMagick)] [InlineData(GrayscaleBinary)] public void PbmGrayscaleImageCanRoundTrip(string imagePath) { @@ -38,6 +39,7 @@ public void PbmGrayscaleImageCanRoundTrip(string imagePath) [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 444be63a24..930b550a28 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -875,9 +875,11 @@ public static class Pbm 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 0000000000..fe1bb28b33 --- /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 0000000000..ee88eb7f30 --- /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 23/29] 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 7eae5938ff..cbf38f3083 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ImageComparingUtils.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ImageComparingUtils.cs @@ -25,7 +25,7 @@ public static void CompareWithReferenceDecoder( } 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 24/29] 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 b2be74ea14..8bac0bfd14 100644 --- a/src/ImageSharp/Formats/Pbm/PbmDecoderCore.cs +++ b/src/ImageSharp/Formats/Pbm/PbmDecoderCore.cs @@ -115,7 +115,7 @@ private void ProcessHeader(BufferedReadStream stream) 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 fe0f7f9f16..7984dddacc 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 35aa9cf8c7..5ffb49652f 100644 --- a/src/ImageSharp/Formats/Pbm/PbmFormat.cs +++ b/src/ImageSharp/Formats/Pbm/PbmFormat.cs @@ -17,7 +17,7 @@ private PbmFormat() /// /// 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 b29cd27c26..869b1b06de 100644 --- a/src/ImageSharp/Formats/Pbm/PbmMetadata.cs +++ b/src/ImageSharp/Formats/Pbm/PbmMetadata.cs @@ -11,10 +11,7 @@ public class PbmMetadata : IDeepCloneable /// /// 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 dc5350bdd9..4521f9b649 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 @@ private static void ProcessBlackAndWhite(Configuration configuration, Bu { 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 44fab1617c..2ca49a39de 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 @@ public class PbmEncoderTests }; public static readonly TheoryData PbmColorTypeFiles = - new TheoryData + new() { { BlackAndWhiteBinary, PbmColorType.BlackAndWhite }, { BlackAndWhitePlain, PbmColorType.BlackAndWhite }, @@ -67,7 +66,7 @@ public void PbmEncoder_WithPlainEncoding_PreserveBitsPerPixel(string imagePath, Encoding = PbmEncoding.Plain }; - TestFile testFile = TestFile.Create(imagePath); + var testFile = TestFile.Create(imagePath); using (Image input = testFile.CreateRgba32Image()) { using (var memStream = new MemoryStream()) From f6301d4b679cc6fa7319858a2a7a2238f45cd6a5 Mon Sep 17 00:00:00 2001 From: Ynse Hoornenborg Date: Wed, 8 Dec 2021 21:45:04 +0100 Subject: [PATCH 25/29] 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 2a171456ad..a469ced8a5 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 @@ internal class BinaryDecoder /// 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 @@ public static void Process(Configuration configuration, Buffer2D } 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 626026726b..8b32c18c2f 100644 --- a/src/ImageSharp/Formats/Pbm/BinaryEncoder.cs +++ b/src/ImageSharp/Formats/Pbm/BinaryEncoder.cs @@ -22,16 +22,16 @@ internal class BinaryEncoder /// 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 @@ public static void WritePixels(Configuration configuration, Stream strea } 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 c5c409ec8c..988d9e560e 100644 --- a/src/ImageSharp/Formats/Pbm/IPbmEncoderOptions.cs +++ b/src/ImageSharp/Formats/Pbm/IPbmEncoderOptions.cs @@ -19,8 +19,8 @@ internal interface IPbmEncoderOptions 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 0000000000..26272021ce --- /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 8bac0bfd14..749fc0292b 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 @@ internal sealed class PbmDecoderCore : IImageDecoderInternals 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 @@ internal sealed class PbmDecoderCore : IImageDecoderInternals /// 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 @@ public IImageInfo Identify(BufferedReadStream stream, CancellationToken cancella { 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 @@ private void ProcessHeader(BufferedReadStream stream) 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 @@ private void ProcessHeader(BufferedReadStream stream) 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 @@ private void ProcessPixels(BufferedReadStream stream, Buffer2D p { 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 7984dddacc..75d6660635 100644 --- a/src/ImageSharp/Formats/Pbm/PbmEncoder.cs +++ b/src/ImageSharp/Formats/Pbm/PbmEncoder.cs @@ -46,9 +46,9 @@ public sealed class PbmEncoder : IImageEncoder, IPbmEncoderOptions 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 158786e3ca..9d1f39edf3 100644 --- a/src/ImageSharp/Formats/Pbm/PbmEncoderCore.cs +++ b/src/ImageSharp/Formats/Pbm/PbmEncoderCore.cs @@ -42,7 +42,7 @@ internal sealed class PbmEncoderCore : IImageEncoderInternals /// /// Gets the maximum pixel value, per component. /// - private int maxPixelValue; + private PbmComponentType componentType; /// /// Initializes a new instance of the class. @@ -87,8 +87,11 @@ private void DeduceOptions(Image image) 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 @@ private void WriteHeader(Stream stream, byte signature, Size pixelSize) 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 @@ private void WritePixels(Stream stream, ImageFrame image) { 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 869b1b06de..a00ae46dee 100644 --- a/src/ImageSharp/Formats/Pbm/PbmMetadata.cs +++ b/src/ImageSharp/Formats/Pbm/PbmMetadata.cs @@ -11,7 +11,8 @@ public class PbmMetadata : IDeepCloneable /// /// 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 @@ private PbmMetadata(PbmMetadata other) { this.Encoding = other.Encoding; this.ColorType = other.ColorType; - this.MaxPixelValue = other.MaxPixelValue; + this.ComponentType = other.ComponentType; } /// @@ -35,9 +36,9 @@ private PbmMetadata(PbmMetadata other) 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 4521f9b649..a9e90d788d 100644 --- a/src/ImageSharp/Formats/Pbm/PlainDecoder.cs +++ b/src/ImageSharp/Formats/Pbm/PlainDecoder.cs @@ -25,13 +25,13 @@ internal class PlainDecoder /// 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 @@ public static void Process(Configuration configuration, Buffer2D } 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 8d534b7a9a..75e6f56e9e 100644 --- a/src/ImageSharp/Formats/Pbm/PlainEncoder.cs +++ b/src/ImageSharp/Formats/Pbm/PlainEncoder.cs @@ -36,13 +36,13 @@ internal class PlainEncoder /// 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 @@ public static void WritePixels(Configuration configuration, Stream strea } 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 51bf61d230..97237bca59 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 @@ public void ImageLoadCanDecode(string imagePath, PbmColorType expectedColorType) // 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 @@ public void ImageLoadRgb24CanDecode(string imagePath) } [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 00b4f443dd..7915d224a9 100644 --- a/tests/ImageSharp.Tests/Formats/Pbm/PbmMetadataTests.cs +++ b/tests/ImageSharp.Tests/Formats/Pbm/PbmMetadataTests.cs @@ -20,8 +20,10 @@ public void CloneIsDeep() 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 @@ public void Identify_DetectsCorrectColorType(string imagePath, PbmColorType expe } [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 @@ public void Identify_DetectsCorrectMaxPixelValue(string imagePath, int expectedM Assert.NotNull(imageInfo); PbmMetadata bitmapMetadata = imageInfo.Metadata.GetPbmMetadata(); Assert.NotNull(bitmapMetadata); - Assert.Equal(expectedMaxPixelValue, bitmapMetadata.MaxPixelValue); + Assert.Equal(expectedComponentType, bitmapMetadata.ComponentType); } } } From 749452503b6a7f638a1adf31b391a577569c4080 Mon Sep 17 00:00:00 2001 From: Ynse Hoornenborg Date: Fri, 10 Dec 2021 13:25:14 +0100 Subject: [PATCH 26/29] 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 75e6f56e9e..2868922ea5 100644 --- a/src/ImageSharp/Formats/Pbm/PlainEncoder.cs +++ b/src/ImageSharp/Formats/Pbm/PlainEncoder.cs @@ -66,6 +66,9 @@ public static void WritePixels(Configuration configuration, Stream strea { 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 2ca49a39de..e9b496ce44 100644 --- a/tests/ImageSharp.Tests/Formats/Pbm/PbmEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Pbm/PbmEncoderTests.cs @@ -72,7 +72,13 @@ public void PbmEncoder_WithPlainEncoding_PreserveBitsPerPixel(string imagePath, 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 27/29] 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 62cef176de..c00e4affe4 100644 --- a/src/ImageSharp/Formats/Pbm/PbmDecoder.cs +++ b/src/ImageSharp/Formats/Pbm/PbmDecoder.cs @@ -54,9 +54,8 @@ public Task> DecodeAsync(Configuration configuration, Stre } /// - 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 @@ public IImageInfo Identify(Configuration configuration, Stream stream) } /// - 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 28/29] 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 c00e4affe4..2eebbb1d93 100644 --- a/src/ImageSharp/Formats/Pbm/PbmDecoder.cs +++ b/src/ImageSharp/Formats/Pbm/PbmDecoder.cs @@ -54,8 +54,9 @@ public Task> DecodeAsync(Configuration configuration, Stre } /// - 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 29/29] 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 a469ced8a5..33af30434c 100644 --- a/src/ImageSharp/Formats/Pbm/BinaryDecoder.cs +++ b/src/ImageSharp/Formats/Pbm/BinaryDecoder.cs @@ -73,7 +73,7 @@ private static void ProcessGrayscale(Configuration configuration, Buffer 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 @@ private static void ProcessWideGrayscale(Configuration configuration, Bu 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 @@ private static void ProcessRgb(Configuration configuration, Buffer2D pixelSpan = pixels.GetRowSpan(y); + Span pixelSpan = pixels.DangerousGetRowSpan(y); PixelOperations.Instance.FromRgb24Bytes( configuration, rowSpan, @@ -139,7 +139,7 @@ private static void ProcessWideRgb(Configuration configuration, Buffer2D 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 @@ private static void ProcessBlackAndWhite(Configuration configuration, Bu } } - 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 8b32c18c2f..332ab9b50d 100644 --- a/src/ImageSharp/Formats/Pbm/BinaryEncoder.cs +++ b/src/ImageSharp/Formats/Pbm/BinaryEncoder.cs @@ -62,13 +62,14 @@ private static void WriteGrayscale(Configuration configuration, Stream s { 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 @@ private static void WriteWideGrayscale(Configuration configuration, Stre 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 @@ private static void WriteRgb(Configuration configuration, Stream stream, 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 @@ private static void WriteWideRgb(Configuration configuration, Stream str 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 @@ private static void WriteBlackAndWhite(Configuration configuration, Stre { 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 @@ private static void WriteBlackAndWhite(Configuration configuration, Stre 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 a9e90d788d..aeb527dd20 100644 --- a/src/ImageSharp/Formats/Pbm/PlainDecoder.cs +++ b/src/ImageSharp/Formats/Pbm/PlainDecoder.cs @@ -75,7 +75,7 @@ private static void ProcessGrayscale(Configuration configuration, Buffer rowSpan[x] = new L8(value); } - Span pixelSpan = pixels.GetRowSpan(y); + Span pixelSpan = pixels.DangerousGetRowSpan(y); PixelOperations.Instance.FromL8( configuration, rowSpan, @@ -101,7 +101,7 @@ private static void ProcessWideGrayscale(Configuration configuration, Bu rowSpan[x] = new L16(value); } - Span pixelSpan = pixels.GetRowSpan(y); + Span pixelSpan = pixels.DangerousGetRowSpan(y); PixelOperations.Instance.FromL16( configuration, rowSpan, @@ -131,7 +131,7 @@ private static void ProcessRgb(Configuration configuration, Buffer2D pixelSpan = pixels.GetRowSpan(y); + Span pixelSpan = pixels.DangerousGetRowSpan(y); PixelOperations.Instance.FromRgb24( configuration, rowSpan, @@ -161,7 +161,7 @@ private static void ProcessWideRgb(Configuration configuration, Buffer2D 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 @@ private static void ProcessBlackAndWhite(Configuration configuration, Bu 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 2868922ea5..a64ae38a74 100644 --- a/src/ImageSharp/Formats/Pbm/PlainEncoder.cs +++ b/src/ImageSharp/Formats/Pbm/PlainEncoder.cs @@ -76,6 +76,7 @@ private static void WriteGrayscale(Configuration configuration, Stream s { 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 @@ private static void WriteGrayscale(Configuration configuration, Stream s 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 @@ private static void WriteWideGrayscale(Configuration configuration, Stre { 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 @@ private static void WriteWideGrayscale(Configuration configuration, Stre 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 @@ private static void WriteRgb(Configuration configuration, Stream stream, { 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 @@ private static void WriteRgb(Configuration configuration, Stream stream, 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 @@ private static void WriteWideRgb(Configuration configuration, Stream str { 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 @@ private static void WriteWideRgb(Configuration configuration, Stream str 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 @@ private static void WriteBlackAndWhite(Configuration configuration, Stre { 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 @@ private static void WriteBlackAndWhite(Configuration configuration, Stre 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 4de1b9a19d..1801d6b590 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ImageComparingUtils.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ImageComparingUtils.cs @@ -8,9 +8,9 @@ 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,