diff --git a/src/ImageSharp/Formats/Pbm/BinaryDecoder.cs b/src/ImageSharp/Formats/Pbm/BinaryDecoder.cs index d49633575..f62928234 100644 --- a/src/ImageSharp/Formats/Pbm/BinaryDecoder.cs +++ b/src/ImageSharp/Formats/Pbm/BinaryDecoder.cs @@ -152,7 +152,6 @@ internal class BinaryDecoder { 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,12 @@ internal class BinaryDecoder for (int x = 0; x < width;) { int raw = stream.ReadByte(); - int bit = startBit; - startBit = 0; - for (; 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; x++; - if (x == width) - { - startBit = (bit + 1) & 7; // Round off to below 8. - if (startBit != 0) - { - stream.Seek(-1, System.IO.SeekOrigin.Current); - } - - break; - } } } diff --git a/src/ImageSharp/Formats/Pbm/BinaryEncoder.cs b/src/ImageSharp/Formats/Pbm/BinaryEncoder.cs index b179c775c..dddc629b3 100644 --- a/src/ImageSharp/Formats/Pbm/BinaryEncoder.cs +++ b/src/ImageSharp/Formats/Pbm/BinaryEncoder.cs @@ -33,10 +33,14 @@ internal class BinaryEncoder { 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 @@ internal class BinaryEncoder { 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."); + } } } @@ -164,8 +179,6 @@ internal class BinaryEncoder 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 = pixelBuffer.DangerousGetRowSpan(y); @@ -177,8 +190,9 @@ internal class BinaryEncoder for (int x = 0; x < width;) { - int value = previousValue; - for (int i = startBit; i < 8; i++) + int value = 0; + int stopBit = Math.Min(8, width - x); + for (int i = 0; i < stopBit; i++) { if (rowSpan[x].PackedValue < 128) { @@ -186,19 +200,9 @@ internal class BinaryEncoder } x++; - 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); } } } diff --git a/src/ImageSharp/Formats/Tiff/Compression/Decompressors/T6BitReader.cs b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/T6BitReader.cs index 8be0939d3..ea0309487 100644 --- a/src/ImageSharp/Formats/Tiff/Compression/Decompressors/T6BitReader.cs +++ b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/T6BitReader.cs @@ -125,13 +125,29 @@ internal sealed class T6BitReader : T4BitReader if (value == Len7Code0000000.Code) { this.Code = Len7Code0000000; - return false; + + // We do not support Extensions1D codes, but some encoders (scanner from epson) write a premature EOL code, + // which at this point cannot be distinguished from the marker, because we read the data bit by bit. + // Read the next 5 bit, if its a EOL code return true, indicating its the end of the image. + if (this.ReadValue(5) == 1) + { + return true; + } + + throw new NotSupportedException("ccitt extensions 1D codes are not supported."); } if (value == Len7Code0000001.Code) { this.Code = Len7Code0000001; - return false; + + // Same as above, we do not support Extensions2D codes, but it could be a EOL instead. + if (this.ReadValue(5) == 1) + { + return true; + } + + throw new NotSupportedException("ccitt extensions 2D codes are not supported."); } if (value == Len7Code0000011.Code) diff --git a/tests/ImageSharp.Tests/Formats/Pbm/PbmDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Pbm/PbmDecoderTests.cs index 5bdab7b37..1b57663f3 100644 --- a/tests/ImageSharp.Tests/Formats/Pbm/PbmDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Pbm/PbmDecoderTests.cs @@ -81,6 +81,7 @@ public class PbmDecoderTests [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 a0a4c1164..05f1d963b 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 class PbmEncoderTests 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 d62ba53a0..dd1e9f968 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -1041,5 +1041,6 @@ public static class TestImages 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 000000000..e8a70e6b4 --- /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 000000000..0123c65ee --- /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