From 53fc42d1089ac1600ddf01af72c591d093d70b68 Mon Sep 17 00:00:00 2001 From: Ynse Hoornenborg Date: Mon, 19 Jun 2023 22:00:44 +0200 Subject: [PATCH 1/6] End each row on a byte boundary --- src/ImageSharp/Formats/Pbm/BinaryEncoder.cs | 34 +++++++++++++-------- 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/src/ImageSharp/Formats/Pbm/BinaryEncoder.cs b/src/ImageSharp/Formats/Pbm/BinaryEncoder.cs index b179c775cf..ca1e4eaa2e 100644 --- a/src/ImageSharp/Formats/Pbm/BinaryEncoder.cs +++ b/src/ImageSharp/Formats/Pbm/BinaryEncoder.cs @@ -33,10 +33,14 @@ public static void WritePixels(Configuration configuration, Stream strea { WriteGrayscale(configuration, stream, image); } - else + else if (componentType == PbmComponentType.Short) { WriteWideGrayscale(configuration, stream, image); } + else + { + throw new ImageFormatException("Component type not supported for Grayscale PBM."); + } } else if (colorType == PbmColorType.Rgb) { @@ -44,14 +48,25 @@ public static void WritePixels(Configuration configuration, Stream strea { WriteRgb(configuration, stream, image); } - else + else if (componentType == PbmComponentType.Short) { WriteWideRgb(configuration, stream, image); } + else + { + throw new ImageFormatException("Component type not supported for Color PBM."); + } } else { - WriteBlackAndWhite(configuration, stream, image); + if (componentType == PbmComponentType.Bit) + { + WriteBlackAndWhite(configuration, stream, image); + } + else + { + throw new ImageFormatException("Component type not supported for Black & White PBM."); + } } } @@ -165,7 +180,6 @@ private static void WriteBlackAndWhite(Configuration configuration, Stre Span rowSpan = row.GetSpan(); int previousValue = 0; - int startBit = 0; for (int y = 0; y < height; y++) { Span pixelSpan = pixelBuffer.DangerousGetRowSpan(y); @@ -178,7 +192,7 @@ private static void WriteBlackAndWhite(Configuration configuration, Stre for (int x = 0; x < width;) { int value = previousValue; - for (int i = startBit; i < 8; i++) + for (int i = 0; i < 8; i++) { if (rowSpan[x].PackedValue < 128) { @@ -186,19 +200,15 @@ private static void WriteBlackAndWhite(Configuration configuration, Stre } x++; + // End each row on a byte boundary. if (x == width) { - previousValue = value; - startBit = (i + 1) & 7; // Round off to below 8. break; } } - if (startBit == 0) - { - stream.WriteByte((byte)value); - previousValue = 0; - } + stream.WriteByte((byte)value); + previousValue = 0; } } } From bbc14f4ff529925a9e937168cc1ad54a6489c03e Mon Sep 17 00:00:00 2001 From: Ynse Hoornenborg Date: Wed, 21 Jun 2023 18:48:19 +0200 Subject: [PATCH 2/6] Row boundary on decode --- src/ImageSharp/Formats/Pbm/BinaryDecoder.cs | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/src/ImageSharp/Formats/Pbm/BinaryDecoder.cs b/src/ImageSharp/Formats/Pbm/BinaryDecoder.cs index d49633575d..449548f3d2 100644 --- a/src/ImageSharp/Formats/Pbm/BinaryDecoder.cs +++ b/src/ImageSharp/Formats/Pbm/BinaryDecoder.cs @@ -152,7 +152,6 @@ private static void ProcessBlackAndWhite(Configuration configuration, Bu { 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(); @@ -162,23 +161,11 @@ private static void ProcessBlackAndWhite(Configuration configuration, Bu for (int x = 0; x < width;) { int raw = stream.ReadByte(); - int bit = startBit; - startBit = 0; - for (; bit < 8; bit++) + for (int bit = 0; bit < 8; bit++) { bool bitValue = (raw & (0x80 >> bit)) != 0; rowSpan[x] = bitValue ? black : white; x++; - if (x == width) - { - startBit = (bit + 1) & 7; // Round off to below 8. - if (startBit != 0) - { - stream.Seek(-1, System.IO.SeekOrigin.Current); - } - - break; - } } } From 7e4825332b685992e8e965ed61b703125b7bdde7 Mon Sep 17 00:00:00 2001 From: Ynse Hoornenborg Date: Wed, 21 Jun 2023 19:14:21 +0200 Subject: [PATCH 3/6] Out of range fix --- src/ImageSharp/Formats/Pbm/BinaryDecoder.cs | 3 ++- src/ImageSharp/Formats/Pbm/BinaryEncoder.cs | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/ImageSharp/Formats/Pbm/BinaryDecoder.cs b/src/ImageSharp/Formats/Pbm/BinaryDecoder.cs index 449548f3d2..f629282340 100644 --- a/src/ImageSharp/Formats/Pbm/BinaryDecoder.cs +++ b/src/ImageSharp/Formats/Pbm/BinaryDecoder.cs @@ -161,7 +161,8 @@ private static void ProcessBlackAndWhite(Configuration configuration, Bu for (int x = 0; x < width;) { int raw = stream.ReadByte(); - for (int bit = 0; bit < 8; bit++) + int stopBit = Math.Min(8, width - x); + for (int bit = 0; bit < stopBit; bit++) { bool bitValue = (raw & (0x80 >> bit)) != 0; rowSpan[x] = bitValue ? black : white; diff --git a/src/ImageSharp/Formats/Pbm/BinaryEncoder.cs b/src/ImageSharp/Formats/Pbm/BinaryEncoder.cs index ca1e4eaa2e..b9bc812f0d 100644 --- a/src/ImageSharp/Formats/Pbm/BinaryEncoder.cs +++ b/src/ImageSharp/Formats/Pbm/BinaryEncoder.cs @@ -192,7 +192,8 @@ private static void WriteBlackAndWhite(Configuration configuration, Stre for (int x = 0; x < width;) { int value = previousValue; - for (int i = 0; i < 8; i++) + int stopBit = Math.Min(8, width - x); + for (int i = 0; i < stopBit; i++) { if (rowSpan[x].PackedValue < 128) { From c60cae82acbaf58e16a03869c2c1ddd9689d8ddc Mon Sep 17 00:00:00 2001 From: Ynse Hoornenborg Date: Wed, 21 Jun 2023 19:14:32 +0200 Subject: [PATCH 4/6] Tests --- tests/ImageSharp.Tests/Formats/Pbm/PbmDecoderTests.cs | 1 + tests/ImageSharp.Tests/Formats/Pbm/PbmEncoderTests.cs | 6 ++++++ tests/ImageSharp.Tests/TestImages.cs | 1 + .../PbmDecoderTests/DecodeReferenceImage_L8_issue2477.png | 3 +++ tests/Images/Input/Pbm/issue2477.pbm | 3 +++ 5 files changed, 14 insertions(+) create mode 100644 tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L8_issue2477.png create mode 100644 tests/Images/Input/Pbm/issue2477.pbm diff --git a/tests/ImageSharp.Tests/Formats/Pbm/PbmDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Pbm/PbmDecoderTests.cs index 5bdab7b37a..1b57663f3a 100644 --- a/tests/ImageSharp.Tests/Formats/Pbm/PbmDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Pbm/PbmDecoderTests.cs @@ -81,6 +81,7 @@ public void ImageLoadRgb24CanDecode(string imagePath) [Theory] [WithFile(BlackAndWhitePlain, PixelTypes.L8, "pbm")] [WithFile(BlackAndWhiteBinary, PixelTypes.L8, "pbm")] + [WithFile(Issue2477, PixelTypes.L8, "pbm")] [WithFile(GrayscalePlain, PixelTypes.L8, "pgm")] [WithFile(GrayscalePlainNormalized, PixelTypes.L8, "pgm")] [WithFile(GrayscaleBinary, PixelTypes.L8, "pgm")] diff --git a/tests/ImageSharp.Tests/Formats/Pbm/PbmEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Pbm/PbmEncoderTests.cs index a0a4c1164f..05f1d963b2 100644 --- a/tests/ImageSharp.Tests/Formats/Pbm/PbmEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Pbm/PbmEncoderTests.cs @@ -26,6 +26,7 @@ public class PbmEncoderTests { { BlackAndWhiteBinary, PbmColorType.BlackAndWhite }, { BlackAndWhitePlain, PbmColorType.BlackAndWhite }, + { Issue2477, PbmColorType.BlackAndWhite }, { GrayscaleBinary, PbmColorType.Grayscale }, { GrayscaleBinaryWide, PbmColorType.Grayscale }, { GrayscalePlain, PbmColorType.Grayscale }, @@ -96,6 +97,11 @@ public void PbmEncoder_P1_Works(TestImageProvider provider) public void PbmEncoder_P4_Works(TestImageProvider provider) where TPixel : unmanaged, IPixel => TestPbmEncoderCore(provider, PbmColorType.BlackAndWhite, PbmEncoding.Binary); + [Theory] + [WithFile(Issue2477, PixelTypes.Rgb24)] + public void PbmEncoder_P4_Irregular_Works(TestImageProvider provider) + where TPixel : unmanaged, IPixel => TestPbmEncoderCore(provider, PbmColorType.BlackAndWhite, PbmEncoding.Binary); + [Theory] [WithFile(GrayscalePlainMagick, PixelTypes.Rgb24)] public void PbmEncoder_P2_Works(TestImageProvider provider) diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index 39b8c95a9c..c4eb866c7c 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -1038,5 +1038,6 @@ public static class Pbm 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"; + public const string Issue2477 = "Pbm/issue2477.pbm"; } } diff --git a/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L8_issue2477.png b/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L8_issue2477.png new file mode 100644 index 0000000000..e8a70e6b41 --- /dev/null +++ b/tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L8_issue2477.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:670bc844ba878afa0f03574dea23ab774ac0cc5aa371d0f4b4dff7da4d32f916 +size 2912 diff --git a/tests/Images/Input/Pbm/issue2477.pbm b/tests/Images/Input/Pbm/issue2477.pbm new file mode 100644 index 0000000000..0123c65ee2 --- /dev/null +++ b/tests/Images/Input/Pbm/issue2477.pbm @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d625635f7be760fbea935056c0f6d046832dd74bba33a1597b52ab3dfe0c5e4e +size 4956 From eab151fada473198f4f722ec2384677ba917b573 Mon Sep 17 00:00:00 2001 From: Ynse Hoornenborg Date: Wed, 21 Jun 2023 19:20:45 +0200 Subject: [PATCH 5/6] Style fix --- src/ImageSharp/Formats/Pbm/BinaryEncoder.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ImageSharp/Formats/Pbm/BinaryEncoder.cs b/src/ImageSharp/Formats/Pbm/BinaryEncoder.cs index b9bc812f0d..abb6d2fca1 100644 --- a/src/ImageSharp/Formats/Pbm/BinaryEncoder.cs +++ b/src/ImageSharp/Formats/Pbm/BinaryEncoder.cs @@ -201,6 +201,7 @@ private static void WriteBlackAndWhite(Configuration configuration, Stre } x++; + // End each row on a byte boundary. if (x == width) { From 4c70682d09f26e29768a53786dce4df98823b8b0 Mon Sep 17 00:00:00 2001 From: Ynse Hoornenborg Date: Wed, 21 Jun 2023 22:33:08 +0200 Subject: [PATCH 6/6] Simplify code --- src/ImageSharp/Formats/Pbm/BinaryEncoder.cs | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/ImageSharp/Formats/Pbm/BinaryEncoder.cs b/src/ImageSharp/Formats/Pbm/BinaryEncoder.cs index abb6d2fca1..dddc629b3e 100644 --- a/src/ImageSharp/Formats/Pbm/BinaryEncoder.cs +++ b/src/ImageSharp/Formats/Pbm/BinaryEncoder.cs @@ -179,7 +179,6 @@ private static void WriteBlackAndWhite(Configuration configuration, Stre using IMemoryOwner row = allocator.Allocate(width); Span rowSpan = row.GetSpan(); - int previousValue = 0; for (int y = 0; y < height; y++) { Span pixelSpan = pixelBuffer.DangerousGetRowSpan(y); @@ -191,7 +190,7 @@ private static void WriteBlackAndWhite(Configuration configuration, Stre for (int x = 0; x < width;) { - int value = previousValue; + int value = 0; int stopBit = Math.Min(8, width - x); for (int i = 0; i < stopBit; i++) { @@ -201,16 +200,9 @@ private static void WriteBlackAndWhite(Configuration configuration, Stre } x++; - - // End each row on a byte boundary. - if (x == width) - { - break; - } } stream.WriteByte((byte)value); - previousValue = 0; } } }