Skip to content

Commit ec146c9

Browse files
Merge pull request #306 from SixLabors/js/fix-305
Expose ImageBrush source region constructor.
2 parents 2316146 + 3ee51ef commit ec146c9

File tree

3 files changed

+65
-14
lines changed

3 files changed

+65
-14
lines changed

src/ImageSharp.Drawing/Processing/ImageBrush.cs

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public class ImageBrush : Brush
2424
/// <summary>
2525
/// Initializes a new instance of the <see cref="ImageBrush"/> class.
2626
/// </summary>
27-
/// <param name="image">The image.</param>
27+
/// <param name="image">The source image to draw.</param>
2828
public ImageBrush(Image image)
2929
: this(image, image.Bounds)
3030
{
@@ -33,15 +33,12 @@ public ImageBrush(Image image)
3333
/// <summary>
3434
/// Initializes a new instance of the <see cref="ImageBrush"/> class.
3535
/// </summary>
36-
/// <param name="image">The image.</param>
37-
/// <param name="region">
38-
/// The region of interest.
39-
/// This overrides any region used to initialize the brush applicator.
40-
/// </param>
41-
internal ImageBrush(Image image, RectangleF region)
36+
/// <param name="image">The source image.</param>
37+
/// <param name="region">The region of interest within the source image to draw.</param>
38+
public ImageBrush(Image image, RectangleF region)
4239
{
4340
this.image = image;
44-
this.region = region;
41+
this.region = RectangleF.Intersect(image.Bounds, region);
4542
}
4643

4744
/// <inheritdoc />

tests/ImageSharp.Drawing.Tests/Drawing/FillImageBrushTests.cs

Lines changed: 57 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,10 @@ public class FillImageBrushTests
1414
[Fact]
1515
public void DoesNotDisposeImage()
1616
{
17-
using (var src = new Image<Rgba32>(5, 5))
17+
using (Image<Rgba32> src = new(5, 5))
1818
{
19-
var brush = new ImageBrush(src);
20-
using (var dest = new Image<Rgba32>(10, 10))
19+
ImageBrush brush = new(src);
20+
using (Image<Rgba32> dest = new(10, 10))
2121
{
2222
dest.Mutate(c => c.Fill(brush, new Rectangle(0, 0, 10, 10)));
2323
dest.Mutate(c => c.Fill(brush, new Rectangle(0, 0, 10, 10)));
@@ -36,7 +36,7 @@ public void UseBrushOfDifferentPixelType<TPixel>(TestImageProvider<TPixel> provi
3636
? Image.Load<Bgra32>(data)
3737
: Image.Load<Rgba32>(data);
3838

39-
var brush = new ImageBrush(overlay);
39+
ImageBrush brush = new(overlay);
4040
background.Mutate(c => c.Fill(brush));
4141

4242
background.DebugSave(provider, appendSourceFileOrDescription: false);
@@ -54,7 +54,7 @@ public void CanDrawLandscapeImage<TPixel>(TestImageProvider<TPixel> provider)
5454

5555
overlay.Mutate(c => c.Crop(new Rectangle(0, 0, 125, 90)));
5656

57-
var brush = new ImageBrush(overlay);
57+
ImageBrush brush = new(overlay);
5858
background.Mutate(c => c.Fill(brush));
5959

6060
background.DebugSave(provider, appendSourceFileOrDescription: false);
@@ -72,10 +72,61 @@ public void CanDrawPortraitImage<TPixel>(TestImageProvider<TPixel> provider)
7272

7373
overlay.Mutate(c => c.Crop(new Rectangle(0, 0, 90, 125)));
7474

75-
var brush = new ImageBrush(overlay);
75+
ImageBrush brush = new(overlay);
7676
background.Mutate(c => c.Fill(brush));
7777

7878
background.DebugSave(provider, appendSourceFileOrDescription: false);
7979
background.CompareToReferenceOutput(provider, appendSourceFileOrDescription: false);
8080
}
81+
82+
[Theory]
83+
[WithSolidFilledImages(1000, 1000, "White", PixelTypes.Rgba32)]
84+
public void CanDrawNegativeOffsetImage<TPixel>(TestImageProvider<TPixel> provider)
85+
where TPixel : unmanaged, IPixel<TPixel>
86+
{
87+
byte[] data = TestFile.Create(TestImages.Png.Ducky).Bytes;
88+
using Image<TPixel> background = provider.GetImage();
89+
using Image overlay = Image.Load<Rgba32>(data);
90+
91+
overlay.Mutate(c => c.Resize(100, 100));
92+
93+
ImageBrush halfBrush = new(overlay, new RectangleF(50, 0, 50, 100));
94+
ImageBrush fullBrush = new(overlay);
95+
background.Mutate(c => DrawFull(c, new Size(100, 100), fullBrush, halfBrush, background.Width, background.Height));
96+
97+
background.DebugSave(provider, appendSourceFileOrDescription: false);
98+
background.CompareToReferenceOutput(provider, appendSourceFileOrDescription: false);
99+
}
100+
101+
private static void DrawFull(IImageProcessingContext ctx, Size size, ImageBrush brush, ImageBrush halfBrush, int width, int height)
102+
{
103+
int j = 0;
104+
while (j < height)
105+
{
106+
bool half = false;
107+
int limitWidth = width;
108+
int i = 0;
109+
if ((j / size.Height) % 2 != 0)
110+
{
111+
half = true;
112+
}
113+
114+
while (i < limitWidth)
115+
{
116+
if (half)
117+
{
118+
ctx.Fill(halfBrush, new RectangleF(i, j, size.Width / 2f, size.Height));
119+
i += (int)(size.Width / 2f);
120+
half = false;
121+
}
122+
else
123+
{
124+
ctx.Fill(brush, new RectangleF(new PointF(i, j), size));
125+
i += size.Width;
126+
}
127+
}
128+
129+
j += size.Height;
130+
}
131+
}
81132
}
Lines changed: 3 additions & 0 deletions
Loading

0 commit comments

Comments
 (0)