/// <inheritdoc/> protected override void Decompress(BufferedReadStream stream, int byteCount, int stripHeight, Span <byte> buffer) { int height = stripHeight; using System.Buffers.IMemoryOwner <byte> scanLineBuffer = this.Allocator.Allocate <byte>(this.width * 2); Span <byte> scanLine = scanLineBuffer.GetSpan().Slice(0, this.width); Span <byte> referenceScanLineSpan = scanLineBuffer.GetSpan().Slice(this.width, this.width); using var bitReader = new T6BitReader(stream, this.FillOrder, byteCount, this.Allocator); var referenceScanLine = new CcittReferenceScanline(this.isWhiteZero, this.width); uint bitsWritten = 0; for (int y = 0; y < height; y++) { scanLine.Fill(0); Decode2DScanline(bitReader, this.isWhiteZero, referenceScanLine, scanLine); bitsWritten = this.WriteScanLine(buffer, scanLine, bitsWritten); scanLine.CopyTo(referenceScanLineSpan); referenceScanLine = new CcittReferenceScanline(this.isWhiteZero, referenceScanLineSpan); } }
private static void Decode2DScanline(T6BitReader bitReader, bool whiteIsZero, CcittReferenceScanline referenceScanline, Span <byte> scanline) { int width = scanline.Length; bitReader.StartNewRow(); // 2D Encoding variables. int a0 = -1; byte fillByte = whiteIsZero ? (byte)0 : (byte)255; // Process every code word in this scanline. int unpacked = 0; while (true) { // Read next code word and advance pass it. bool isEol = bitReader.ReadNextCodeWord(); // Special case handling for EOL. if (isEol) { // If a TIFF reader encounters EOFB before the expected number of lines has been extracted, // it is appropriate to assume that the missing rows consist entirely of white pixels. scanline.Fill(whiteIsZero ? (byte)0 : (byte)255); break; } // Update 2D Encoding variables. int b1 = referenceScanline.FindB1(a0, fillByte); // Switch on the code word. int a1; switch (bitReader.Code.Type) { case CcittTwoDimensionalCodeType.None: TiffThrowHelper.ThrowImageFormatException("ccitt compression parsing error, could not read a valid code word."); break; case CcittTwoDimensionalCodeType.Pass: int b2 = referenceScanline.FindB2(b1); scanline.Slice(unpacked, b2 - unpacked).Fill(fillByte); unpacked = b2; a0 = b2; break; case CcittTwoDimensionalCodeType.Horizontal: // Decode M(a0a1) bitReader.ReadNextRun(); int runLength = (int)bitReader.RunLength; if (runLength > (uint)(scanline.Length - unpacked)) { TiffThrowHelper.ThrowImageFormatException("ccitt compression parsing error"); } scanline.Slice(unpacked, runLength).Fill(fillByte); unpacked += runLength; fillByte = (byte)~fillByte; // Decode M(a1a2) bitReader.ReadNextRun(); runLength = (int)bitReader.RunLength; if (runLength > (uint)(scanline.Length - unpacked)) { TiffThrowHelper.ThrowImageFormatException("ccitt compression parsing error"); } scanline.Slice(unpacked, runLength).Fill(fillByte); unpacked += runLength; fillByte = (byte)~fillByte; // Prepare next a0 a0 = unpacked; break; case CcittTwoDimensionalCodeType.Vertical0: a1 = b1; scanline.Slice(unpacked, a1 - unpacked).Fill(fillByte); unpacked = a1; a0 = a1; fillByte = (byte)~fillByte; bitReader.SwapColor(); break; case CcittTwoDimensionalCodeType.VerticalR1: a1 = b1 + 1; scanline.Slice(unpacked, a1 - unpacked).Fill(fillByte); unpacked = a1; a0 = a1; fillByte = (byte)~fillByte; bitReader.SwapColor(); break; case CcittTwoDimensionalCodeType.VerticalR2: a1 = b1 + 2; scanline.Slice(unpacked, a1 - unpacked).Fill(fillByte); unpacked = a1; a0 = a1; fillByte = (byte)~fillByte; bitReader.SwapColor(); break; case CcittTwoDimensionalCodeType.VerticalR3: a1 = b1 + 3; scanline.Slice(unpacked, a1 - unpacked).Fill(fillByte); unpacked = a1; a0 = a1; fillByte = (byte)~fillByte; bitReader.SwapColor(); break; case CcittTwoDimensionalCodeType.VerticalL1: a1 = b1 - 1; scanline.Slice(unpacked, a1 - unpacked).Fill(fillByte); unpacked = a1; a0 = a1; fillByte = (byte)~fillByte; bitReader.SwapColor(); break; case CcittTwoDimensionalCodeType.VerticalL2: a1 = b1 - 2; scanline.Slice(unpacked, a1 - unpacked).Fill(fillByte); unpacked = a1; a0 = a1; fillByte = (byte)~fillByte; bitReader.SwapColor(); break; case CcittTwoDimensionalCodeType.VerticalL3: a1 = b1 - 3; scanline.Slice(unpacked, a1 - unpacked).Fill(fillByte); unpacked = a1; a0 = a1; fillByte = (byte)~fillByte; bitReader.SwapColor(); break; default: throw new NotSupportedException("ccitt extensions are not supported."); } // This line is fully unpacked. Should exit and process next line. if (unpacked == width) { break; } if (unpacked > width) { TiffThrowHelper.ThrowImageFormatException("ccitt compression parsing error, unpacked data > width"); } } }