/// <inheritdoc/>
        protected override void OnFrameApply(ImageFrame <TPixelDst> source, Rectangle sourceRectangle, Configuration configuration)
        {
            Image <TPixelSrc>        targetImage = this.Image;
            PixelBlender <TPixelDst> 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;

            var workingRect = Rectangle.FromLTRB(minX, minY, maxX, maxY);

            ParallelHelper.IterateRows(
                workingRect,
                configuration,
                rows =>
            {
                for (int y = rows.Min; y < rows.Max; y++)
                {
                    Span <TPixelDst> background = source.GetPixelRowSpan(y).Slice(minX, width);
                    Span <TPixelSrc> foreground =
                        targetImage.GetPixelRowSpan(y - locationY).Slice(targetX, width);
                    blender.Blend <TPixelSrc>(configuration, background, background, foreground, this.Opacity);
                }
            });
        }
Beispiel #2
0
        /// <summary>
        /// Initializes a new instance of the <see cref="VignetteProcessor{TPixel}" /> class.
        /// </summary>
        /// <param name="color">The color of the vignette.</param>
        /// <param name="options">The options effecting blending and composition.</param>
        public VignetteProcessor(TPixel color, GraphicsOptions options)
        {
            this.VignetteColor = color;

            this.options = options;
            this.blender = PixelOperations <TPixel> .Instance.GetPixelBlender(this.options.BlenderMode);
        }
        /// <inheritdoc/>
        protected override void OnFrameApply(ImageFrame <TPixelDst> source, Rectangle sourceRectangle, Configuration configuration)
        {
            Image <TPixelSrc>        targetImage = this.Image;
            PixelBlender <TPixelDst> 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;

            ParallelFor.WithConfiguration(
                minY,
                maxY,
                configuration,
                y =>
            {
                Span <TPixelDst> background = source.GetPixelRowSpan(y).Slice(minX, width);
                Span <TPixelSrc> foreground = targetImage.GetPixelRowSpan(y - locationY).Slice(targetX, width);
                blender.Blend <TPixelSrc>(memoryAllocator, background, background, foreground, this.Opacity);
            });
        }
        public static IPixelBlender GetBlender(PixelFormat backBuffer, Endianess backBufferEndianess, PixelFormat fronBuffer, Endianess frontBufferEndianes, PixelFormat output, Endianess outputEndianess, PixelFormat?clutForegroundFormat = null, PixelFormat?clutBackgroundFormat = null)
        {
            var blenderConfiguration = Tuple.Create(backBuffer, backBufferEndianess, fronBuffer, frontBufferEndianes, output, outputEndianess);

            if (!blendersCache.ContainsKey(blenderConfiguration))
            {
                blendersCache[blenderConfiguration] = new PixelBlender(backBuffer, fronBuffer, output,
                                                                       GenerateBlendMethod(
                                                                           new BufferDescriptor
                {
                    ColorFormat     = backBuffer,
                    ClutColorFormat = clutBackgroundFormat,
                    DataEndianness  = backBufferEndianess
                },
                                                                           new BufferDescriptor
                {
                    ColorFormat     = fronBuffer,
                    ClutColorFormat = clutForegroundFormat,
                    DataEndianness  = frontBufferEndianes
                },
                                                                           new BufferDescriptor
                {
                    ColorFormat    = output,
                    DataEndianness = outputEndianess
                }));
            }
            return(blendersCache[blenderConfiguration]);
        }
        public void ReturnsCorrectBlender <TPixel>(TestPixel <TPixel> pixel, Type type, PixelBlenderMode mode)
            where TPixel : struct, IPixel <TPixel>
        {
            PixelBlender <TPixel> blender = PixelOperations <TPixel> .Instance.GetPixelBlender(mode);

            Assert.IsType(type, blender);
        }
Beispiel #6
0
 /// <summary>
 /// Initializes a new instance of the <see cref="GlowProcessor{TPixel}" /> class.
 /// </summary>
 /// <param name="color">The color or the glow.</param>
 /// <param name="radius">The radius of the glow.</param>
 /// <param name="options">The options effecting blending and composition.</param>
 public GlowProcessor(TPixel color, ValueSize radius, GraphicsOptions options)
 {
     this.options   = options;
     this.GlowColor = color;
     this.Radius    = radius;
     this.blender   = PixelOperations <TPixel> .Instance.GetPixelBlender(this.options.BlenderMode);
 }
Beispiel #7
0
        public void ReturnsCorrectBlender <TPixel>(TestPixel <TPixel> pixel, Type type, PixelColorBlendingMode mode)
            where TPixel : unmanaged, IPixel <TPixel>
        {
            PixelBlender <TPixel> blender = PixelOperations <TPixel> .Instance.GetPixelBlender(mode, PixelAlphaCompositionMode.SrcOver);

            Assert.IsType(type, blender);
        }
Beispiel #8
0
        /// <inheritdoc />
        protected override void OnFrameApply(ImageFrame <TPixelBg> source)
        {
            SixLabors.ImageSharp.Rectangle sourceRectangle = this.SourceRectangle;
            Configuration configuration = this.Configuration;

            SixLabors.ImageSharp.Image <TPixelFg> image = this.Image;
            PixelBlender <TPixelBg> blender             = this.Blender;
            int y = this.Location.Y;

            SixLabors.ImageSharp.Rectangle rectangle1 = image.Bounds();
            int num     = Math.Max(this.Location.X, sourceRectangle.X);
            int right   = Math.Min(this.Location.X + rectangle1.Width, sourceRectangle.Right);
            int targetX = num - this.Location.X;
            int top     = Math.Max(this.Location.Y, sourceRectangle.Y);
            int bottom  = Math.Min(this.Location.Y + rectangle1.Height, sourceRectangle.Bottom);
            int width   = right - num;

            SixLabors.ImageSharp.Rectangle rectangle2 = SixLabors.ImageSharp.Rectangle.FromLTRB(num, top, right, bottom);

            if (rectangle2.Width <= 0 || rectangle2.Height <= 0)
            {
                throw new ImageProcessingException(
                          "Cannot draw image because the source image does not overlap the target image.");
            }

            InterpolateProcessor <TPixelBg, TPixelFg> .RowOperation operation =
                new InterpolateProcessor <TPixelBg, TPixelFg> .RowOperation(
                    source, image, blender, configuration, num, width, y, targetX, InterpolationValue);

            ParallelRowIterator.IterateRows <InterpolateProcessor <TPixelBg, TPixelFg> .RowOperation>(
                configuration, rectangle2, in operation);
        }
Beispiel #9
0
 public static IPixelBlender GetBlender(PixelFormat backBuffer, Endianess backBufferEndianess, PixelFormat fronBuffer, Endianess frontBufferEndianes, PixelFormat output, Endianess outputEndianess, PixelFormat? clutForegroundFormat = null, PixelFormat? clutBackgroundFormat = null)
 {
     var blenderConfiguration = Tuple.Create(backBuffer, backBufferEndianess, fronBuffer, frontBufferEndianes, output, outputEndianess);
     if(!blendersCache.ContainsKey(blenderConfiguration))
     {
         blendersCache[blenderConfiguration] = new PixelBlender(backBuffer, fronBuffer, output, 
             GenerateBlendMethod(
                 new BufferDescriptor 
                 {
                     ColorFormat = backBuffer,
                     ClutColorFormat = clutBackgroundFormat,
                     DataEndianness = backBufferEndianess
                 },
                 new BufferDescriptor 
                 {
                     ColorFormat = fronBuffer,
                     ClutColorFormat = clutForegroundFormat,
                     DataEndianness = frontBufferEndianes
                 },
                 new BufferDescriptor 
                 {
                     ColorFormat = output,
                     DataEndianness = outputEndianess
                 }));
     }
     return blendersCache[blenderConfiguration];
 }
Beispiel #10
0
        public void BlendFillColorOverBackround <TPixel>(
            TestImageProvider <TPixel> provider,
            bool triggerFillRegion,
            string newColorName,
            float alpha,
            PixelBlenderMode blenderMode,
            float blendPercentage)
            where TPixel : struct, IPixel <TPixel>
        {
            var vec = TestUtils.GetPixelOfNamedColor <RgbaVector>(newColorName).ToVector4();

            vec.W = alpha;

            TPixel fillColor = default;

            fillColor.PackFromVector4(vec);

            using (Image <TPixel> image = provider.GetImage())
            {
                TPixel bgColor = image[0, 0];

                var options = new GraphicsOptions(false)
                {
                    BlenderMode     = blenderMode,
                    BlendPercentage = blendPercentage
                };

                if (triggerFillRegion)
                {
                    var region = new ShapeRegion(new RectangularPolygon(0, 0, 16, 16));

                    image.Mutate(c => c.Fill(options, new SolidBrush <TPixel>(fillColor), region));
                }
                else
                {
                    image.Mutate(c => c.Fill(options, new SolidBrush <TPixel>(fillColor)));
                }

                var testOutputDetails = new
                {
                    triggerFillRegion = triggerFillRegion,
                    newColorName      = newColorName,
                    alpha             = alpha,
                    blenderMode       = blenderMode,
                    blendPercentage   = blendPercentage
                };

                image.DebugSave(
                    provider,
                    testOutputDetails,
                    appendPixelTypeToFileName: false,
                    appendSourceFileOrDescription: false);

                PixelBlender <TPixel> blender = PixelOperations <TPixel> .Instance.GetPixelBlender(blenderMode);

                TPixel expectedPixel = blender.Blend(bgColor, fillColor, blendPercentage);

                image.ComparePixelBufferTo(expectedPixel);
            }
        }
Beispiel #11
0
        public void BlendFillColorOverBackground <TPixel>(
            TestImageProvider <TPixel> provider,
            bool triggerFillRegion,
            string newColorName,
            float alpha,
            PixelColorBlendingMode blenderMode,
            float blendPercentage)
            where TPixel : unmanaged, IPixel <TPixel>
        {
            Color fillColor = TestUtils.GetColorByName(newColorName).WithAlpha(alpha);

            using (Image <TPixel> image = provider.GetImage())
            {
                TPixel bgColor = image[0, 0];

                var options = new DrawingOptions
                {
                    GraphicsOptions = new GraphicsOptions
                    {
                        Antialias         = false,
                        ColorBlendingMode = blenderMode,
                        BlendPercentage   = blendPercentage
                    }
                };

                if (triggerFillRegion)
                {
                    var path = new RectangularPolygon(0, 0, 16, 16);
                    image.Mutate(c => c.SetGraphicsOptions(options.GraphicsOptions).Fill(new SolidBrush(fillColor), path));
                }
                else
                {
                    image.Mutate(c => c.Fill(options, new SolidBrush(fillColor)));
                }

                var testOutputDetails = new
                {
                    triggerFillRegion,
                    newColorName,
                    alpha,
                    blenderMode,
                    blendPercentage
                };

                image.DebugSave(
                    provider,
                    testOutputDetails,
                    appendPixelTypeToFileName: false,
                    appendSourceFileOrDescription: false);

                PixelBlender <TPixel> blender = PixelOperations <TPixel> .Instance.GetPixelBlender(
                    blenderMode,
                    PixelAlphaCompositionMode.SrcOver);

                TPixel expectedPixel = blender.Blend(bgColor, fillColor.ToPixel <TPixel>(), blendPercentage);

                image.ComparePixelBufferTo(expectedPixel);
            }
        }
Beispiel #12
0
        public DXT1Texture(int id, int width, int height, int levels, Endianness endianness, Stream stream) : base(id, width, height, levels, stream)
        {
            Endianness = endianness;

            Words  = new UInt16Serializer(Endianness);
            Pixels = PixelOperations <RgbaVector> .Instance
                     .GetPixelBlender(new GraphicsOptions());
        }
Beispiel #13
0
 /// <summary>
 /// Initializes a new instance of the <see cref="VignetteProcessor{TPixel}" /> class.
 /// </summary>
 /// <param name="color">The color of the vignette.</param>
 /// <param name="radiusX">The x-radius.</param>
 /// <param name="radiusY">The y-radius.</param>
 /// <param name="options">The options effecting blending and composition.</param>
 public VignetteProcessor(TPixel color, ValueSize radiusX, ValueSize radiusY, GraphicsOptions options)
 {
     this.VignetteColor = color;
     this.RadiusX       = radiusX;
     this.RadiusY       = radiusY;
     this.options       = options;
     this.blender       = PixelOperations <TPixel> .Instance.GetPixelBlender(this.options.BlenderMode);
 }
 public static IPixelBlender GetBlender(PixelFormat backBuffer, Endianess backBufferEndianess, PixelFormat fronBuffer, Endianess frontBufferEndianes, PixelFormat output, Endianess outputEndianess)
 {
     var tuple = Tuple.Create(backBuffer, backBufferEndianess, fronBuffer, frontBufferEndianes, output, outputEndianess);
     if(!blendersCache.ContainsKey(tuple))
     {
         blendersCache[tuple] = new PixelBlender(backBuffer, fronBuffer, output, GenerateBlendMethod(backBuffer, backBufferEndianess, fronBuffer, frontBufferEndianes, output, outputEndianess));
     }
     return blendersCache[tuple];
 }
Beispiel #15
0
        public void TestAlphaCompositionModes(Rgba32 backdrop, Rgba32 source, float opacity, PixelAlphaCompositionMode mode, Rgba32 expectedResult)
        {
            PixelBlender <Rgba32> blender = PixelOperations <Rgba32> .Instance.GetPixelBlender(PixelColorBlendingMode.Normal, mode);

            Rgba32 actualResult = blender.Blend(backdrop, source, opacity);

            // var str = actualResult.Rgba.ToString("X8"); // used to extract expectedResults
            Assert.Equal(actualResult.ToVector4(), expectedResult.ToVector4());
        }
        public static IPixelBlender GetBlender(PixelFormat backBuffer, Endianess backBufferEndianess, PixelFormat fronBuffer, Endianess frontBufferEndianes, PixelFormat output, Endianess outputEndianess)
        {
            var tuple = Tuple.Create(backBuffer, backBufferEndianess, fronBuffer, frontBufferEndianes, output, outputEndianess);

            if (!blendersCache.ContainsKey(tuple))
            {
                blendersCache[tuple] = new PixelBlender(backBuffer, fronBuffer, output, GenerateBlendMethod(backBuffer, backBufferEndianess, fronBuffer, frontBufferEndianes, output, outputEndianess));
            }
            return(blendersCache[tuple]);
        }
Beispiel #17
0
        /// <summary>
        /// Initializes a new instance of the <see cref="DrawImageProcessor{TPixel}"/> class.
        /// </summary>
        /// <param name="image">The image to blend with the currently processing image.</param>
        /// <param name="size">The size to draw the blended image.</param>
        /// <param name="location">The location to draw the blended image.</param>
        /// <param name="options">The opacity of the image to blend. Between 0 and 100.</param>
        public DrawImageProcessor(Image <TPixel> image, Size size, Point location, GraphicsOptions options)
        {
            Guard.MustBeBetweenOrEqualTo(options.BlendPercentage, 0, 1, nameof(options.BlendPercentage));
            this.Image   = image;
            this.Size    = size;
            this.Alpha   = options.BlendPercentage;
            this.blender = PixelOperations <TPixel> .Instance.GetPixelBlender(options.BlenderMode);

            this.Location = location;
        }
Beispiel #18
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());
                    });
                }
        }
        /// <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;

            // 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> colors = new Buffer <TPixel>(width))
                using (Buffer <float> amount = new Buffer <float>(width))
                    using (PixelAccessor <TPixel> sourcePixels = source.Lock())
                    {
                        for (int i = 0; i < width; i++)
                        {
                            colors[i] = this.Value;
                            amount[i] = this.options.BlendPercentage;
                        }

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

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

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

                            // this switched color & destination in the 2nd and 3rd places because we are applying the target colour under the current one
                            blender.Blend(destination, colors, destination, amount);
                        });
                    }
        }
 public RowIntervalOperation(
     ImageFrame <TPixelBg> sourceFrame,
     Image <TPixelFg> targetImage,
     PixelBlender <TPixelBg> blender,
     Configuration configuration,
     int width)
 {
     this.sourceFrame   = sourceFrame;
     this.targetImage   = targetImage;
     this.blender       = blender;
     this.configuration = configuration;
     this.width         = width;
 }
        /// <inheritdoc/>
        protected override void OnFrameApply(
            ImageFrame <TPixelBg> source,
            Rectangle sourceRectangle,
            Configuration configuration)
        {
            Image <TPixelFg>        targetImage = this.Image;
            PixelBlender <TPixelBg> 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.Right);
            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;

            var workingRect = Rectangle.FromLTRB(minX, minY, maxX, maxY);

            // not a valid operation because rectangle does not overlap with this image.
            if (workingRect.Width <= 0 || workingRect.Height <= 0)
            {
                throw new ImageProcessingException(
                          "Cannot draw image because the source image does not overlap the target image.");
            }

            ParallelHelper.IterateRows(
                workingRect,
                configuration,
                rows =>
            {
                for (int y = rows.Min; y < rows.Max; y++)
                {
                    Span <TPixelBg> background = source.GetPixelRowSpan(y).Slice(minX, width);
                    Span <TPixelFg> foreground =
                        targetImage.GetPixelRowSpan(y - locationY).Slice(targetX, width);
                    blender.Blend <TPixelFg>(configuration, background, background, foreground, this.Opacity);
                }
            });
        }
 public RowOperation(
     Configuration configuration,
     Rectangle bounds,
     IMemoryOwner <TPixel> colors,
     PixelBlender <TPixel> blender,
     Vector2 center,
     float maxDistance,
     float blendPercent,
     ImageFrame <TPixel> source)
 {
     this.configuration = configuration;
     this.bounds        = bounds;
     this.colors        = colors;
     this.blender       = blender;
     this.center        = center;
     this.maxDistance   = maxDistance;
     this.blendPercent  = blendPercent;
     this.source        = source;
 }
Beispiel #23
0
 public RowOperation(ImageFrame <TPixelBg> sourceFrame,
                     SixLabors.ImageSharp.Image <TPixelFg> targetImage,
                     PixelBlender <TPixelBg> blender,
                     Configuration configuration,
                     int minX,
                     int width,
                     int locationY,
                     int targetX,
                     float interpolationValue)
 {
     this.sourceFrame        = sourceFrame;
     this.targetImage        = targetImage;
     this.blender            = blender;
     this.configuration      = configuration;
     this.minX               = minX;
     this.width              = width;
     this.locationY          = locationY;
     this.targetX            = targetX;
     this.interpolationValue = interpolationValue;
 }
Beispiel #24
0
 public RowOperation(
     Buffer2D <TPixelBg> source,
     Buffer2D <TPixelFg> target,
     PixelBlender <TPixelBg> blender,
     Configuration configuration,
     int minX,
     int width,
     int locationY,
     int targetX,
     float opacity)
 {
     this.source        = source;
     this.target        = target;
     this.blender       = blender;
     this.configuration = configuration;
     this.minX          = minX;
     this.width         = width;
     this.locationY     = locationY;
     this.targetX       = targetX;
     this.opacity       = opacity;
 }
 public RowOperation(
     ImageFrame <TPixelBg> sourceFrame,
     Image <TPixelFg> targetImage,
     PixelBlender <TPixelBg> blender,
     Configuration configuration,
     int minX,
     int width,
     int locationY,
     int targetX,
     float opacity)
 {
     this.sourceFrame   = sourceFrame;
     this.targetImage   = targetImage;
     this.blender       = blender;
     this.configuration = configuration;
     this.minX          = minX;
     this.width         = width;
     this.locationY     = locationY;
     this.targetX       = targetX;
     this.opacity       = opacity;
 }
        /// <inheritdoc/>
        protected override void OnFrameApply(ImageFrame <TPixelBg> source)
        {
            Rectangle     sourceRectangle = this.SourceRectangle;
            Configuration configuration   = this.Configuration;

            Image <TPixelFg>        targetImage = this.Image;
            PixelBlender <TPixelBg> 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.Right);
            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;

            var workingRect = Rectangle.FromLTRB(minX, minY, maxX, maxY);

            // Not a valid operation because rectangle does not overlap with this image.
            if (workingRect.Width <= 0 || workingRect.Height <= 0)
            {
                throw new ImageProcessingException(
                          "Cannot draw image because the source image does not overlap the target image.");
            }

            var operation = new RowOperation(source, targetImage, blender, configuration, minX, width, locationY, targetX, this.Opacity);

            ParallelRowIterator.IterateRows(
                configuration,
                workingRect,
                in operation);
        }
Beispiel #27
0
        /// <inheritdoc/>
        protected override void OnApply(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;

            using (var amount = new Buffer <float>(width))
            {
                for (int i = 0; i < width; i++)
                {
                    amount[i] = 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(background, background, foreground, amount);
                });
            }
        }
Beispiel #28
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;

            MemoryManager memoryManager = this.Image.GetConfiguration().MemoryManager;

            using (IBuffer <float> amount = memoryManager.Allocate <float>(width))
            {
                amount.Span.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(memoryManager, background, background, foreground, amount.Span);
                });
            }
        }
 /// <summary>
 /// Initializes a new instance of the <see cref="GlowProcessor{TPixel}"/> class.
 /// </summary>
 /// <param name="configuration">The configuration which allows altering default behaviour or extending the library.</param>
 /// <param name="definition">The <see cref="GlowProcessor"/> defining the processor parameters.</param>
 /// <param name="source">The source <see cref="Image{TPixel}"/> for the current processor instance.</param>
 /// <param name="sourceRectangle">The source area to process for the current processor instance.</param>
 public GlowProcessor(Configuration configuration, GlowProcessor definition, Image <TPixel> source, Rectangle sourceRectangle)
     : base(configuration, source, sourceRectangle)
 {
     this.definition = definition;
     this.blender    = PixelOperations <TPixel> .Instance.GetPixelBlender(definition.GraphicsOptions);
 }
 /// <summary>
 /// Initializes a new instance of the <see cref="VignetteProcessor{TPixel}"/> class.
 /// </summary>
 /// <param name="definition">The <see cref="VignetteProcessor"/> defining the processor parameters.</param>
 /// <param name="source">The source <see cref="Image{TPixel}"/> for the current processor instance.</param>
 /// <param name="sourceRectangle">The source area to process for the current processor instance.</param>
 public VignetteProcessor(VignetteProcessor definition, Image <TPixel> source, Rectangle sourceRectangle)
     : base(source, sourceRectangle)
 {
     this.definition = definition;
     this.blender    = PixelOperations <TPixel> .Instance.GetPixelBlender(definition.GraphicsOptions);
 }
 public GlowProcessor(GlowProcessor definition)
 {
     this.definition = definition;
     this.blender    = PixelOperations <TPixel> .Instance.GetPixelBlender(definition.GraphicsOptions);
 }
        /// <inheritdoc/>
        protected override void OnFrameApply(ImageFrame <TPixel> source)
        {
            TPixel          color           = this.definition.Color.ToPixel <TPixel>();
            GraphicsOptions graphicsOptions = this.definition.GraphicsOptions;

            int startY = this.SourceRectangle.Y;
            int endY   = this.SourceRectangle.Bottom;
            int startX = this.SourceRectangle.X;
            int endX   = this.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;

            var workingRect = Rectangle.FromLTRB(minX, minY, maxX, maxY);

            using (IMemoryOwner <TPixel> colors = source.MemoryAllocator.Allocate <TPixel>(width))
                using (IMemoryOwner <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();

                    colorSpan.Fill(color);
                    amountSpan.Fill(graphicsOptions.BlendPercentage);

                    PixelBlender <TPixel> blender = PixelOperations <TPixel> .Instance.GetPixelBlender(graphicsOptions);

                    ParallelHelper.IterateRows(
                        workingRect,
                        this.Configuration,
                        rows =>
                    {
                        for (int y = rows.Min; y < rows.Max; 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.Configuration,
                                destination,
                                colors.GetSpan(),
                                destination,
                                amount.GetSpan());
                        }
                    });
                }
        }