예제 #1
0
        /// <inheritdoc />
        public ValueTask InvokeAsync(TiffImageDecoderContext context, ITiffImageDecoderPipelineNode next)
        {
            if (context is null)
            {
                throw new ArgumentNullException(nameof(context));
            }
            if (next is null)
            {
                throw new ArgumentNullException(nameof(next));
            }

            int  bitCount = _bitCount;
            bool isHigherOrderBitsFirst = _fillOrder != TiffFillOrder.LowerOrderBitsFirst;

            int                 bytesPerScanline = (context.SourceImageSize.Width * bitCount + 7) / 8;
            Memory <byte>       source           = context.UncompressedData.Slice(context.SourceReadOffset.Y * bytesPerScanline);
            ReadOnlySpan <byte> sourceSpan       = source.Span;

            using TiffPixelBufferWriter <TiffGray16> writer = context.GetWriter <TiffGray16>();

            int rows = context.ReadSize.Height;
            int cols = context.ReadSize.Width;

            // BitReader.Read reads bytes in big-endian way, we only need to reverse the endianness if the source is little-endian.
            bool reverseEndianness = context.IsLittleEndian && bitCount % 8 == 0;
            bool canDoFastPath     = bitCount >= 16 && !reverseEndianness;

            for (int row = 0; row < rows; row++)
            {
                using TiffPixelSpanHandle <TiffGray16> pixelSpanHandle = writer.GetRowSpan(row);
                Span <TiffGray16> pixelSpan = pixelSpanHandle.GetSpan();
                var bitReader = new BitReader(sourceSpan.Slice(0, bytesPerScanline), isHigherOrderBitsFirst);
                bitReader.Advance(context.SourceReadOffset.X * bitCount);

                if (canDoFastPath)
                {
                    // Fast path for bits >= 16
                    for (int col = 0; col < cols; col++)
                    {
                        uint value = bitReader.Read(bitCount);
                        value          = FastExpandBits(value, bitCount, 32);
                        pixelSpan[col] = new TiffGray16((ushort)(~value >> 16));
                    }
                }
                else
                {
                    // Slow path
                    for (int col = 0; col < cols; col++)
                    {
                        uint value = bitReader.Read(bitCount);
                        value          = (uint)ExpandBits(value, bitCount, 32, reverseEndianness);
                        pixelSpan[col] = new TiffGray16((ushort)(~value >> 16));
                    }
                }

                sourceSpan = sourceSpan.Slice(bytesPerScanline);
            }

            return(next.RunAsync(context));
        }
예제 #2
0
        public void TestGray16()
        {
            Assert.Equal(2, Unsafe.SizeOf <TiffGray16>());

            var defaultPixel = default(TiffGray16);

            Assert.Equal(0, defaultPixel.Intensity);

            var pixel1 = new TiffGray16(0x1234);

            Assert.Equal(0x1234, pixel1.Intensity);

            Assert.False(pixel1.Equals(defaultPixel));
            Assert.False(defaultPixel.Equals(pixel1));
            Assert.False(pixel1 == defaultPixel);
            Assert.False(defaultPixel == pixel1);
            Assert.True(pixel1 != defaultPixel);
            Assert.True(defaultPixel != pixel1);
            Assert.False(pixel1.GetHashCode() == defaultPixel.GetHashCode());

            var pixel2 = new TiffGray16(0x1234);

            Assert.True(pixel1.Equals(pixel2));
            Assert.True(pixel2.Equals(pixel1));
            Assert.True(pixel1 == pixel2);
            Assert.True(pixel2 == pixel1);
            Assert.False(pixel1 != pixel2);
            Assert.False(pixel2 != pixel1);
            Assert.True(pixel1.GetHashCode() == pixel2.GetHashCode());
        }
예제 #3
0
        public async Task TestImageDecodeAsync(string refImage, int refIfd, int refBitDepth, string testImage, int testIfd, int testBitDepth)
        {
            const int BufferBitDepth = 16;

            // We do not support decoding into 32 bit buffer yet.
            refBitDepth  = Math.Min(refBitDepth, BufferBitDepth);
            testBitDepth = Math.Min(testBitDepth, BufferBitDepth);

            TiffStreamOffset       ifdOffset;
            TiffImageFileDirectory ifd;

            // Load reference image
            await using TiffFileReader refTiff = await TiffFileReader.OpenAsync(refImage);

            ifdOffset = refTiff.FirstImageFileDirectoryOffset;
            Assert.False(ifdOffset.IsZero);
            for (int i = 0; i < refIfd; i++)
            {
                ifd = await refTiff.ReadImageFileDirectoryAsync(ifdOffset);

                ifdOffset = ifd.NextOffset;
                Assert.False(ifdOffset.IsZero);
            }
            ifd = await refTiff.ReadImageFileDirectoryAsync(ifdOffset);

            TiffImageDecoder refDecoder = await refTiff.CreateImageDecoderAsync(ifd);

            // Load test image
            await using TiffFileReader testTiff = await TiffFileReader.OpenAsync(testImage);

            ifdOffset = testTiff.FirstImageFileDirectoryOffset;
            Assert.False(ifdOffset.IsZero);
            for (int i = 0; i < testIfd; i++)
            {
                ifd = await testTiff.ReadImageFileDirectoryAsync(ifdOffset);

                ifdOffset = ifd.NextOffset;
                Assert.False(ifdOffset.IsZero);
            }
            ifd = await testTiff.ReadImageFileDirectoryAsync(ifdOffset);

            TiffImageDecoder testDecoder = await testTiff.CreateImageDecoderAsync(ifd);

            Assert.Equal(refDecoder.Width, testDecoder.Width);
            Assert.Equal(refDecoder.Height, testDecoder.Height);

            TiffGray16[] refBuffer  = new TiffGray16[refDecoder.Width * refDecoder.Height];
            TiffGray16[] testBuffer = new TiffGray16[testDecoder.Width * testDecoder.Height];

            await refDecoder.DecodeAsync(TiffPixelBuffer.Wrap(refBuffer, refDecoder.Width, refDecoder.Height));

            await testDecoder.DecodeAsync(TiffPixelBuffer.Wrap(testBuffer, testDecoder.Width, testDecoder.Height));

            ShiftPixels(MemoryMarshal.Cast <TiffGray16, ushort>(refBuffer), BufferBitDepth - refBitDepth);
            ShiftPixels(MemoryMarshal.Cast <TiffGray16, ushort>(testBuffer), BufferBitDepth - testBitDepth);

            Assert.True(refBuffer.AsSpan().SequenceEqual(testBuffer));
        }