diff --git a/src/ImageSharp/Drawing/Brushes/ImageBrush.cs b/src/ImageSharp/Drawing/Brushes/ImageBrush.cs new file mode 100644 index 0000000000..8ac4f43d29 --- /dev/null +++ b/src/ImageSharp/Drawing/Brushes/ImageBrush.cs @@ -0,0 +1,108 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.Drawing.Brushes +{ + using System; + using System.Collections.Generic; + using System.Numerics; + using System.Threading.Tasks; + using Processors; + + /// + /// Provides an implementaion of a solid brush for painting with repeating images. + /// + public class ImageBrush : ImageBrush + { + /// + /// Initializes a new instance of the class. + /// + /// The color. + public ImageBrush(IImageBase image) + : base(image) + { + } + } + + /// + /// Provides an implementaion of a solid brush for painting solid color areas. + /// + /// The type of the color. + /// The type of the packed. + public class ImageBrush : IBrush + where TColor : struct, IPackedPixel + where TPacked : struct + { + private readonly IImageBase image; + + /// + /// Initializes a new instance of the class. + /// + /// The color. + public ImageBrush(IImageBase image) + { + this.image = image; + } + + /// + /// Creates the applicator for this brush. + /// + /// The region the brush will be applied to. + /// + /// The brush applicator for this brush + /// + /// + /// The when being applied to things like shapes would ussually be the + /// bounding box of the shape not necessarily the bounds of the whole image + /// + public IBrushApplicator CreateApplicator(RectangleF region) + { + return new ImageBrushApplicator(this.image, region); + } + + private class ImageBrushApplicator : IBrushApplicator + { + private readonly PixelAccessor source; + private readonly int yLength; + private readonly int xLength; + private readonly Vector2 offset; + private readonly float YOffset; + + public ImageBrushApplicator(IImageBase image, RectangleF region) + { + this.source = image.Lock(); + this.xLength = image.Width; + this.yLength = image.Height; + this.offset = new Vector2((float)Math.Max(Math.Floor(region.Top), 0), + (float)Math.Max(Math.Floor(region.Left), 0)); + } + + /// + /// Gets the color for a single pixel. + /// + /// The point. + /// + /// The color + /// + public TColor GetColor(Vector2 point) + { + //offset the requested pixel by the value in the rectangle (the shapes position) + point = point - offset; + var x = (int)point.X % this.xLength; + var y = (int)point.Y % this.yLength; + + return source[x, y]; + } + + /// + /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + /// + public void Dispose() + { + source.Dispose(); + } + } + } +} diff --git a/tests/ImageSharp.Tests/Drawing/SolidPolygonTests.cs b/tests/ImageSharp.Tests/Drawing/SolidPolygonTests.cs index 9903e699af..cc2e34accf 100644 --- a/tests/ImageSharp.Tests/Drawing/SolidPolygonTests.cs +++ b/tests/ImageSharp.Tests/Drawing/SolidPolygonTests.cs @@ -12,6 +12,7 @@ namespace ImageSharp.Tests.Drawing using System.IO; using System.Numerics; using Xunit; + using ImageSharp.Drawing.Brushes; public class SolidPolygonTests : FileTestBase { @@ -77,6 +78,28 @@ namespace ImageSharp.Tests.Drawing } } + [Fact] + public void ImageShouldBeOverlayedByFilledPolygon_Image() + { + string path = CreateOutputDirectory("Drawing", "FilledPolygons"); + var simplePath = new[] { + new Vector2(10, 10), + new Vector2(200, 150), + new Vector2(50, 300) + }; + + var brush = new ImageBrush(Files[2].CreateImage()); + var image = new Image(500, 500); + + using (FileStream output = File.OpenWrite($"{path}/Image.png")) + { + image + .BackgroundColor(Color.Blue) + .FillPolygon(brush, simplePath) + .Save(output); + } + } + [Fact] public void ImageShouldBeOverlayedByFilledPolygonOpacity() { @@ -87,7 +110,7 @@ namespace ImageSharp.Tests.Drawing new Vector2(50, 300) }; var color = new Color(Color.HotPink.R, Color.HotPink.G, Color.HotPink.B, 150); - + var image = new Image(500, 500); using (FileStream output = File.OpenWrite($"{path}/Opacity.png"))