예제 #1
0
        /// <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);
            }
        }
예제 #2
0
        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");
                }
            }
        }