Esempio n. 1
0
        public void TestUnalignedReadHigherOrderBitsFirst()
        {
            byte[] data      = new byte[] { 0x12, 0x23, 0x34, 0x45, 0x56, 0x67, 0x78, 0x89, 0x9a, 0xab, 0xbc };
            var    bitReader = new BitReader(data);

            Assert.Equal((uint)0, bitReader.Peek(1));
            Assert.Equal(0, bitReader.ConsumedBits);
            Assert.Equal(0, bitReader.ConsumedBytes);
            Assert.Equal((uint)0, bitReader.Read(1));
            Assert.Equal(1, bitReader.ConsumedBits);
            Assert.Equal(1, bitReader.ConsumedBytes);

            Assert.Equal((uint)0, bitReader.Read(2));
            Assert.Equal(3, bitReader.ConsumedBits);
            Assert.Equal(1, bitReader.ConsumedBytes);

            Assert.Equal((uint)0b100, bitReader.Peek(3));
            Assert.Equal((uint)0b100, bitReader.Read(3));
            Assert.Equal(6, bitReader.ConsumedBits);
            Assert.Equal(1, bitReader.ConsumedBytes);

            Assert.Equal((uint)0b10001, bitReader.Peek(5));
            bitReader.AdvanceAlignByte();
            Assert.Equal(8, bitReader.ConsumedBits);
            Assert.Equal(1, bitReader.ConsumedBytes);

            Assert.Equal((uint)0b001000, bitReader.Read(6));
            Assert.Equal((uint)0b1100110, bitReader.Read(7));
            Assert.Equal((uint)0b10001000, bitReader.Read(8));
            Assert.Equal((uint)0b101, bitReader.Peek(3));
            Assert.Equal(29, bitReader.ConsumedBits);

            Assert.Equal((uint)0b1010101011, bitReader.Peek(10));
            Assert.Equal((uint)0b101010, bitReader.Read(6));
            Assert.Equal((uint)0b10110011, bitReader.Peek(8));
            Assert.Equal(35, bitReader.ConsumedBits);

            bitReader.AdvanceAlignByte();

            Assert.Equal(40, bitReader.ConsumedBits);
            Assert.Equal(5, bitReader.ConsumedBytes);

            Assert.Equal((uint)0x6778899a, bitReader.Peek(32));
            Assert.Equal((uint)0b01100, bitReader.Read(5));

            Assert.Equal(0b111_01111000_10001001_10011010_10101, (uint)bitReader.Read(32));
            bitReader.AdvanceAlignByte();
            Assert.Equal(80, bitReader.ConsumedBits);
            Assert.Equal(10, bitReader.ConsumedBytes);

            Assert.Equal((uint)0xbc, bitReader.Peek(8));
            Assert.Equal((uint)0xbc00, bitReader.Peek(16));
        }
Esempio n. 2
0
        public void TestAlignedAdvanceByte()
        {
            byte[] data      = new byte[] { 0xab, 0xcd, 0xef };
            var    bitReader = new BitReader(data);

            bitReader.Read(8);
            bitReader.AdvanceAlignByte();
            Assert.Equal(1, bitReader.ConsumedBytes);
            Assert.Equal(8, bitReader.ConsumedBits);
            Assert.Equal((uint)0xcd, bitReader.Read(8));
        }
Esempio n. 3
0
        /// <inheritdoc />
        public void Decompress(TiffDecompressionContext context, ReadOnlyMemory <byte> input, Memory <byte> output)
        {
            if (context is null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            if (context.PhotometricInterpretation != TiffPhotometricInterpretation.WhiteIsZero && context.PhotometricInterpretation != TiffPhotometricInterpretation.BlackIsZero)
            {
                throw new NotSupportedException("T4 compression does not support this photometric interpretation.");
            }

            if (context.BitsPerSample.Count != 1 || context.BitsPerSample[0] != 1)
            {
                throw new NotSupportedException("Unsupported bits per sample.");
            }

            ReadOnlySpan <byte> inputSpan           = input.Span;
            Span <byte>         scanlinesBufferSpan = output.Span;

            bool whiteIsZero = context.PhotometricInterpretation == TiffPhotometricInterpretation.WhiteIsZero;
            int  width       = context.ImageSize.Width;
            int  height      = context.SkippedScanlines + context.RequestedScanlines;
            var  bitReader   = new BitReader(inputSpan, higherOrderBitsFirst: _higherOrderBitsFirst);

            // Skip the first EOL code
            if (bitReader.Peek(12) == 0b000000000001) // EOL code is 000000000001 (12bits).
            {
                bitReader.Advance(12);
            }
            else if (bitReader.Peek(16) == 1) // Or EOL code is zero filled.
            {
                bitReader.Advance(16);
            }

            // Process every scanline
            for (int i = 0; i < height; i++)
            {
                if (scanlinesBufferSpan.Length < width)
                {
                    throw new InvalidDataException();
                }
                Span <byte> scanline = scanlinesBufferSpan.Slice(0, width);
                scanlinesBufferSpan = scanlinesBufferSpan.Slice(width);

                // Process every code word in this scanline
                byte fillValue = whiteIsZero ? (byte)0 : (byte)255;
                CcittDecodingTable currentTable = CcittDecodingTable.WhiteInstance;
                CcittDecodingTable otherTable   = CcittDecodingTable.BlackInstance;
                int            unpacked         = 0;
                CcittCodeValue tableEntry;
                while (true)
                {
                    uint value = bitReader.Peek(16);
                    if (!currentTable.TryLookup(value, out tableEntry))
                    {
                        throw new InvalidDataException();
                    }

                    if (tableEntry.IsEndOfLine)
                    {
                        // fill the rest of scanline
                        scanline.Fill(fillValue);
                        bitReader.Advance(tableEntry.BitsRequired);
                        break;
                    }

                    // Check to see whether we are encountering a "filled" EOL ?
                    if ((value & 0b1111111111110000) == 0)
                    {
                        // Align to 8 bits
                        int filledBits = 8 - (bitReader.ConsumedBits + 12) % 8;
                        if (bitReader.Peek(filledBits) != 0)
                        {
                            throw new InvalidDataException();
                        }

                        // Confirm it is indeed an EOL code.
                        value = bitReader.Read(filledBits + 12);
                        if (value == 0b000000000001)
                        {
                            // fill the rest of scanline
                            scanline.Fill(fillValue);
                            break;
                        }

                        throw new InvalidDataException();
                    }

                    // Process normal code.
                    int runLength = tableEntry.RunLength;
                    scanline.Slice(0, runLength).Fill(fillValue);
                    scanline  = scanline.Slice(runLength);
                    unpacked += runLength;
                    bitReader.Advance(tableEntry.BitsRequired);

                    // Terminating code is met. Switch to the other color.
                    if (tableEntry.IsTerminatingCode)
                    {
                        fillValue = (byte)~fillValue;
                        CcittHelper.SwapTable(ref currentTable, ref otherTable);

                        // This line is fully unpacked. Should exit and process next line.
                        if (unpacked == width)
                        {
                            // If this is the last line of the image, we don't process any code after this.
                            if (i == height - 1)
                            {
                                break;
                            }

                            // Is the next code word EOL ?
                            value = bitReader.Peek(16);
                            if ((value >> 4) == 0b000000000001)
                            {
                                // Skip the EOL code
                                bitReader.Advance(12);
                                break;
                            }

                            // Maybe the EOL is zero filled? First align to 8 bits
                            int filledBits = 8 - (bitReader.ConsumedBits + 12) % 8;
                            if (bitReader.Peek(filledBits) != 0)
                            {
                                bitReader.AdvanceAlignByte();
                                break;
                            }

                            // Confirm it is indeed an EOL code.
                            value = bitReader.Peek(filledBits + 12);
                            if (value == 0b000000000001)
                            {
                                bitReader.Advance(filledBits + 12);
                            }

                            bitReader.AdvanceAlignByte();
                            break;
                        }
                    }
                }
            }
        }
        /// <inheritdoc />
        public void Decompress(TiffDecompressionContext context, ReadOnlyMemory <byte> input, Memory <byte> output)
        {
            if (context is null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            if (context.PhotometricInterpretation != TiffPhotometricInterpretation.WhiteIsZero && context.PhotometricInterpretation != TiffPhotometricInterpretation.BlackIsZero)
            {
                throw new NotSupportedException("Modified Huffman compression does not support this photometric interpretation.");
            }

            if (context.BitsPerSample.Count != 1 || context.BitsPerSample[0] != 1)
            {
                throw new NotSupportedException("Unsupported bits per sample.");
            }

            ReadOnlySpan <byte> inputSpan           = input.Span;
            Span <byte>         scanlinesBufferSpan = output.Span;

            bool whiteIsZero = context.PhotometricInterpretation == TiffPhotometricInterpretation.WhiteIsZero;
            int  width       = context.ImageSize.Width;
            int  height      = context.SkippedScanlines + context.RequestedScanlines;
            var  bitReader   = new BitReader(inputSpan, higherOrderBitsFirst: _higherOrderBitsFirst);

            // Process every scanline
            for (int i = 0; i < height; i++)
            {
                if (scanlinesBufferSpan.Length < width)
                {
                    throw new InvalidDataException();
                }
                Span <byte> scanline = scanlinesBufferSpan.Slice(0, width);
                scanlinesBufferSpan = scanlinesBufferSpan.Slice(width);

                // Process every code word in this scanline
                byte fillValue = whiteIsZero ? (byte)0 : (byte)255;
                CcittDecodingTable currentTable = CcittDecodingTable.WhiteInstance;
                CcittDecodingTable otherTable   = CcittDecodingTable.BlackInstance;
                int unpacked = 0;
                while (true)
                {
                    if (!currentTable.TryLookup(bitReader.Peek(16), out CcittCodeValue tableEntry))
                    {
                        throw new InvalidDataException();
                    }

                    if (tableEntry.IsEndOfLine)
                    {
                        // EOL code is not used in modified huffman algorithm
                        throw new InvalidDataException();
                    }

                    // Process normal code.
                    int runLength = tableEntry.RunLength;
                    scanline.Slice(0, runLength).Fill(fillValue);
                    scanline  = scanline.Slice(runLength);
                    unpacked += runLength;
                    bitReader.Advance(tableEntry.BitsRequired);

                    // Terminating code is met. Switch to the other color.
                    if (tableEntry.IsTerminatingCode)
                    {
                        fillValue = (byte)~fillValue;
                        CcittHelper.SwapTable(ref currentTable, ref otherTable);

                        // This line is fully unpacked. Should exit and process next line.
                        if (unpacked == width)
                        {
                            break;
                        }
                    }
                }

                bitReader.AdvanceAlignByte();
            }
        }