Beispiel #1
0
        /// <inheritdoc/>
        protected override void OnFrameApply(ImageFrame <TPixel> source, Rectangle sourceRectangle, Configuration configuration)
        {
            int startY = sourceRectangle.Y;
            int endY   = sourceRectangle.Bottom;
            int startX = sourceRectangle.X;
            int endX   = sourceRectangle.Right;

            // 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 (IBuffer <TPixel> colors = source.MemoryAllocator.Allocate <TPixel>(width))
                using (IBuffer <float> amount = source.MemoryAllocator.Allocate <float>(width))
                {
                    // Be careful! Do not capture colorSpan & amountSpan in the lambda below!
                    Span <TPixel> colorSpan  = colors.GetSpan();
                    Span <float>  amountSpan = amount.GetSpan();

                    // TODO: Use Span.Fill?
                    for (int i = 0; i < width; i++)
                    {
                        colorSpan[i]  = this.Color;
                        amountSpan[i] = this.GraphicsOptions.BlendPercentage;
                    }

                    PixelBlender <TPixel> blender = PixelOperations <TPixel> .Instance.GetPixelBlender(this.GraphicsOptions.BlenderMode);

                    Parallel.For(
                        minY,
                        maxY,
                        configuration.ParallelOptions,
                        y =>
                    {
                        Span <TPixel> destination = source.GetPixelRowSpan(y - startY).Slice(minX - startX, width);

                        // This switched color & destination in the 2nd and 3rd places because we are applying the target color under the current one
                        blender.Blend(source.MemoryAllocator, destination, colors.GetSpan(), destination, amount.GetSpan());
                    });
                }
        }
Beispiel #2
0
            /// <inheritdoc />
            internal override void Apply(Span <float> scanline, int x, int y)
            {
                MemoryAllocator memoryAllocator = this.Target.MemoryAllocator;

                using (IBuffer <float> amountBuffer = memoryAllocator.Allocate <float>(scanline.Length))
                    using (IBuffer <TPixel> overlay = memoryAllocator.Allocate <TPixel>(scanline.Length))
                    {
                        Span <float>  amountSpan  = amountBuffer.GetSpan();
                        Span <TPixel> overlaySpan = overlay.GetSpan();

                        for (int i = 0; i < scanline.Length; i++)
                        {
                            amountSpan[i] = scanline[i] * this.Options.BlendPercentage;

                            int offsetX = x + i;

                            // No doubt this one can be optimized further but I can't imagine its
                            // actually being used and can probably be removed/internalized for now
                            overlaySpan[i] = this[offsetX, y];
                        }

                        Span <TPixel> destinationRow = this.Target.GetPixelRowSpan(y).Slice(x, scanline.Length);
                        this.Blender.Blend(memoryAllocator, destinationRow, destinationRow, overlaySpan, amountSpan);
                    }
            }
            /// <inheritdoc />
            internal override void Apply(Span <float> scanline, int x, int y)
            {
                // Create a span for colors
                using (IBuffer <float> amountBuffer = this.Target.MemoryAllocator.Allocate <float>(scanline.Length))
                    using (IBuffer <TPixel> overlay = this.Target.MemoryAllocator.Allocate <TPixel>(scanline.Length))
                    {
                        Span <float>  amountSpan  = amountBuffer.GetSpan();
                        Span <TPixel> overlaySpan = overlay.GetSpan();

                        int           sourceY   = (y - this.offsetY) % this.yLength;
                        int           offsetX   = x - this.offsetX;
                        Span <TPixel> sourceRow = this.source.GetPixelRowSpan(sourceY);

                        for (int i = 0; i < scanline.Length; i++)
                        {
                            amountSpan[i] = scanline[i] * this.Options.BlendPercentage;

                            int    sourceX = (i + offsetX) % this.xLength;
                            TPixel pixel   = sourceRow[sourceX];
                            overlaySpan[i] = pixel;
                        }

                        Span <TPixel> destinationRow = this.Target.GetPixelRowSpan(y).Slice(x, scanline.Length);
                        this.Blender.Blend(this.source.MemoryAllocator, destinationRow, destinationRow, overlaySpan, amountSpan);
                    }
            }
Beispiel #4
0
 private void TestSpanPropertyIsAlwaysTheSame <T>(int desiredLength, bool testManagedByteBuffer = false)
     where T : struct
 {
     using (IBuffer <T> buffer = this.Allocate <T>(desiredLength, false, testManagedByteBuffer))
     {
         ref T a = ref MemoryMarshal.GetReference(buffer.GetSpan());
         ref T b = ref MemoryMarshal.GetReference(buffer.GetSpan());
Beispiel #5
0
            /// <inheritdoc />
            internal override void Apply(Span <float> scanline, int x, int y)
            {
                Span <TPixel> destinationRow = this.Target.GetPixelRowSpan(y).Slice(x, scanline.Length);

                MemoryAllocator memoryAllocator = this.Target.MemoryAllocator;

                if (this.Options.BlendPercentage == 1f)
                {
                    this.Blender.Blend(memoryAllocator, destinationRow, destinationRow, this.Colors.GetSpan(), scanline);
                }
                else
                {
                    using (IBuffer <float> amountBuffer = memoryAllocator.Allocate <float>(scanline.Length))
                    {
                        Span <float> amountSpan = amountBuffer.GetSpan();

                        for (int i = 0; i < scanline.Length; i++)
                        {
                            amountSpan[i] = scanline[i] * this.Options.BlendPercentage;
                        }

                        this.Blender.Blend(memoryAllocator, destinationRow, destinationRow, this.Colors.GetSpan(), amountSpan);
                    }
                }
            }
        /// <summary>
        /// Applies the opacity weighting for each pixel in a scanline to the target based on the pattern contained in the brush.
        /// </summary>
        /// <param name="scanline">The a collection of opacity values between 0 and 1 to be merged with the brushed color value before being applied to the target.</param>
        /// <param name="x">The x position in the target pixel space that the start of the scanline data corresponds to.</param>
        /// <param name="y">The y position in  the target pixel space that whole scanline corresponds to.</param>
        /// <remarks>scanlineBuffer will be > scanlineWidth but provide and offset in case we want to share a larger buffer across runs.</remarks>
        internal virtual void Apply(Span <float> scanline, int x, int y)
        {
            MemoryAllocator memoryAllocator = this.Target.MemoryAllocator;

            using (IBuffer <float> amountBuffer = memoryAllocator.Allocate <float>(scanline.Length))
                using (IBuffer <TPixel> overlay = memoryAllocator.Allocate <TPixel>(scanline.Length))
                {
                    Span <float>  amountSpan  = amountBuffer.GetSpan();
                    Span <TPixel> overlaySpan = overlay.GetSpan();

                    for (int i = 0; i < scanline.Length; i++)
                    {
                        if (this.Options.BlendPercentage < 1)
                        {
                            amountSpan[i] = scanline[i] * this.Options.BlendPercentage;
                        }
                        else
                        {
                            amountSpan[i] = scanline[i];
                        }

                        overlaySpan[i] = this[x + i, y];
                    }

                    Span <TPixel> destinationRow = this.Target.GetPixelRowSpan(y).Slice(x, scanline.Length);
                    this.Blender.Blend(memoryAllocator, destinationRow, destinationRow, overlaySpan, amountSpan);
                }
        }
Beispiel #7
0
        /// <inheritdoc/>
        protected override void OnFrameApply(ImageFrame <TPixel> source, Rectangle sourceRectangle, Configuration configuration)
        {
            MemoryAllocator memoryAllocator = configuration.MemoryAllocator;
            int             numberOfPixels  = source.Width * source.Height;
            Span <TPixel>   pixels          = source.GetPixelSpan();

            // Build the histogram of the grayscale levels.
            using (IBuffer <int> histogramBuffer = memoryAllocator.Allocate <int>(this.LuminanceLevels, AllocationOptions.Clean))
                using (IBuffer <int> cdfBuffer = memoryAllocator.Allocate <int>(this.LuminanceLevels, AllocationOptions.Clean))
                {
                    Span <int> histogram = histogramBuffer.GetSpan();
                    for (int i = 0; i < pixels.Length; i++)
                    {
                        TPixel sourcePixel = pixels[i];
                        int    luminance   = this.GetLuminance(sourcePixel, this.LuminanceLevels);
                        histogram[luminance]++;
                    }

                    // Calculate the cumulative distribution function, which will map each input pixel to a new value.
                    Span <int> cdf    = cdfBuffer.GetSpan();
                    int        cdfMin = this.CalculateCdf(cdf, histogram);

                    // Apply the cdf to each pixel of the image
                    float numberOfPixelsMinusCdfMin = numberOfPixels - cdfMin;
                    for (int i = 0; i < pixels.Length; i++)
                    {
                        TPixel sourcePixel = pixels[i];

                        int   luminance          = this.GetLuminance(sourcePixel, this.LuminanceLevels);
                        float luminanceEqualized = cdf[luminance] / numberOfPixelsMinusCdfMin;

                        pixels[i].PackFromVector4(new Vector4(luminanceEqualized));
                    }
                }
        }
        internal static unsafe System.Drawing.Bitmap ToSystemDrawingBitmap <TPixel>(Image <TPixel> image)
            where TPixel : struct, IPixel <TPixel>
        {
            int w = image.Width;
            int h = image.Height;

            var        resultBitmap = new System.Drawing.Bitmap(w, h, PixelFormat.Format32bppArgb);
            var        fullRect     = new System.Drawing.Rectangle(0, 0, w, h);
            BitmapData data         = resultBitmap.LockBits(fullRect, ImageLockMode.ReadWrite, resultBitmap.PixelFormat);
            byte *     destPtrBase  = (byte *)data.Scan0;

            long destRowByteCount   = data.Stride;
            long sourceRowByteCount = w * sizeof(Bgra32);

            using (IBuffer <Bgra32> workBuffer = image.GetConfiguration().MemoryAllocator.Allocate <Bgra32>(w))
            {
                fixed(Bgra32 *sourcePtr = &workBuffer.GetReference())
                {
                    for (int y = 0; y < h; y++)
                    {
                        Span <TPixel> row = image.Frames.RootFrame.GetPixelRowSpan(y);
                        PixelOperations <TPixel> .Instance.ToBgra32(row, workBuffer.GetSpan(), row.Length);

                        byte *destPtr = destPtrBase + data.Stride * y;

                        Buffer.MemoryCopy(sourcePtr, destPtr, destRowByteCount, sourceRowByteCount);
                    }
                }
            }

            resultBitmap.UnlockBits(data);

            return(resultBitmap);
        }
Beispiel #9
0
 private void TestHasCorrectLength <T>(int desiredLength)
     where T : struct
 {
     using (IBuffer <T> buffer = this.MemoryAllocator.Allocate <T>(desiredLength))
     {
         Assert.Equal(desiredLength, buffer.GetSpan().Length);
     }
 }
Beispiel #10
0
        public CoreSize BulkPixelConvert()
        {
            using (var image = new Image <Rgba32>(800, 800))
            {
                using (IBuffer <float> amounts = Configuration.Default.MemoryAllocator.Allocate <float>(image.Width))
                {
                    amounts.GetSpan().Fill(1);
                    Buffer2D <Rgba32> pixels = image.GetRootFramePixelBuffer();
                    for (int y = 0; y < image.Height; y++)
                    {
                        Span <Rgba32> span = pixels.GetRowSpan(y);
                        this.BulkPixelConvert(span, span, span, amounts.GetSpan());
                    }

                    return(new CoreSize(image.Width, image.Height));
                }
            }
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="PdfJsHuffmanTable"/> struct.
        /// </summary>
        /// <param name="memoryAllocator">The <see cref="MemoryAllocator"/> to use for buffer allocations.</param>
        /// <param name="lengths">The code lengths</param>
        /// <param name="values">The huffman values</param>
        public PdfJsHuffmanTable(MemoryAllocator memoryAllocator, ReadOnlySpan <byte> lengths, ReadOnlySpan <byte> values)
        {
            const int length = 257;

            using (IBuffer <short> huffsize = memoryAllocator.Allocate <short>(length))
                using (IBuffer <short> huffcode = memoryAllocator.Allocate <short>(length))
                {
                    ref short huffsizeRef = ref MemoryMarshal.GetReference(huffsize.GetSpan());
                    ref short huffcodeRef = ref MemoryMarshal.GetReference(huffcode.GetSpan());
Beispiel #12
0
            /// <inheritdoc/>
            protected override void OnFrameApply(ImageFrame <TPixel> source, Rectangle sourceRectangle, Configuration configuration)
            {
                int     startY      = sourceRectangle.Y;
                int     endY        = sourceRectangle.Bottom;
                int     startX      = sourceRectangle.X;
                int     endX        = sourceRectangle.Right;
                TPixel  glowColor   = this.GlowColor;
                Vector2 centre      = Rectangle.Center(sourceRectangle);
                float   maxDistance = this.Radius > 0 ? Math.Min(this.Radius, sourceRectangle.Width * .5F) : sourceRectangle.Width * .5F;

                // 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 (IBuffer <TPixel> rowColors = Configuration.Default.MemoryAllocator.Allocate <TPixel>(width))
                {
                    Buffer2D <TPixel> sourcePixels = source.PixelBuffer;
                    rowColors.GetSpan().Fill(glowColor);

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

                        for (int x = minX; x < maxX; x++)
                        {
                            int offsetX         = x - startX;
                            float distance      = Vector2.Distance(centre, new Vector2(offsetX, offsetY));
                            Vector4 sourceColor = sourcePixels[offsetX, offsetY].ToVector4();
                            TPixel packed       = default(TPixel);
                            packed.PackFromVector4(PremultipliedLerp(sourceColor, glowColor.ToVector4(), 1 - (.95F * (distance / maxDistance))));
                            sourcePixels[offsetX, offsetY] = packed;
                        }
                    });
                }
            }
Beispiel #13
0
        private void TestCanAllocateCleanBuffer <T>(int desiredLength, bool testManagedByteBuffer = false)
            where T : struct, IEquatable <T>
        {
            ReadOnlySpan <T> expected = new T[desiredLength];

            for (int i = 0; i < 10; i++)
            {
                using (IBuffer <T> buffer = this.Allocate <T>(desiredLength, true, testManagedByteBuffer))
                {
                    Assert.True(buffer.GetSpan().SequenceEqual(expected));
                }
            }
        }
Beispiel #14
0
        /// <inheritdoc/>
        public override int Scan(float y, Span <float> buffer, Configuration configuration)
        {
            var start = new PointF(this.Bounds.Left - 1, y);
            var end   = new PointF(this.Bounds.Right + 1, y);

            using (IBuffer <PointF> tempBuffer = configuration.MemoryAllocator.Allocate <PointF>(buffer.Length))
            {
                Span <PointF> innerBuffer = tempBuffer.GetSpan();
                int           count       = this.Shape.FindIntersections(start, end, innerBuffer);

                for (int i = 0; i < count; i++)
                {
                    buffer[i] = innerBuffer[i].X;
                }

                return(count);
            }
        }
Beispiel #15
0
        public Span <byte> GetSpan(int sizeHint = 0)
        {
            var buffer = PipeStream.GetWriteBuffer();

            if (buffer.FreeSpace >= sizeHint)
            {
                mBuffer = buffer;
                return(mBuffer.GetSpan(sizeHint));
            }
            else
            {
                mBuffer = null;
                OnReturn();
                mData = System.Buffers.ArrayPool <byte> .Shared.Rent(sizeHint);

                return(new Span <byte>(mData));
            }
        }
        /// <summary>
        /// TODO: Doesn not work yet!
        /// </summary>
        internal static unsafe Image <TPixel> FromFromRgb24SystemDrawingBitmap <TPixel>(System.Drawing.Bitmap bmp)
            where TPixel : struct, IPixel <TPixel>
        {
            int w = bmp.Width;
            int h = bmp.Height;

            var fullRect = new System.Drawing.Rectangle(0, 0, w, h);

            if (bmp.PixelFormat != PixelFormat.Format24bppRgb)
            {
                throw new ArgumentException($"FromFromArgb32SystemDrawingBitmap(): pixel format should be Rgb24!", nameof(bmp));
            }

            BitmapData data          = bmp.LockBits(fullRect, ImageLockMode.ReadWrite, bmp.PixelFormat);
            byte *     sourcePtrBase = (byte *)data.Scan0;

            long sourceRowByteCount = data.Stride;
            long destRowByteCount   = w * sizeof(Bgr24);

            var image = new Image <TPixel>(w, h);

            using (IBuffer <Bgr24> workBuffer = Configuration.Default.MemoryAllocator.Allocate <Bgr24>(w))
            {
                fixed(Bgr24 *destPtr = &workBuffer.GetReference())
                {
                    for (int y = 0; y < h; y++)
                    {
                        Span <TPixel> row = image.Frames.RootFrame.GetPixelRowSpan(y);

                        byte *sourcePtr = sourcePtrBase + data.Stride * y;

                        Buffer.MemoryCopy(sourcePtr, destPtr, destRowByteCount, sourceRowByteCount);
                        PixelOperations <TPixel> .Instance.PackFromBgr24(workBuffer.GetSpan(), row, row.Length);

                        // FromRgb24(workBuffer.GetSpan(), row);
                    }
                }
            }

            return(image);
        }
            /// <inheritdoc />
            internal override void Apply(Span <float> scanline, int x, int y)
            {
                int             patternY        = y % this.pattern.Rows;
                MemoryAllocator memoryAllocator = this.Target.MemoryAllocator;

                using (IBuffer <float> amountBuffer = memoryAllocator.Allocate <float>(scanline.Length))
                    using (IBuffer <TPixel> overlay = memoryAllocator.Allocate <TPixel>(scanline.Length))
                    {
                        Span <float>  amountSpan  = amountBuffer.GetSpan();
                        Span <TPixel> overlaySpan = overlay.GetSpan();

                        for (int i = 0; i < scanline.Length; i++)
                        {
                            amountSpan[i] = (scanline[i] * this.Options.BlendPercentage).Clamp(0, 1);

                            int patternX = (x + i) % this.pattern.Columns;
                            overlaySpan[i] = this.pattern[patternY, patternX];
                        }

                        Span <TPixel> destinationRow = this.Target.GetPixelRowSpan(y).Slice(x, scanline.Length);
                        this.Blender.Blend(memoryAllocator, destinationRow, destinationRow, overlaySpan, amountSpan);
                    }
            }
Beispiel #18
0
        /// <inheritdoc/>
        protected override void OnFrameApply(ImageFrame <TPixel> source, Rectangle sourceRectangle, Configuration configuration)
        {
            Image <TPixel>        targetImage = this.Image;
            PixelBlender <TPixel> blender     = this.Blender;
            int locationY = this.Location.Y;

            // Align start/end positions.
            Rectangle bounds = targetImage.Bounds();

            int minX    = Math.Max(this.Location.X, sourceRectangle.X);
            int maxX    = Math.Min(this.Location.X + bounds.Width, sourceRectangle.Width);
            int targetX = minX - this.Location.X;

            int minY = Math.Max(this.Location.Y, sourceRectangle.Y);
            int maxY = Math.Min(this.Location.Y + bounds.Height, sourceRectangle.Bottom);

            int width = maxX - minX;

            MemoryAllocator memoryAllocator = this.Image.GetConfiguration().MemoryAllocator;

            using (IBuffer <float> amount = memoryAllocator.Allocate <float>(width))
            {
                amount.GetSpan().Fill(this.Opacity);

                Parallel.For(
                    minY,
                    maxY,
                    configuration.ParallelOptions,
                    y =>
                {
                    Span <TPixel> background = source.GetPixelRowSpan(y).Slice(minX, width);
                    Span <TPixel> foreground = targetImage.GetPixelRowSpan(y - locationY).Slice(targetX, width);
                    blender.Blend(memoryAllocator, background, background, foreground, amount.GetSpan());
                });
            }
        }
 public static void Clear <T>(this IBuffer <T> buffer)
     where T : struct
 {
     buffer.GetSpan().Clear();
 }
Beispiel #20
0
        /// <summary>
        /// Initializes a new instance of the <see cref="PdfJsHuffmanTable"/> struct.
        /// </summary>
        /// <param name="memoryAllocator">The <see cref="MemoryAllocator"/> to use for buffer allocations.</param>
        /// <param name="count">The code lengths</param>
        /// <param name="values">The huffman values</param>
        public PdfJsHuffmanTable(MemoryAllocator memoryAllocator, ReadOnlySpan <byte> count, ReadOnlySpan <byte> values)
        {
            const int Length = 257;

            using (IBuffer <short> huffcode = memoryAllocator.Allocate <short>(Length))
            {
                ref short huffcodeRef = ref MemoryMarshal.GetReference(huffcode.GetSpan());

                // Figure C.1: make table of Huffman code length for each symbol
                fixed(short *sizesRef = this.Sizes.Data)
                {
                    short x = 0;

                    for (short i = 1; i < 17; i++)
                    {
                        byte l = count[i];
                        for (short j = 0; j < l; j++)
                        {
                            sizesRef[x] = i;
                            x++;
                        }
                    }

                    sizesRef[x] = 0;

                    // Figure C.2: generate the codes themselves
                    int k = 0;

                    fixed(int *valOffsetRef = this.ValOffset.Data)
                    fixed(uint *maxcodeRef = this.MaxCode.Data)
                    {
                        uint code = 0;
                        int  j;

                        for (j = 1; j < 17; j++)
                        {
                            // Compute delta to add to code to compute symbol id.
                            valOffsetRef[j] = (int)(k - code);
                            if (sizesRef[k] == j)
                            {
                                while (sizesRef[k] == j)
                                {
                                    Unsafe.Add(ref huffcodeRef, k++) = (short)code++;
                                }
                            }

                            // Figure F.15: generate decoding tables for bit-sequential decoding.
                            // Compute largest code + 1 for this size. preshifted as need later.
                            maxcodeRef[j] = code << (16 - j);
                            code        <<= 1;
                        }

                        maxcodeRef[j] = 0xFFFFFFFF;
                    }

                    // Generate non-spec lookup tables to speed up decoding.
                    fixed(byte *lookaheadRef = this.Lookahead.Data)
                    {
                        const int FastBits = ScanDecoder.FastBits;
                        var       fast     = new Span <byte>(lookaheadRef, 1 << FastBits);

                        fast.Fill(0xFF); // Flag for non-accelerated

                        for (int i = 0; i < k; i++)
                        {
                            int s = sizesRef[i];
                            if (s <= ScanDecoder.FastBits)
                            {
                                int c = Unsafe.Add(ref huffcodeRef, i) << (FastBits - s);
                                int m = 1 << (FastBits - s);
                                for (int j = 0; j < m; j++)
                                {
                                    fast[c + j] = (byte)i;
                                }
                            }
                        }
                    }
                }
            }
        /// <inheritdoc/>
        protected override void OnFrameApply(ImageFrame <TPixel> source, Rectangle sourceRectangle, Configuration configuration)
        {
            int startX = sourceRectangle.X;
            int endX   = sourceRectangle.Right;
            int startY = sourceRectangle.Y;
            int endY   = sourceRectangle.Bottom;

            // 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);

            int width = maxX - minX;

            // If there's no reason for blending, then avoid it.
            if (this.IsSolidBrushWithoutBlending(out SolidBrush <TPixel> solidBrush))
            {
                Parallel.For(
                    minY,
                    maxY,
                    configuration.ParallelOptions,
                    y =>
                {
                    source.GetPixelRowSpan(y).Slice(minX, width).Fill(solidBrush.Color);
                });
            }
            else
            {
                // Reset offset if necessary.
                if (minX > 0)
                {
                    startX = 0;
                }

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

                using (IBuffer <float> amount = source.MemoryAllocator.Allocate <float>(width))
                    using (BrushApplicator <TPixel> applicator = this.brush.CreateApplicator(
                               source,
                               sourceRectangle,
                               this.options))
                    {
                        amount.GetSpan().Fill(1f);

                        Parallel.For(
                            minY,
                            maxY,
                            configuration.ParallelOptions,
                            y =>
                        {
                            int offsetY = y - startY;
                            int offsetX = minX - startX;

                            applicator.Apply(amount.GetSpan(), offsetX, offsetY);
                        });
                    }
            }
        }
Beispiel #22
0
            private Buffer2D <float> Render(IPath path)
            {
                Size size = Rectangle.Ceiling(path.Bounds).Size;

                size = new Size(size.Width + (this.offset * 2), size.Height + (this.offset * 2));

                float subpixelCount = 4;
                float offset        = 0.5f;

                if (this.Options.Antialias)
                {
                    offset        = 0f; // we are antialising skip offsetting as real antalising should take care of offset.
                    subpixelCount = this.Options.AntialiasSubpixelDepth;
                    if (subpixelCount < 4)
                    {
                        subpixelCount = 4;
                    }
                }

                // take the path inside the path builder, scan thing and generate a Buffer2d representing the glyph and cache it.
                Buffer2D <float> fullBuffer = this.MemoryAllocator.Allocate2D <float>(size.Width + 1, size.Height + 1, true);

                using (IBuffer <float> bufferBacking = this.MemoryAllocator.Allocate <float>(path.MaxIntersections))
                    using (IBuffer <PointF> rowIntersectionBuffer = this.MemoryAllocator.Allocate <PointF>(size.Width))
                    {
                        float subpixelFraction      = 1f / subpixelCount;
                        float subpixelFractionPoint = subpixelFraction / subpixelCount;

                        for (int y = 0; y <= size.Height; y++)
                        {
                            Span <float> scanline      = fullBuffer.GetRowSpan(y);
                            bool         scanlineDirty = false;
                            float        yPlusOne      = y + 1;

                            for (float subPixel = (float)y; subPixel < yPlusOne; subPixel += subpixelFraction)
                            {
                                var           start            = new PointF(path.Bounds.Left - 1, subPixel);
                                var           end              = new PointF(path.Bounds.Right + 1, subPixel);
                                Span <PointF> intersectionSpan = rowIntersectionBuffer.GetSpan();
                                Span <float>  buffer           = bufferBacking.GetSpan();
                                int           pointsFound      = path.FindIntersections(start, end, intersectionSpan);

                                if (pointsFound == 0)
                                {
                                    // nothing on this line skip
                                    continue;
                                }

                                for (int i = 0; i < pointsFound && i < intersectionSpan.Length; i++)
                                {
                                    buffer[i] = intersectionSpan[i].X;
                                }

                                QuickSort.Sort(buffer.Slice(0, pointsFound));

                                for (int point = 0; point < pointsFound; point += 2)
                                {
                                    // points will be paired up
                                    float scanStart = buffer[point];
                                    float scanEnd   = buffer[point + 1];
                                    int   startX    = (int)MathF.Floor(scanStart + offset);
                                    int   endX      = (int)MathF.Floor(scanEnd + offset);

                                    if (startX >= 0 && startX < scanline.Length)
                                    {
                                        for (float x = scanStart; x < startX + 1; x += subpixelFraction)
                                        {
                                            scanline[startX] += subpixelFractionPoint;
                                            scanlineDirty     = true;
                                        }
                                    }

                                    if (endX >= 0 && endX < scanline.Length)
                                    {
                                        for (float x = endX; x < scanEnd; x += subpixelFraction)
                                        {
                                            scanline[endX] += subpixelFractionPoint;
                                            scanlineDirty   = true;
                                        }
                                    }

                                    int nextX = startX + 1;
                                    endX  = Math.Min(endX, scanline.Length); // reduce to end to the right edge
                                    nextX = Math.Max(nextX, 0);
                                    for (int x = nextX; x < endX; x++)
                                    {
                                        scanline[x]  += subpixelFraction;
                                        scanlineDirty = true;
                                    }
                                }
                            }

                            if (scanlineDirty)
                            {
                                if (!this.Options.Antialias)
                                {
                                    for (int x = 0; x < size.Width; x++)
                                    {
                                        if (scanline[x] >= 0.5)
                                        {
                                            scanline[x] = 1;
                                        }
                                        else
                                        {
                                            scanline[x] = 0;
                                        }
                                    }
                                }
                            }
                        }
                    }

                return(fullBuffer);
            }
            // [Fact] // Profiling benchmark - enable manually!
#pragma warning disable xUnit1013 // Public method should be marked as test
            public void Benchmark_ToVector4()
#pragma warning restore xUnit1013 // Public method should be marked as test
            {
                int times = 200000;
                int count = 1024;

                using (IBuffer <ImageSharp.PixelFormats.Rgba32> source = Configuration.Default.MemoryAllocator.Allocate <ImageSharp.PixelFormats.Rgba32>(count))
                    using (IBuffer <Vector4> dest = Configuration.Default.MemoryAllocator.Allocate <Vector4>(count))
                    {
                        this.Measure(
                            times,
                            () =>
                        {
                            PixelOperations <ImageSharp.PixelFormats.Rgba32> .Instance.ToVector4(source.GetSpan(), dest.GetSpan(), count);
                        });
                    }
            }
 public static ref T GetReference <T>(this IBuffer <T> buffer)
     where T : struct =>
 ref MemoryMarshal.GetReference(buffer.GetSpan());
        /// <inheritdoc/>
        protected override void OnFrameApply(ImageFrame <TPixel> source, Rectangle sourceRectangle, Configuration configuration)
        {
            Region    region = this.Region;
            Rectangle rect   = region.Bounds;

            // Align start/end positions.
            int minX = Math.Max(0, rect.Left);
            int maxX = Math.Min(source.Width, rect.Right);
            int minY = Math.Max(0, rect.Top);
            int maxY = Math.Min(source.Height, rect.Bottom);

            if (minX >= maxX)
            {
                return; // no effect inside image;
            }

            if (minY >= maxY)
            {
                return; // no effect inside image;
            }

            int   maxIntersections = region.MaxIntersections;
            float subpixelCount    = 4;

            // we need to offset the pixel grid to account for when we outline a path.
            // basically if the line is [1,2] => [3,2] then when outlining at 1 we end up with a region of [0.5,1.5],[1.5, 1.5],[3.5,2.5],[2.5,2.5]
            // and this can cause missed fills when not using antialiasing.so we offset the pixel grid by 0.5 in the x & y direction thus causing the#
            // region to alline with the pixel grid.
            float offset = 0.5f;

            if (this.Options.Antialias)
            {
                offset        = 0f; // we are antialising skip offsetting as real antalising should take care of offset.
                subpixelCount = this.Options.AntialiasSubpixelDepth;
                if (subpixelCount < 4)
                {
                    subpixelCount = 4;
                }
            }

            using (BrushApplicator <TPixel> applicator = this.Brush.CreateApplicator(source, rect, this.Options))
            {
                int scanlineWidth = maxX - minX;
                using (IBuffer <float> bBuffer = source.MemoryAllocator.Allocate <float>(maxIntersections))
                    using (IBuffer <float> bScanline = source.MemoryAllocator.Allocate <float>(scanlineWidth))
                    {
                        bool  scanlineDirty         = true;
                        float subpixelFraction      = 1f / subpixelCount;
                        float subpixelFractionPoint = subpixelFraction / subpixelCount;

                        Span <float> buffer   = bBuffer.GetSpan();
                        Span <float> scanline = bScanline.GetSpan();

                        for (int y = minY; y < maxY; y++)
                        {
                            if (scanlineDirty)
                            {
                                scanline.Clear();
                                scanlineDirty = false;
                            }

                            float yPlusOne = y + 1;
                            for (float subPixel = (float)y; subPixel < yPlusOne; subPixel += subpixelFraction)
                            {
                                int pointsFound = region.Scan(subPixel + offset, buffer, configuration);
                                if (pointsFound == 0)
                                {
                                    // nothing on this line skip
                                    continue;
                                }

                                QuickSort.Sort(buffer.Slice(0, pointsFound));

                                for (int point = 0; point < pointsFound; point += 2)
                                {
                                    // points will be paired up
                                    float scanStart = buffer[point] - minX;
                                    float scanEnd   = buffer[point + 1] - minX;
                                    int   startX    = (int)MathF.Floor(scanStart + offset);
                                    int   endX      = (int)MathF.Floor(scanEnd + offset);

                                    if (startX >= 0 && startX < scanline.Length)
                                    {
                                        for (float x = scanStart; x < startX + 1; x += subpixelFraction)
                                        {
                                            scanline[startX] += subpixelFractionPoint;
                                            scanlineDirty     = true;
                                        }
                                    }

                                    if (endX >= 0 && endX < scanline.Length)
                                    {
                                        for (float x = endX; x < scanEnd; x += subpixelFraction)
                                        {
                                            scanline[endX] += subpixelFractionPoint;
                                            scanlineDirty   = true;
                                        }
                                    }

                                    int nextX = startX + 1;
                                    endX  = Math.Min(endX, scanline.Length); // reduce to end to the right edge
                                    nextX = Math.Max(nextX, 0);
                                    for (int x = nextX; x < endX; x++)
                                    {
                                        scanline[x]  += subpixelFraction;
                                        scanlineDirty = true;
                                    }
                                }
                            }

                            if (scanlineDirty)
                            {
                                if (!this.Options.Antialias)
                                {
                                    for (int x = 0; x < scanlineWidth; x++)
                                    {
                                        if (scanline[x] >= 0.5)
                                        {
                                            scanline[x] = 1;
                                        }
                                        else
                                        {
                                            scanline[x] = 0;
                                        }
                                    }
                                }

                                applicator.Apply(scanline, minX, y);
                            }
                        }
                    }
            }
        }
 public static int Length <T>(this IBuffer <T> buffer)
     where T : struct => buffer.GetSpan().Length;
        /// <inheritdoc/>
        protected override void OnFrameApply(ImageFrame <TPixel> source, Rectangle sourceRectangle, Configuration configuration)
        {
            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);

            Size  sourceSize   = source.Size();
            float finalRadiusX = this.RadiusX.Calculate(sourceSize);
            float finalRadiusY = this.RadiusY.Calculate(sourceSize);
            float rX           = finalRadiusX > 0 ? MathF.Min(finalRadiusX, sourceRectangle.Width * .5F) : sourceRectangle.Width * .5F;
            float rY           = finalRadiusY > 0 ? MathF.Min(finalRadiusY, 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 (IBuffer <TPixel> rowColors = source.MemoryAllocator.Allocate <TPixel>(width))
            {
                // Be careful! Do not capture rowColorsSpan in the lambda below!
                Span <TPixel> rowColorsSpan = rowColors.GetSpan();

                for (int i = 0; i < width; i++)
                {
                    rowColorsSpan[i] = vignetteColor;
                }

                Parallel.For(
                    minY,
                    maxY,
                    configuration.ParallelOptions,
                    y =>
                {
                    using (IBuffer <float> amounts = source.MemoryAllocator.Allocate <float>(width))
                    {
                        Span <float> amountsSpan = amounts.GetSpan();
                        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));
                            amountsSpan[i] = (this.GraphicsOptions.BlendPercentage * (.9F * (distance / maxDistance))).Clamp(0, 1);
                        }

                        Span <TPixel> destination = source.GetPixelRowSpan(offsetY).Slice(offsetX, width);

                        this.blender.Blend(source.MemoryAllocator, destination, destination, rowColors.GetSpan(), amountsSpan);
                    }
                });
            }
        }
 public static Span <T> Slice <T>(this IBuffer <T> buffer, int start, int length)
     where T : struct
 {
     return(buffer.GetSpan().Slice(start, length));
 }