Example #1
0
        public void TestRgb24()
        {
            Assert.Equal(3, Unsafe.SizeOf <TiffRgb24>());

            var defaultPixel = default(TiffRgb24);

            Assert.Equal(0, defaultPixel.R);
            Assert.Equal(0, defaultPixel.G);
            Assert.Equal(0, defaultPixel.B);

            var pixel1 = new TiffRgb24(0x12, 0x34, 0x56);

            Assert.Equal(0x12, pixel1.R);
            Assert.Equal(0x34, pixel1.G);
            Assert.Equal(0x56, pixel1.B);

            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 TiffRgb24(0x12, 0x34, 0x56);

            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());
        }
        public async Task TestAsync(string reference, string test)
        {
            using var refImage = Image.Load <Rgb24>(reference);

            await using TiffFileReader tiff = await TiffFileReader.OpenAsync(test);

            TiffStreamOffset ifdOffset = tiff.FirstImageFileDirectoryOffset;

            while (!ifdOffset.IsZero)
            {
                TiffImageFileDirectory ifd = await tiff.ReadImageFileDirectoryAsync(ifdOffset);

                TiffImageDecoder decoder = await tiff.CreateImageDecoderAsync(ifd, new TiffImageDecoderOptions { UndoColorPreMultiplying = true });

                Assert.Equal(refImage.Width, decoder.Width);
                Assert.Equal(refImage.Height, decoder.Height);
                TiffRgb24[] pixels = new TiffRgb24[decoder.Width * decoder.Height];

                await decoder.DecodeAsync(TiffPixelBuffer.Wrap(pixels, decoder.Width, decoder.Height));

                AssertEqual(refImage, pixels);

                using (var image = new Image <Rgb24>(decoder.Width, decoder.Height))
                {
                    decoder.Decode(image);
                    AssertEqual(refImage, image);
                }

                ifdOffset = ifd.NextOffset;
            }
        }
        public void TestYCbCr8ToRgb24(byte y, byte cb, byte cr)
        {
            var converter = TiffYCbCrConverter8.CreateDefault();

            TiffRgb24 pixel = converter.ConvertToRgb24(y, cb, cr);

            converter.ConvertFromRgb24(pixel, out byte oy, out byte ocb, out byte ocr);
            Assert.Equal(y, oy);
            Assert.Equal(cb, ocb);
            Assert.Equal(cr, ocr);

            Span <byte> ycbcr = stackalloc byte[9];

            ycbcr[0] = y;
            ycbcr[1] = cb;
            ycbcr[2] = cr;
            ycbcr[3] = y;
            ycbcr[4] = cb;
            ycbcr[5] = cr;
            ycbcr[6] = y;
            ycbcr[7] = cb;
            ycbcr[8] = cr;

            Span <TiffRgb24> rgb       = stackalloc TiffRgb24[3];
            Span <byte>      ycbcrBack = stackalloc byte[9];

            converter.ConvertToRgb24(ycbcr, rgb, 3);
            converter.ConvertFromRgb24(rgb, ycbcrBack, 3);

            Assert.True(ycbcr.SequenceEqual(ycbcrBack));
        }
        public TiffRgb24 ConvertToRgb24(byte y, byte cb, byte cr)
        {
            CodingRangeExpander expanderY  = _expanderY;
            CodingRangeExpander expanderCb = _expanderCb;
            CodingRangeExpander expanderCr = _expanderCr;
            YCbCrToRgbConverter converter  = _converterFrom;

            float y64  = expanderY.Expand(y);
            float cb64 = expanderCb.Expand(cb);
            float cr64 = expanderCr.Expand(cr);

            TiffRgb24 pixel = default; // TODO: SkipInit

            converter.Convert(y64, cb64, cr64, ref pixel);

            return(pixel);
        }
Example #5
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 skippedRowOffset = context.SourceImageSize.Width * context.SourceReadOffset.Y;
            int planarByteCount  = context.SourceImageSize.Width * context.SourceImageSize.Height;

            ReadOnlySpan <byte> sourceSpan = context.UncompressedData.Span;
            ReadOnlySpan <byte> sourceR    = sourceSpan.Slice(0, planarByteCount);
            ReadOnlySpan <byte> sourceG    = sourceSpan.Slice(planarByteCount, planarByteCount);
            ReadOnlySpan <byte> sourceB    = sourceSpan.Slice(2 * planarByteCount, planarByteCount);

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

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

            for (int row = 0; row < rows; row++)
            {
                using TiffPixelSpanHandle <TiffRgb24> pixelSpanHandle = writer.GetRowSpan(row);
                Span <TiffRgb24> rowDestinationSpan = pixelSpanHandle.GetSpan();
                int rowOffset = skippedRowOffset + row * context.SourceImageSize.Width + context.SourceReadOffset.X;
                for (int col = 0; col < cols; col++)
                {
                    int componentOffset = rowOffset + col;
                    rowDestinationSpan[col] = new TiffRgb24(sourceR[componentOffset], sourceG[componentOffset], sourceB[componentOffset]);
                }
            }

            return(next.RunAsync(context));
        }
Example #6
0
        private static void ProcessAssociatedPreservingColorPreMultiplying(TiffImageDecoderContext context)
        {
            int                 bytesPerScanline = 4 * context.SourceImageSize.Width;
            Memory <byte>       source           = context.UncompressedData.Slice(context.SourceReadOffset.Y * bytesPerScanline);
            ReadOnlySpan <byte> sourceSpan       = source.Span;

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

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

            for (int row = 0; row < rows; row++)
            {
                using TiffPixelSpanHandle <TiffRgb24> pixelSpanHandle = writer.GetRowSpan(row);
                ReadOnlySpan <TiffRgba32> rowSourceSpan      = MemoryMarshal.Cast <byte, TiffRgba32>(sourceSpan.Slice(4 * context.SourceReadOffset.X, 4 * context.ReadSize.Width));
                Span <TiffRgb24>          rowDestinationSpan = pixelSpanHandle.GetSpan();

                for (int col = 0; col < cols; col++)
                {
                    TiffRgba32 pixel = rowSourceSpan[col];
                    TiffRgb24  pixel24;
                    byte       a = pixel.A;
                    if (a == 0)
                    {
                        pixel24 = default;
                    }
                    else
                    {
                        pixel24 = new TiffRgb24((byte)(pixel.R * 255 / a), (byte)(pixel.G * 255 / a), (byte)(pixel.B * 255 / a));
                    }
                    rowDestinationSpan[col] = pixel24;
                }

                sourceSpan = sourceSpan.Slice(bytesPerScanline);
            }
        }
        /// <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));
            }

            Span <ushort> bitsPerSample = stackalloc ushort[3];

            _bitsPerSample.CopyTo(bitsPerSample);
            bool isHigherOrderBitsFirst = _fillOrder != TiffFillOrder.LowerOrderBitsFirst;
            bool canDoFastPath          = bitsPerSample[0] >= 4 && bitsPerSample[1] >= 4 && bitsPerSample[2] >= 4;
            int  totalBitsPerSample     = bitsPerSample[0] + bitsPerSample[1] + bitsPerSample[2];

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

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

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

            TiffRgb24 pixel = default;

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

                if (canDoFastPath)
                {
                    // Fast path for bits >= 8
                    for (int col = 0; col < cols; col++)
                    {
                        pixel.R        = (byte)FastExpandBits(bitReader.Read(bitsPerSample[0]), bitsPerSample[0], 8);
                        pixel.G        = (byte)FastExpandBits(bitReader.Read(bitsPerSample[1]), bitsPerSample[1], 8);
                        pixel.B        = (byte)FastExpandBits(bitReader.Read(bitsPerSample[2]), bitsPerSample[2], 8);
                        pixelSpan[col] = pixel;
                    }
                }
                else
                {
                    // Slow path
                    for (int col = 0; col < cols; col++)
                    {
                        pixel.R        = (byte)ExpandBits(bitReader.Read(bitsPerSample[0]), bitsPerSample[0], 8);
                        pixel.G        = (byte)ExpandBits(bitReader.Read(bitsPerSample[1]), bitsPerSample[1], 8);
                        pixel.B        = (byte)ExpandBits(bitReader.Read(bitsPerSample[2]), bitsPerSample[2], 8);
                        pixelSpan[col] = pixel;
                    }
                }

                sourceSpan = sourceSpan.Slice(bytesPerScanline);
            }

            return(next.RunAsync(context));
        }