Exemplo n.º 1
0
        public void Encode_WithPngTransparentColorBehaviorClear_Works(PngColorType colorType)
        {
            // arrange
            var image   = new Image <Rgba32>(50, 50);
            var encoder = new PngEncoder()
            {
                TransparentColorMode = PngTransparentColorMode.Clear,
                ColorType            = colorType
            };
            Rgba32 rgba32 = Color.Blue;

            for (int y = 0; y < image.Height; y++)
            {
                System.Span <Rgba32> rowSpan = image.GetPixelRowSpan(y);

                // Half of the test image should be transparent.
                if (y > 25)
                {
                    rgba32.A = 0;
                }

                for (int x = 0; x < image.Width; x++)
                {
                    rowSpan[x].FromRgba32(rgba32);
                }
            }

            // act
            using var memStream = new MemoryStream();
            image.Save(memStream, encoder);

            // assert
            memStream.Position = 0;
            using var actual   = Image.Load <Rgba32>(memStream);
            Rgba32 expectedColor = Color.Blue;

            if (colorType == PngColorType.Grayscale || colorType == PngColorType.GrayscaleWithAlpha)
            {
                var luminance = ImageMaths.Get8BitBT709Luminance(expectedColor.R, expectedColor.G, expectedColor.B);
                expectedColor = new Rgba32(luminance, luminance, luminance);
            }

            for (int y = 0; y < actual.Height; y++)
            {
                System.Span <Rgba32> rowSpan = actual.GetPixelRowSpan(y);

                if (y > 25)
                {
                    expectedColor = Color.Transparent;
                }

                for (int x = 0; x < actual.Width; x++)
                {
                    Assert.Equal(expectedColor, rowSpan[x]);
                }
            }
        }
        /// <inheritdoc/>
        protected override void OnFrameApply(ImageFrame <TPixel> source)
        {
            byte threshold   = (byte)MathF.Round(this.Definition.Threshold * 255F);
            bool isAlphaOnly = typeof(TPixel) == typeof(Alpha8);

            var interest = Rectangle.Intersect(this.SourceRectangle, source.Bounds());
            int startY   = interest.Y;
            int endY     = interest.Bottom;
            int startX   = interest.X;
            int endX     = interest.Right;

            // Collect the values before looping so we can reduce our calculation count for identical sibling pixels
            TPixel             sourcePixel   = source[startX, startY];
            TPixel             previousPixel = sourcePixel;
            PixelPair <TPixel> pair          = this.GetClosestPixelPair(ref sourcePixel);
            Rgba32             rgba          = default;

            sourcePixel.ToRgba32(ref rgba);

            // Convert to grayscale using ITU-R Recommendation BT.709 if required
            byte luminance = isAlphaOnly ? rgba.A : ImageMaths.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B);

            for (int y = startY; y < endY; y++)
            {
                Span <TPixel> row = source.GetPixelRowSpan(y);

                for (int x = startX; x < endX; x++)
                {
                    sourcePixel = row[x];

                    // Check if this is the same as the last pixel. If so use that value
                    // rather than calculating it again. This is an inexpensive optimization.
                    if (!previousPixel.Equals(sourcePixel))
                    {
                        pair = this.GetClosestPixelPair(ref sourcePixel);

                        // No error to spread, exact match.
                        if (sourcePixel.Equals(pair.First))
                        {
                            continue;
                        }

                        sourcePixel.ToRgba32(ref rgba);
                        luminance = isAlphaOnly ? rgba.A : ImageMaths.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B);

                        // Setup the previous pointer
                        previousPixel = sourcePixel;
                    }

                    TPixel transformedPixel = luminance >= threshold ? pair.Second : pair.First;
                    this.Definition.Diffuser.Dither(source, sourcePixel, transformedPixel, x, y, startX, startY, endX, endY);
                }
            }
        }
Exemplo n.º 3
0
        public void Gray8_FromRgba32(byte rgb)
        {
            // Arrange
            Gray8 gray     = default;
            byte  expected = ImageMaths.Get8BitBT709Luminance(rgb, rgb, rgb);

            // Act
            gray.FromRgba32(new Rgba32(rgb, rgb, rgb));
            byte actual = gray.PackedValue;

            // Assert
            Assert.Equal(expected, actual);
        }
Exemplo n.º 4
0
        public void La16_FromRgba32(byte rgb)
        {
            // Arrange
            La16 gray     = default;
            byte expected = ImageMaths.Get8BitBT709Luminance(rgb, rgb, rgb);

            // Act
            gray.FromRgba32(new Rgba32(rgb, rgb, rgb));
            byte actual = gray.L;

            // Assert
            Assert.Equal(expected, actual);
            Assert.Equal(255, gray.A);
        }
        /// <inheritdoc/>
        protected override void OnFrameApply(ImageFrame <TPixel> source)
        {
            IOrderedDither dither     = this.definition.Dither;
            TPixel         upperColor = this.definition.UpperColor.ToPixel <TPixel>();
            TPixel         lowerColor = this.definition.LowerColor.ToPixel <TPixel>();

            bool isAlphaOnly = typeof(TPixel) == typeof(A8);

            var interest = Rectangle.Intersect(this.SourceRectangle, source.Bounds());
            int startY   = interest.Y;
            int endY     = interest.Bottom;
            int startX   = interest.X;
            int endX     = interest.Right;

            // Collect the values before looping so we can reduce our calculation count for identical sibling pixels
            TPixel sourcePixel   = source[startX, startY];
            TPixel previousPixel = sourcePixel;
            Rgba32 rgba          = default;

            sourcePixel.ToRgba32(ref rgba);

            // Convert to grayscale using ITU-R Recommendation BT.709 if required
            byte luminance = isAlphaOnly ? rgba.A : ImageMaths.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B);

            for (int y = startY; y < endY; y++)
            {
                Span <TPixel> row = source.GetPixelRowSpan(y);

                for (int x = startX; x < endX; x++)
                {
                    sourcePixel = row[x];

                    // Check if this is the same as the last pixel. If so use that value
                    // rather than calculating it again. This is an inexpensive optimization.
                    if (!previousPixel.Equals(sourcePixel))
                    {
                        sourcePixel.ToRgba32(ref rgba);
                        luminance = isAlphaOnly ? rgba.A : ImageMaths.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B);

                        // Setup the previous pointer
                        previousPixel = sourcePixel;
                    }

                    dither.Dither(source, sourcePixel, upperColor, lowerColor, luminance, x, y);
                }
            }
        }
        /// <inheritdoc/>
        protected override void OnFrameApply(ImageFrame <TPixel> source)
        {
            byte   threshold = (byte)MathF.Round(this.definition.Threshold * 255F);
            TPixel upper     = this.definition.UpperColor.ToPixel <TPixel>();
            TPixel lower     = this.definition.LowerColor.ToPixel <TPixel>();

            Rectangle     sourceRectangle = this.SourceRectangle;
            Configuration configuration   = this.Configuration;

            var interest = Rectangle.Intersect(sourceRectangle, source.Bounds());
            int startY   = interest.Y;
            int endY     = interest.Bottom;
            int startX   = interest.X;
            int endX     = interest.Right;

            bool isAlphaOnly = typeof(TPixel) == typeof(Alpha8);

            var workingRect = Rectangle.FromLTRB(startX, startY, endX, endY);

            ParallelHelper.IterateRows(
                workingRect,
                configuration,
                rows =>
            {
                Rgba32 rgba = default;
                for (int y = rows.Min; y < rows.Max; y++)
                {
                    Span <TPixel> row = source.GetPixelRowSpan(y);

                    for (int x = startX; x < endX; x++)
                    {
                        ref TPixel color = ref row[x];
                        color.ToRgba32(ref rgba);

                        // Convert to grayscale using ITU-R Recommendation BT.709 if required
                        byte luminance = isAlphaOnly ? rgba.A : ImageMaths.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B);
                        color          = luminance >= threshold ? upper : lower;
                    }
                }
            });
        }