Esempio n. 1
0
        public CoreSize BulkVectorConvert()
        {
            using (Image <Rgba32> image = new Image <Rgba32>(800, 800))
            {
                using (IBuffer <float> amounts = Configuration.Default.MemoryManager.Allocate <float>(image.Width))
                {
                    amounts.Span.Fill(1);

                    using (PixelAccessor <Rgba32> pixels = image.Lock())
                    {
                        for (int y = 0; y < image.Height; y++)
                        {
                            Span <Rgba32> span = pixels.GetRowSpan(y);
                            this.BulkVectorConvert(span, span, span, amounts.Span);
                        }
                    }
                    return(new CoreSize(image.Width, image.Height));
                }
            }
        }
Esempio n. 2
0
        public CoreSize BulkPixelConvert()
        {
            using (Image <Rgba32> image = new Image <Rgba32>(800, 800))
            {
                Buffer <float> amounts = new Buffer <float>(image.Width);

                for (int x = 0; x < image.Width; x++)
                {
                    amounts[x] = 1;
                }
                using (PixelAccessor <Rgba32> pixels = image.Lock())
                {
                    for (int y = 0; y < image.Height; y++)
                    {
                        BufferSpan <Rgba32> span = pixels.GetRowSpan(y);
                        BulkPixelConvert(span, span, span, amounts);
                    }
                }
                return(new CoreSize(image.Width, image.Height));
            }
        }
Esempio n. 3
0
        /// <summary>
        /// Looks up color values and builds the image from de-compressed RLE8 data.
        /// Compresssed RLE8 stream is uncompressed by <see cref="UncompressRle8(int, Buffer{byte})"/>
        /// </summary>
        /// <typeparam name="TPixel">The pixel format.</typeparam>
        /// <param name="pixels">The <see cref="PixelAccessor{TPixel}"/> to assign the palette to.</param>
        /// <param name="colors">The <see cref="T:byte[]"/> containing the colors.</param>
        /// <param name="width">The width of the bitmap.</param>
        /// <param name="height">The height of the bitmap.</param>
        /// <param name="inverted">Whether the bitmap is inverted.</param>
        private void ReadRle8 <TPixel>(PixelAccessor <TPixel> pixels, byte[] colors, int width, int height, bool inverted)
            where TPixel : struct, IPixel <TPixel>
        {
            var color = default(TPixel);
            var rgba  = default(Rgba32);

            using (var buffer = Buffer <byte> .CreateClean(width * height))
            {
                this.UncompressRle8(width, buffer);

                for (int y = 0; y < height; y++)
                {
                    int           newY     = Invert(y, height, inverted);
                    Span <TPixel> pixelRow = pixels.GetRowSpan(newY);
                    for (int x = 0; x < width; x++)
                    {
                        rgba.Bgr = Unsafe.As <byte, Bgr24>(ref colors[buffer[(y * width) + x] * 4]);
                        color.PackFromRgba32(rgba);
                        pixelRow[x] = color;
                    }
                }
            }
        }
Esempio n. 4
0
        /// <summary>
        /// Reads the 16 bit color palette from the stream
        /// </summary>
        /// <typeparam name="TPixel">The pixel format.</typeparam>
        /// <param name="pixels">The <see cref="PixelAccessor{TPixel}"/> to assign the palette to.</param>
        /// <param name="width">The width of the bitmap.</param>
        /// <param name="height">The height of the bitmap.</param>
        /// <param name="inverted">Whether the bitmap is inverted.</param>
        private void ReadRgb16 <TPixel>(PixelAccessor <TPixel> pixels, int width, int height, bool inverted)
            where TPixel : struct, IPixel <TPixel>
        {
            // We divide here as we will store the colors in our floating point format.
            const int ScaleR         = 8; // 256/32
            const int ScaleG         = 4; // 256/64
            const int ComponentCount = 2;

            TPixel color = default(TPixel);
            Rgba32 rgba  = new Rgba32(0, 0, 0, 255);

            using (PixelArea <TPixel> row = new PixelArea <TPixel>(width, ComponentOrder.Xyz))
            {
                for (int y = 0; y < height; y++)
                {
                    row.Read(this.currentStream);

                    int newY = Invert(y, height, inverted);

                    Span <TPixel> pixelRow = pixels.GetRowSpan(newY);

                    int offset = 0;
                    for (int x = 0; x < width; x++)
                    {
                        short temp = BitConverter.ToInt16(row.Bytes, offset);

                        rgba.R = (byte)(((temp & Rgb16RMask) >> 11) * ScaleR);
                        rgba.G = (byte)(((temp & Rgb16GMask) >> 5) * ScaleG);
                        rgba.B = (byte)((temp & Rgb16BMask) * ScaleR);

                        color.PackFromRgba32(rgba);
                        pixelRow[x] = color;
                        offset     += ComponentCount;
                    }
                }
            }
        }
Esempio n. 5
0
        /// <inheritdoc/>
        protected override void OnApply(ImageFrame <TPixel> source, Rectangle sourceRectangle, Configuration configuration)
        {
            if (this.OptimizedApply(source, configuration))
            {
                return;
            }

            int       height       = this.CanvasRectangle.Height;
            int       width        = this.CanvasRectangle.Width;
            Matrix3x2 matrix       = this.GetCenteredMatrix(source, this.processMatrix);
            Rectangle sourceBounds = source.Bounds();

            using (var targetPixels = new PixelAccessor <TPixel>(width, height))
            {
                Parallel.For(
                    0,
                    height,
                    configuration.ParallelOptions,
                    y =>
                {
                    Span <TPixel> targetRow = targetPixels.GetRowSpan(y);

                    for (int x = 0; x < width; x++)
                    {
                        var transformedPoint = Point.Rotate(new Point(x, y), matrix);

                        if (sourceBounds.Contains(transformedPoint.X, transformedPoint.Y))
                        {
                            targetRow[x] = source[transformedPoint.X, transformedPoint.Y];
                        }
                    }
                });

                source.SwapPixelsBuffers(targetPixels);
            }
        }
        /// <inheritdoc/>
        protected override void OnApply(ImageFrame <TPixel> source, Rectangle sourceRectangle, Configuration configuration)
        {
            int kernelYHeight = this.KernelY.Height;
            int kernelYWidth  = this.KernelY.Width;
            int kernelXHeight = this.KernelX.Height;
            int kernelXWidth  = this.KernelX.Width;
            int radiusY       = kernelYHeight >> 1;
            int radiusX       = kernelXWidth >> 1;

            int startY = sourceRectangle.Y;
            int endY   = sourceRectangle.Bottom;
            int startX = sourceRectangle.X;
            int endX   = sourceRectangle.Right;
            int maxY   = endY - 1;
            int maxX   = endX - 1;

            using (var targetPixels = new PixelAccessor <TPixel>(source.Width, source.Height))
            {
                source.CopyTo(targetPixels);

                Parallel.For(
                    startY,
                    endY,
                    configuration.ParallelOptions,
                    y =>
                {
                    Span <TPixel> sourceRow = source.GetPixelRowSpan(y);
                    Span <TPixel> targetRow = targetPixels.GetRowSpan(y);

                    for (int x = startX; x < endX; x++)
                    {
                        float rX = 0;
                        float gX = 0;
                        float bX = 0;
                        float rY = 0;
                        float gY = 0;
                        float bY = 0;

                        // Apply each matrix multiplier to the color components for each pixel.
                        for (int fy = 0; fy < kernelYHeight; fy++)
                        {
                            int fyr     = fy - radiusY;
                            int offsetY = y + fyr;

                            offsetY = offsetY.Clamp(0, maxY);
                            Span <TPixel> sourceOffsetRow = source.GetPixelRowSpan(offsetY);

                            for (int fx = 0; fx < kernelXWidth; fx++)
                            {
                                int fxr     = fx - radiusX;
                                int offsetX = x + fxr;

                                offsetX          = offsetX.Clamp(0, maxX);
                                var currentColor = sourceOffsetRow[offsetX].ToVector4();

                                if (fy < kernelXHeight)
                                {
                                    Vector4 kx = this.KernelX[fy, fx] * currentColor;
                                    rX        += kx.X;
                                    gX        += kx.Y;
                                    bX        += kx.Z;
                                }

                                if (fx < kernelYWidth)
                                {
                                    Vector4 ky = this.KernelY[fy, fx] * currentColor;
                                    rY        += ky.X;
                                    gY        += ky.Y;
                                    bY        += ky.Z;
                                }
                            }
                        }

                        float red   = MathF.Sqrt((rX * rX) + (rY * rY));
                        float green = MathF.Sqrt((gX * gX) + (gY * gY));
                        float blue  = MathF.Sqrt((bX * bX) + (bY * bY));

                        ref TPixel pixel = ref targetRow[x];
                        pixel.PackFromVector4(new Vector4(red, green, blue, sourceRow[x].ToVector4().W));
                    }
                });

                source.SwapPixelsBuffers(targetPixels);
            }
        }
Esempio n. 7
0
        /// <inheritdoc/>
        protected override void OnApply(ImageBase <TPixel> source, Rectangle sourceRectangle)
        {
            int     startY        = sourceRectangle.Y;
            int     endY          = sourceRectangle.Bottom;
            int     startX        = sourceRectangle.X;
            int     endX          = sourceRectangle.Right;
            TPixel  vignetteColor = this.VignetteColor;
            Vector2 centre        = Rectangle.Center(sourceRectangle).ToVector2();
            float   rX            = this.RadiusX > 0 ? MathF.Min(this.RadiusX, sourceRectangle.Width * .5F) : sourceRectangle.Width * .5F;
            float   rY            = this.RadiusY > 0 ? MathF.Min(this.RadiusY, sourceRectangle.Height * .5F) : sourceRectangle.Height * .5F;
            float   maxDistance   = MathF.Sqrt((rX * rX) + (rY * rY));

            // Align start/end positions.
            int minX = Math.Max(0, startX);
            int maxX = Math.Min(source.Width, endX);
            int minY = Math.Max(0, startY);
            int maxY = Math.Min(source.Height, endY);

            // Reset offset if necessary.
            if (minX > 0)
            {
                startX = 0;
            }

            if (minY > 0)
            {
                startY = 0;
            }

            int width = maxX - minX;

            using (Buffer <TPixel> rowColors = new Buffer <TPixel>(width))
                using (PixelAccessor <TPixel> sourcePixels = source.Lock())
                {
                    for (int i = 0; i < width; i++)
                    {
                        rowColors[i] = vignetteColor;
                    }

                    Parallel.For(
                        minY,
                        maxY,
                        this.ParallelOptions,
                        y =>
                    {
                        using (Buffer <float> amounts = new Buffer <float>(width))
                        {
                            int offsetY = y - startY;
                            int offsetX = minX - startX;
                            for (int i = 0; i < width; i++)
                            {
                                float distance = Vector2.Distance(centre, new Vector2(i + offsetX, offsetY));
                                amounts[i]     = (this.options.BlendPercentage * (.9F * (distance / maxDistance))).Clamp(0, 1);
                            }

                            Span <TPixel> destination = sourcePixels.GetRowSpan(offsetY).Slice(offsetX, width);

                            this.blender.Blend(destination, destination, rowColors, amounts);
                        }
                    });
                }
        }
        /// <inheritdoc/>
        protected override void OnApply(ImageFrame <TPixel> source, Rectangle sourceRectangle, Configuration configuration)
        {
            int kernelLength = this.KernelXY.Height;
            int radius       = kernelLength >> 1;

            int startY = sourceRectangle.Y;
            int endY   = sourceRectangle.Bottom;
            int startX = sourceRectangle.X;
            int endX   = sourceRectangle.Right;
            int maxY   = endY - 1;
            int maxX   = endX - 1;

            using (var targetPixels = new PixelAccessor <TPixel>(source.Width, source.Height))
            {
                source.CopyTo(targetPixels);

                Parallel.For(
                    startY,
                    endY,
                    configuration.ParallelOptions,
                    y =>
                {
                    Span <TPixel> sourceRow = source.GetPixelRowSpan(y);
                    Span <TPixel> targetRow = targetPixels.GetRowSpan(y);

                    for (int x = startX; x < endX; x++)
                    {
                        float red   = 0;
                        float green = 0;
                        float blue  = 0;

                        // Apply each matrix multiplier to the color components for each pixel.
                        for (int fy = 0; fy < kernelLength; fy++)
                        {
                            int fyr     = fy - radius;
                            int offsetY = y + fyr;

                            offsetY = offsetY.Clamp(0, maxY);
                            Span <TPixel> sourceOffsetRow = source.GetPixelRowSpan(offsetY);

                            for (int fx = 0; fx < kernelLength; fx++)
                            {
                                int fxr     = fx - radius;
                                int offsetX = x + fxr;

                                offsetX = offsetX.Clamp(0, maxX);

                                var currentColor = sourceOffsetRow[offsetX].ToVector4();
                                currentColor    *= this.KernelXY[fy, fx];

                                red   += currentColor.X;
                                green += currentColor.Y;
                                blue  += currentColor.Z;
                            }
                        }

                        ref TPixel pixel = ref targetRow[x];
                        pixel.PackFromVector4(new Vector4(red, green, blue, sourceRow[x].ToVector4().W));
                    }
                });

                source.SwapPixelsBuffers(targetPixels);
            }
        }
Esempio n. 9
0
        /// <inheritdoc/>
        protected override unsafe void OnApply(ImageBase <TColor> source, Rectangle sourceRectangle)
        {
            // Jump out, we'll deal with that later.
            if (source.Width == this.Width && source.Height == this.Height && sourceRectangle == this.ResizeRectangle)
            {
                return;
            }

            int width   = this.Width;
            int height  = this.Height;
            int sourceX = sourceRectangle.X;
            int sourceY = sourceRectangle.Y;
            int startY  = this.ResizeRectangle.Y;
            int endY    = this.ResizeRectangle.Bottom;
            int startX  = this.ResizeRectangle.X;
            int endX    = this.ResizeRectangle.Right;

            int minX = Math.Max(0, startX);
            int maxX = Math.Min(width, endX);
            int minY = Math.Max(0, startY);
            int maxY = Math.Min(height, endY);

            if (this.Sampler is NearestNeighborResampler)
            {
                // Scaling factors
                float widthFactor  = sourceRectangle.Width / (float)this.ResizeRectangle.Width;
                float heightFactor = sourceRectangle.Height / (float)this.ResizeRectangle.Height;

                using (PixelAccessor <TColor> targetPixels = new PixelAccessor <TColor>(width, height))
                {
                    using (PixelAccessor <TColor> sourcePixels = source.Lock())
                    {
                        Parallel.For(
                            minY,
                            maxY,
                            this.ParallelOptions,
                            y =>
                        {
                            // Y coordinates of source points
                            int originY = (int)(((y - startY) * heightFactor) + sourceY);

                            for (int x = minX; x < maxX; x++)
                            {
                                // X coordinates of source points
                                targetPixels[x, y] = sourcePixels[(int)(((x - startX) * widthFactor) + sourceX), originY];
                            }
                        });
                    }

                    // Break out now.
                    source.SwapPixelsBuffers(targetPixels);
                    return;
                }
            }

            // Interpolate the image using the calculated weights.
            // A 2-pass 1D algorithm appears to be faster than splitting a 1-pass 2D algorithm
            // First process the columns. Since we are not using multiple threads startY and endY
            // are the upper and lower bounds of the source rectangle.

            // TODO: Using a transposed variant of 'firstPassPixels' could eliminate the need for the WeightsWindow.ComputeWeightedColumnSum() method, and improve speed!
            using (PixelAccessor <TColor> targetPixels = new PixelAccessor <TColor>(width, height))
            {
                using (PixelAccessor <TColor> sourcePixels = source.Lock())
                    using (Buffer2D <Vector4> firstPassPixels = new Buffer2D <Vector4>(width, source.Height))
                    {
                        firstPassPixels.Clear();

                        Parallel.For(
                            0,
                            sourceRectangle.Bottom,
                            this.ParallelOptions,
                            y =>
                        {
                            // TODO: Without Parallel.For() this buffer object could be reused:
                            using (Buffer <Vector4> tempRowBuffer = new Buffer <Vector4>(sourcePixels.Width))
                            {
                                BufferSpan <TColor> sourceRow = sourcePixels.GetRowSpan(y);

                                BulkPixelOperations <TColor> .Instance.ToVector4(
                                    sourceRow,
                                    tempRowBuffer,
                                    sourceRow.Length);

                                if (this.Compand)
                                {
                                    for (int x = minX; x < maxX; x++)
                                    {
                                        WeightsWindow window  = this.HorizontalWeights.Weights[x - startX];
                                        firstPassPixels[x, y] = window.ComputeExpandedWeightedRowSum(tempRowBuffer);
                                    }
                                }
                                else
                                {
                                    for (int x = minX; x < maxX; x++)
                                    {
                                        WeightsWindow window  = this.HorizontalWeights.Weights[x - startX];
                                        firstPassPixels[x, y] = window.ComputeWeightedRowSum(tempRowBuffer);
                                    }
                                }
                            }
                        });

                        // Now process the rows.
                        Parallel.For(
                            minY,
                            maxY,
                            this.ParallelOptions,
                            y =>
                        {
                            // Ensure offsets are normalised for cropping and padding.
                            WeightsWindow window = this.VerticalWeights.Weights[y - startY];

                            if (this.Compand)
                            {
                                for (int x = 0; x < width; x++)
                                {
                                    // Destination color components
                                    Vector4 destination = window.ComputeWeightedColumnSum(firstPassPixels, x);
                                    destination         = destination.Compress();
                                    TColor d            = default(TColor);
                                    d.PackFromVector4(destination);
                                    targetPixels[x, y] = d;
                                }
                            }
                            else
                            {
                                for (int x = 0; x < width; x++)
                                {
                                    // Destination color components
                                    Vector4 destination = window.ComputeWeightedColumnSum(firstPassPixels, x);

                                    TColor d = default(TColor);
                                    d.PackFromVector4(destination);
                                    targetPixels[x, y] = d;
                                }
                            }
                        });
                    }

                source.SwapPixelsBuffers(targetPixels);
            }
        }
Esempio n. 10
0
        /// <inheritdoc/>
        protected override void OnApply(ImageBase <TPixel> source, Rectangle sourceRectangle)
        {
            int startY = sourceRectangle.Y;
            int endY   = sourceRectangle.Bottom;
            int startX = sourceRectangle.X;
            int endX   = sourceRectangle.Right;
            int radius = this.BrushSize >> 1;
            int levels = this.Levels;

            // Align start/end positions.
            int minX = Math.Max(0, startX);
            int maxX = Math.Min(source.Width, endX);
            int minY = Math.Max(0, startY);
            int maxY = Math.Min(source.Height, endY);

            // Reset offset if necessary.
            if (minX > 0)
            {
                startX = 0;
            }

            using (var targetPixels = new PixelAccessor <TPixel>(source.Width, source.Height))
            {
                source.CopyTo(targetPixels);

                Parallel.For(
                    minY,
                    maxY,
                    this.ParallelOptions,
                    y =>
                {
                    Span <TPixel> sourceRow = source.GetRowSpan(y);
                    Span <TPixel> targetRow = targetPixels.GetRowSpan(y);

                    for (int x = startX; x < endX; x++)
                    {
                        int maxIntensity = 0;
                        int maxIndex     = 0;

                        int[] intensityBin = new int[levels];
                        float[] redBin     = new float[levels];
                        float[] blueBin    = new float[levels];
                        float[] greenBin   = new float[levels];

                        for (int fy = 0; fy <= radius; fy++)
                        {
                            int fyr     = fy - radius;
                            int offsetY = y + fyr;

                            offsetY = offsetY.Clamp(0, maxY);

                            Span <TPixel> sourceOffsetRow = source.GetRowSpan(offsetY);

                            for (int fx = 0; fx <= radius; fx++)
                            {
                                int fxr     = fx - radius;
                                int offsetX = x + fxr;
                                offsetX     = offsetX.Clamp(0, maxX);

                                var vector = sourceOffsetRow[offsetX].ToVector4();

                                float sourceRed   = vector.X;
                                float sourceBlue  = vector.Z;
                                float sourceGreen = vector.Y;

                                int currentIntensity = (int)MathF.Round((sourceBlue + sourceGreen + sourceRed) / 3F * (levels - 1));

                                intensityBin[currentIntensity] += 1;
                                blueBin[currentIntensity]      += sourceBlue;
                                greenBin[currentIntensity]     += sourceGreen;
                                redBin[currentIntensity]       += sourceRed;

                                if (intensityBin[currentIntensity] > maxIntensity)
                                {
                                    maxIntensity = intensityBin[currentIntensity];
                                    maxIndex     = currentIntensity;
                                }
                            }

                            float red   = MathF.Abs(redBin[maxIndex] / maxIntensity);
                            float green = MathF.Abs(greenBin[maxIndex] / maxIntensity);
                            float blue  = MathF.Abs(blueBin[maxIndex] / maxIntensity);

                            ref TPixel pixel = ref targetRow[x];
                            pixel.PackFromVector4(new Vector4(red, green, blue, sourceRow[x].ToVector4().W));
                        }
                    }
                });

                source.SwapPixelsBuffers(targetPixels);
            }
        }
Esempio n. 11
0
        /// <inheritdoc/>
        protected override void OnApply(ImageFrame <TPixel> source, Rectangle sourceRectangle, Configuration configuration)
        {
            if (this.BrushSize <= 0 || this.BrushSize > source.Height || this.BrushSize > source.Width)
            {
                throw new ArgumentOutOfRangeException(nameof(this.BrushSize));
            }

            int startY = sourceRectangle.Y;
            int endY   = sourceRectangle.Bottom;
            int startX = sourceRectangle.X;
            int endX   = sourceRectangle.Right;
            int maxY   = endY - 1;
            int maxX   = endX - 1;

            int radius = this.BrushSize >> 1;
            int levels = this.Levels;

            using (var targetPixels = new PixelAccessor <TPixel>(source.Width, source.Height))
            {
                source.CopyTo(targetPixels);

                Parallel.For(
                    startY,
                    maxY,
                    configuration.ParallelOptions,
                    y =>
                {
                    Span <TPixel> sourceRow = source.GetPixelRowSpan(y);
                    Span <TPixel> targetRow = targetPixels.GetRowSpan(y);

                    for (int x = startX; x < endX; x++)
                    {
                        int maxIntensity = 0;
                        int maxIndex     = 0;

                        int[] intensityBin = new int[levels];
                        float[] redBin     = new float[levels];
                        float[] blueBin    = new float[levels];
                        float[] greenBin   = new float[levels];

                        for (int fy = 0; fy <= radius; fy++)
                        {
                            int fyr     = fy - radius;
                            int offsetY = y + fyr;

                            offsetY = offsetY.Clamp(0, maxY);

                            Span <TPixel> sourceOffsetRow = source.GetPixelRowSpan(offsetY);

                            for (int fx = 0; fx <= radius; fx++)
                            {
                                int fxr     = fx - radius;
                                int offsetX = x + fxr;
                                offsetX     = offsetX.Clamp(0, maxX);

                                var vector = sourceOffsetRow[offsetX].ToVector4();

                                float sourceRed   = vector.X;
                                float sourceBlue  = vector.Z;
                                float sourceGreen = vector.Y;

                                int currentIntensity = (int)Math.Round((sourceBlue + sourceGreen + sourceRed) / 3F * (levels - 1));

                                intensityBin[currentIntensity] += 1;
                                blueBin[currentIntensity]      += sourceBlue;
                                greenBin[currentIntensity]     += sourceGreen;
                                redBin[currentIntensity]       += sourceRed;

                                if (intensityBin[currentIntensity] > maxIntensity)
                                {
                                    maxIntensity = intensityBin[currentIntensity];
                                    maxIndex     = currentIntensity;
                                }
                            }

                            float red   = Math.Abs(redBin[maxIndex] / maxIntensity);
                            float green = Math.Abs(greenBin[maxIndex] / maxIntensity);
                            float blue  = Math.Abs(blueBin[maxIndex] / maxIntensity);

                            ref TPixel pixel = ref targetRow[x];
                            pixel.PackFromVector4(new Vector4(red, green, blue, sourceRow[x].ToVector4().W));
                        }
                    }
                });

                source.SwapPixelsBuffers(targetPixels);
            }
        }
Esempio n. 12
0
        /// <inheritdoc/>
        protected override void OnApply(ImageBase <TPixel> source, Rectangle sourceRectangle)
        {
            using (PixelAccessor <TPixel> sourcePixels = source.Lock())
                using (PenApplicator <TPixel> applicator = this.Pen.CreateApplicator(sourcePixels, this.Path.Bounds, this.Options))
                {
                    Rectangle rect = RectangleF.Ceiling(applicator.RequiredRegion);

                    int polyStartY = rect.Y - PaddingFactor;
                    int polyEndY   = rect.Bottom + PaddingFactor;
                    int startX     = rect.X - PaddingFactor;
                    int endX       = rect.Right + PaddingFactor;

                    int minX = Math.Max(sourceRectangle.Left, startX);
                    int maxX = Math.Min(sourceRectangle.Right, endX);
                    int minY = Math.Max(sourceRectangle.Top, polyStartY);
                    int maxY = Math.Min(sourceRectangle.Bottom, polyEndY);

                    // Align start/end positions.
                    minX = Math.Max(0, minX);
                    maxX = Math.Min(source.Width, maxX);
                    minY = Math.Max(0, minY);
                    maxY = Math.Min(source.Height, maxY);

                    // Reset offset if necessary.
                    if (minX > 0)
                    {
                        startX = 0;
                    }

                    if (minY > 0)
                    {
                        polyStartY = 0;
                    }

                    int width = maxX - minX;
                    PixelBlender <TPixel> blender = PixelOperations <TPixel> .Instance.GetPixelBlender(this.Options.BlenderMode);

                    Parallel.For(
                        minY,
                        maxY,
                        this.ParallelOptions,
                        y =>
                    {
                        int offsetY = y - polyStartY;

                        using (Buffer <float> amount = new Buffer <float>(width))
                            using (Buffer <TPixel> colors = new Buffer <TPixel>(width))
                            {
                                for (int i = 0; i < width; i++)
                                {
                                    int x          = i + minX;
                                    int offsetX    = x - startX;
                                    PointInfo info = this.Path.GetPointInfo(offsetX, offsetY);
                                    ColoredPointInfo <TPixel> color = applicator.GetColor(offsetX, offsetY, info);
                                    amount[i] = (this.Opacity(color.DistanceFromElement) * this.Options.BlendPercentage).Clamp(0, 1);
                                    colors[i] = color.Color;
                                }

                                BufferSpan <TPixel> destination = sourcePixels.GetRowSpan(offsetY).Slice(minX - startX, width);
                                blender.Blend(destination, destination, colors, amount);
                            }
                    });
                }
        }