Skip to content

Commit 4148163

Browse files
Merge branch 'main' into sw/path-drawer
2 parents 53b7883 + 1a8dc88 commit 4148163

12 files changed

Lines changed: 179 additions & 72 deletions

File tree

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<Project Sdk="Microsoft.NET.Sdk">
3-
43
<PropertyGroup>
54
<AssemblyName>SixLabors.ImageSharp.Drawing</AssemblyName>
65
<AssemblyTitle>SixLabors.ImageSharp.Drawing</AssemblyTitle>
@@ -14,16 +13,12 @@
1413
<Description>An extension to ImageSharp that allows the drawing of images, paths, and text.</Description>
1514
<TargetFrameworks>netcoreapp3.1;netcoreapp2.1;netstandard2.1;netstandard2.0;net472</TargetFrameworks>
1615
</PropertyGroup>
17-
1816
<ItemGroup>
1917
<None Include="..\..\shared-infrastructure\branding\icons\imagesharp.drawing\sixlabors.imagesharp.drawing.128.png" Pack="true" PackagePath="" />
2018
</ItemGroup>
21-
2219
<ItemGroup>
2320
<PackageReference Include="SixLabors.Fonts" Version="1.0.0-beta16" />
24-
<PackageReference Include="SixLabors.ImageSharp" Version="2.0.0" />
21+
<PackageReference Include="SixLabors.ImageSharp" Version="2.1.1-alpha.0.1" />
2522
</ItemGroup>
26-
2723
<Import Project="..\..\shared-infrastructure\src\SharedInfrastructure\SharedInfrastructure.projitems" Label="Shared" />
28-
29-
</Project>
24+
</Project>

src/ImageSharp.Drawing/Shapes/Rasterization/PolygonScanner.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ public static PolygonScanner Create(
9898
IntersectionRule intersectionRule,
9999
MemoryAllocator allocator)
100100
{
101-
var multipolygon = TessellatedMultipolygon.Create(polygon, allocator);
101+
using var multipolygon = TessellatedMultipolygon.Create(polygon, allocator);
102102
var edges = ScanEdgeCollection.Create(multipolygon, allocator, subsampling);
103103
var scanner = new PolygonScanner(edges, multipolygon.TotalVertexCount * 2, minY, maxY, subsampling, intersectionRule, allocator);
104104
scanner.Init();

src/ImageSharp.Drawing/Shapes/Rasterization/ScanEdgeCollection.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ public static ScanEdgeCollection Create(
4040
MemoryAllocator allocator,
4141
int subsampling)
4242
{
43-
TessellatedMultipolygon multipolygon = TessellatedMultipolygon.Create(polygon, allocator);
43+
using TessellatedMultipolygon multipolygon = TessellatedMultipolygon.Create(polygon, allocator);
4444
return Create(multipolygon, allocator, subsampling);
4545
}
4646
}

tests/ImageSharp.Drawing.Tests/Drawing/Text/DrawTextOnImageTests.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
namespace SixLabors.ImageSharp.Drawing.Tests.Drawing.Text
1717
{
1818
[GroupOutput("Drawing/Text")]
19+
[ValidateDisposedMemoryAllocations]
1920
public class DrawTextOnImageTests
2021
{
2122
private const string AB = "AB\nAB";
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
// Copyright (c) Six Labors.
2+
// Licensed under the Apache License, Version 2.0.
3+
4+
using System;
5+
using System.Threading;
6+
using SixLabors.ImageSharp.Diagnostics;
7+
using Xunit;
8+
9+
namespace SixLabors.ImageSharp.Drawing.Tests
10+
{
11+
public static class MemoryAllocatorValidator
12+
{
13+
private static readonly AsyncLocal<TestMemoryDiagnostics> LocalInstance = new();
14+
15+
public static bool MonitoringAllocations => LocalInstance.Value != null;
16+
17+
static MemoryAllocatorValidator()
18+
{
19+
MemoryDiagnostics.MemoryAllocated += MemoryDiagnostics_MemoryAllocated;
20+
MemoryDiagnostics.MemoryReleased += MemoryDiagnostics_MemoryReleased;
21+
}
22+
23+
private static void MemoryDiagnostics_MemoryReleased()
24+
{
25+
TestMemoryDiagnostics backing = LocalInstance.Value;
26+
if (backing != null)
27+
{
28+
backing.TotalRemainingAllocated--;
29+
}
30+
}
31+
32+
private static void MemoryDiagnostics_MemoryAllocated()
33+
{
34+
TestMemoryDiagnostics backing = LocalInstance.Value;
35+
if (backing != null)
36+
{
37+
backing.TotalAllocated++;
38+
backing.TotalRemainingAllocated++;
39+
}
40+
}
41+
42+
public static TestMemoryDiagnostics MonitorAllocations()
43+
{
44+
var diag = new TestMemoryDiagnostics();
45+
LocalInstance.Value = diag;
46+
return diag;
47+
}
48+
49+
public static void StopMonitoringAllocations() => LocalInstance.Value = null;
50+
51+
public static void ValidateAllocations(int expectedAllocationCount = 0)
52+
=> LocalInstance.Value?.Validate(expectedAllocationCount);
53+
54+
public class TestMemoryDiagnostics : IDisposable
55+
{
56+
public int TotalAllocated { get; set; }
57+
58+
public int TotalRemainingAllocated { get; set; }
59+
60+
public void Validate(int expectedAllocationCount)
61+
{
62+
var count = this.TotalRemainingAllocated;
63+
var pass = expectedAllocationCount == count;
64+
Assert.True(pass, $"Expected a {expectedAllocationCount} undisposed buffers but found {count}");
65+
}
66+
67+
public void Dispose()
68+
{
69+
this.Validate(0);
70+
if (LocalInstance.Value == this)
71+
{
72+
StopMonitoringAllocations();
73+
}
74+
}
75+
}
76+
}
77+
}

tests/ImageSharp.Drawing.Tests/Shapes/Scan/ScanEdgeCollectionTests.cs

Lines changed: 50 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -10,21 +10,20 @@ namespace SixLabors.ImageSharp.Drawing.Tests.Shapes.Scan
1010
{
1111
public class ScanEdgeCollectionTests
1212
{
13-
private ScanEdgeCollection edges;
14-
1513
private static MemoryAllocator MemoryAllocator => Configuration.Default.MemoryAllocator;
1614

1715
private static readonly DebugDraw DebugDraw = new DebugDraw(nameof(ScanEdgeCollectionTests));
1816

1917
private void VerifyEdge(
18+
ScanEdgeCollection edges,
2019
float y0,
2120
float y1,
2221
(FuzzyFloat X, FuzzyFloat Y) arbitraryPoint,
2322
int emit0,
2423
int emit1,
2524
bool edgeUp)
2625
{
27-
foreach (ScanEdge e in this.edges.Edges)
26+
foreach (ScanEdge e in edges.Edges)
2827
{
2928
if (y0 == e.Y0 && y1 == e.Y1)
3029
{
@@ -45,6 +44,7 @@ private void VerifyEdge(
4544
}
4645

4746
[Fact]
47+
[ValidateDisposedMemoryAllocations]
4848
public void SimplePolygon_AllEmitCases()
4949
{
5050
// see: SimplePolygon_AllEmitCases.png
@@ -78,29 +78,29 @@ public void SimplePolygon_AllEmitCases()
7878

7979
DebugDraw.Polygon(polygon, 1, 100);
8080

81-
this.edges = ScanEdgeCollection.Create(polygon, MemoryAllocator, 16);
82-
83-
Assert.Equal(19, this.edges.Edges.Length);
84-
85-
this.VerifyEdge(1f, 2f, (2.5f, 1.5f), 1, 2, true);
86-
this.VerifyEdge(1f, 3f, (3.5f, 2f), 1, 1, false);
87-
this.VerifyEdge(1f, 3f, (5f, 2f), 1, 1, true);
88-
this.VerifyEdge(1f, 2f, (6.5f, 1.5f), 1, 2, false);
89-
this.VerifyEdge(2f, 3f, (8.5f, 2.5f), 1, 0, false);
90-
this.VerifyEdge(3f, 4f, (9f, 3.5f), 1, 0, false);
91-
this.VerifyEdge(4f, 5f, (9.5f, 4.5f), 1, 0, false);
92-
this.VerifyEdge(5f, 6f, (9.5f, 5.5f), 1, 1, false);
93-
this.VerifyEdge(6f, 7f, (8f, 6.5f), 2, 2, false);
94-
this.VerifyEdge(7f, 8f, (9f, 7.5f), 1, 1, false);
95-
this.VerifyEdge(7f, 8f, (6.5f, 7.5f), 1, 1, true);
96-
this.VerifyEdge(7f, 8f, (5.5f, 7.5f), 1, 1, false);
97-
this.VerifyEdge(7f, 8f, (4.5f, 7.5f), 1, 1, true);
98-
this.VerifyEdge(7f, 8f, (3.5f, 7.5f), 1, 1, false);
99-
this.VerifyEdge(6f, 8f, (2f, 7f), 0, 1, true);
100-
this.VerifyEdge(5f, 6f, (2.5f, 5.5f), 2, 1, true);
101-
this.VerifyEdge(4f, 5f, (2f, 4.5f), 0, 1, true);
102-
this.VerifyEdge(3f, 4f, (1.5f, 3.5f), 0, 1, true);
103-
this.VerifyEdge(2f, 3f, (1f, 1.5f), 1, 1, true);
81+
using var edges = ScanEdgeCollection.Create(polygon, MemoryAllocator, 16);
82+
83+
Assert.Equal(19, edges.Edges.Length);
84+
85+
this.VerifyEdge(edges, 1f, 2f, (2.5f, 1.5f), 1, 2, true);
86+
this.VerifyEdge(edges, 1f, 3f, (3.5f, 2f), 1, 1, false);
87+
this.VerifyEdge(edges, 1f, 3f, (5f, 2f), 1, 1, true);
88+
this.VerifyEdge(edges, 1f, 2f, (6.5f, 1.5f), 1, 2, false);
89+
this.VerifyEdge(edges, 2f, 3f, (8.5f, 2.5f), 1, 0, false);
90+
this.VerifyEdge(edges, 3f, 4f, (9f, 3.5f), 1, 0, false);
91+
this.VerifyEdge(edges, 4f, 5f, (9.5f, 4.5f), 1, 0, false);
92+
this.VerifyEdge(edges, 5f, 6f, (9.5f, 5.5f), 1, 1, false);
93+
this.VerifyEdge(edges, 6f, 7f, (8f, 6.5f), 2, 2, false);
94+
this.VerifyEdge(edges, 7f, 8f, (9f, 7.5f), 1, 1, false);
95+
this.VerifyEdge(edges, 7f, 8f, (6.5f, 7.5f), 1, 1, true);
96+
this.VerifyEdge(edges, 7f, 8f, (5.5f, 7.5f), 1, 1, false);
97+
this.VerifyEdge(edges, 7f, 8f, (4.5f, 7.5f), 1, 1, true);
98+
this.VerifyEdge(edges, 7f, 8f, (3.5f, 7.5f), 1, 1, false);
99+
this.VerifyEdge(edges, 6f, 8f, (2f, 7f), 0, 1, true);
100+
this.VerifyEdge(edges, 5f, 6f, (2.5f, 5.5f), 2, 1, true);
101+
this.VerifyEdge(edges, 4f, 5f, (2f, 4.5f), 0, 1, true);
102+
this.VerifyEdge(edges, 3f, 4f, (1.5f, 3.5f), 0, 1, true);
103+
this.VerifyEdge(edges, 2f, 3f, (1f, 1.5f), 1, 1, true);
104104
}
105105

106106
[Fact]
@@ -114,54 +114,54 @@ public void ComplexPolygon()
114114
IPath polygon = contour.Clip(hole);
115115
DebugDraw.Polygon(polygon, 1, 100);
116116

117-
this.edges = ScanEdgeCollection.Create(polygon, MemoryAllocator, 16);
117+
using var edges = ScanEdgeCollection.Create(polygon, MemoryAllocator, 16);
118118

119-
Assert.Equal(8, this.edges.Count);
119+
Assert.Equal(8, edges.Count);
120120

121-
this.VerifyEdge(1, 4, (1, 2), 1, 1, true);
122-
this.VerifyEdge(1, 2, (4, 1.5f), 1, 2, false);
123-
this.VerifyEdge(4, 5, (2, 4.5f), 2, 1, true);
124-
this.VerifyEdge(2, 5, (5, 3f), 1, 1, false);
121+
this.VerifyEdge(edges, 1, 4, (1, 2), 1, 1, true);
122+
this.VerifyEdge(edges, 1, 2, (4, 1.5f), 1, 2, false);
123+
this.VerifyEdge(edges, 4, 5, (2, 4.5f), 2, 1, true);
124+
this.VerifyEdge(edges, 2, 5, (5, 3f), 1, 1, false);
125125

126-
this.VerifyEdge(2, 3, (2, 2.5f), 2, 2, false);
127-
this.VerifyEdge(2, 3, (3.5f, 2.5f), 2, 1, true);
128-
this.VerifyEdge(3, 4, (3, 3.5f), 1, 2, false);
129-
this.VerifyEdge(3, 4, (4, 3.5f), 0, 2, true);
126+
this.VerifyEdge(edges, 2, 3, (2, 2.5f), 2, 2, false);
127+
this.VerifyEdge(edges, 2, 3, (3.5f, 2.5f), 2, 1, true);
128+
this.VerifyEdge(edges, 3, 4, (3, 3.5f), 1, 2, false);
129+
this.VerifyEdge(edges, 3, 4, (4, 3.5f), 0, 2, true);
130130
}
131131

132132
[Fact]
133133
public void NumericCornerCase_C()
134134
{
135-
this.edges = ScanEdgeCollection.Create(NumericCornerCasePolygons.C, MemoryAllocator, 4);
136-
Assert.Equal(2, this.edges.Count);
137-
this.VerifyEdge(3.5f, 4f, (2f, 3.75f), 1, 1, true);
138-
this.VerifyEdge(3.5f, 4f, (8f, 3.75f), 1, 1, false);
135+
using var edges = ScanEdgeCollection.Create(NumericCornerCasePolygons.C, MemoryAllocator, 4);
136+
Assert.Equal(2, edges.Count);
137+
this.VerifyEdge(edges, 3.5f, 4f, (2f, 3.75f), 1, 1, true);
138+
this.VerifyEdge(edges, 3.5f, 4f, (8f, 3.75f), 1, 1, false);
139139
}
140140

141141
[Fact]
142142
public void NumericCornerCase_D()
143143
{
144-
this.edges = ScanEdgeCollection.Create(NumericCornerCasePolygons.D, MemoryAllocator, 4);
145-
Assert.Equal(5, this.edges.Count);
144+
using var edges = ScanEdgeCollection.Create(NumericCornerCasePolygons.D, MemoryAllocator, 4);
145+
Assert.Equal(5, edges.Count);
146146

147-
this.VerifyEdge(3.25f, 4f, (12f, 3.75f), 1, 1, true);
148-
this.VerifyEdge(3.25f, 3.5f, (15f, 3.375f), 1, 0, false);
149-
this.VerifyEdge(3.5f, 4f, (18f, 3.75f), 1, 1, false);
147+
this.VerifyEdge(edges, 3.25f, 4f, (12f, 3.75f), 1, 1, true);
148+
this.VerifyEdge(edges, 3.25f, 3.5f, (15f, 3.375f), 1, 0, false);
149+
this.VerifyEdge(edges, 3.5f, 4f, (18f, 3.75f), 1, 1, false);
150150

151151
// TODO: verify 2 more edges
152152
}
153153

154154
[Fact]
155155
public void NumericCornerCase_H_ShouldCollapseNearZeroEdge()
156156
{
157-
this.edges = ScanEdgeCollection.Create(NumericCornerCasePolygons.H, MemoryAllocator, 4);
157+
using var edges = ScanEdgeCollection.Create(NumericCornerCasePolygons.H, MemoryAllocator, 4);
158158

159-
Assert.Equal(3, this.edges.Count);
160-
this.VerifyEdge(1.75f, 2f, (15f, 1.875f), 1, 1, true);
161-
this.VerifyEdge(1.75f, 2.25f, (16f, 2f), 1, 1, false);
159+
Assert.Equal(3, edges.Count);
160+
this.VerifyEdge(edges, 1.75f, 2f, (15f, 1.875f), 1, 1, true);
161+
this.VerifyEdge(edges, 1.75f, 2.25f, (16f, 2f), 1, 1, false);
162162

163163
// this places two dummy points:
164-
this.VerifyEdge(2f, 2.25f, (15f, 2.125f), 2, 1, true);
164+
this.VerifyEdge(edges, 2f, 2.25f, (15f, 2.125f), 2, 1, true);
165165
}
166166

167167
private static FuzzyFloat F(float value, float eps) => new FuzzyFloat(value, eps);

tests/ImageSharp.Drawing.Tests/TestFormat.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@ public class TestDecoder : IImageDecoder
199199

200200
public int HeaderSize => this.testFormat.HeaderSize;
201201

202-
public Image<TPixel> Decode<TPixel>(Configuration config, Stream stream)
202+
public Image<TPixel> Decode<TPixel>(Configuration config, Stream stream, CancellationToken cancellationToken)
203203
where TPixel : unmanaged, IPixel<TPixel>
204204
{
205205
var ms = new MemoryStream();
@@ -218,7 +218,7 @@ public Image<TPixel> Decode<TPixel>(Configuration config, Stream stream)
218218

219219
public bool IsSupportedFileFormat(Span<byte> header) => this.testFormat.IsSupportedFileFormat(header);
220220

221-
public Image Decode(Configuration configuration, Stream stream) => this.Decode<TestPixelForAgnosticDecode>(configuration, stream);
221+
public Image Decode(Configuration configuration, Stream stream, CancellationToken cancellationToken) => this.Decode<TestPixelForAgnosticDecode>(configuration, stream, cancellationToken);
222222

223223
public Task<Image<TPixel>> DecodeAsync<TPixel>(Configuration configuration, Stream stream, CancellationToken cancellationToken)
224224
where TPixel : unmanaged, IPixel<TPixel>

tests/ImageSharp.Drawing.Tests/TestUtilities/ImageProviders/FileProvider.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using System.Collections.Concurrent;
66
using System.Collections.Generic;
77
using System.Reflection;
8+
using SixLabors.ImageSharp.Diagnostics;
89
using SixLabors.ImageSharp.Formats;
910
using SixLabors.ImageSharp.PixelFormats;
1011

tests/ImageSharp.Drawing.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,9 @@ private static void FromRgba64Bytes<TPixel>(Configuration configuration, Span<by
6161

6262
public Task<Image<TPixel>> DecodeAsync<TPixel>(Configuration configuration, Stream stream, CancellationToken cancellationToken)
6363
where TPixel : unmanaged, PixelFormats.IPixel<TPixel>
64-
=> Task.FromResult(this.Decode<TPixel>(configuration, stream));
64+
=> Task.FromResult(this.Decode<TPixel>(configuration, stream, cancellationToken));
6565

66-
public Image<TPixel> Decode<TPixel>(Configuration configuration, Stream stream)
66+
public Image<TPixel> Decode<TPixel>(Configuration configuration, Stream stream, CancellationToken cancellationToken)
6767
where TPixel : unmanaged, PixelFormats.IPixel<TPixel>
6868
{
6969
var bmpReadDefines = new BmpReadDefines
@@ -105,7 +105,7 @@ public Image<TPixel> Decode<TPixel>(Configuration configuration, Stream stream)
105105
return new Image<TPixel>(configuration, new ImageMetadata(), framesList);
106106
}
107107

108-
public Image Decode(Configuration configuration, Stream stream) => this.Decode<Rgba32>(configuration, stream);
108+
public Image Decode(Configuration configuration, Stream stream, CancellationToken cancellationToken) => this.Decode<Rgba32>(configuration, stream, cancellationToken);
109109

110110
public async Task<Image> DecodeAsync(Configuration configuration, Stream stream, CancellationToken cancellationToken)
111111
=> await this.DecodeAsync<Rgba32>(configuration, stream, cancellationToken);

tests/ImageSharp.Drawing.Tests/TestUtilities/ReferenceCodecs/SystemDrawingReferenceDecoder.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ public class SystemDrawingReferenceDecoder : IImageDecoder, IImageInfoDetector
1414
{
1515
public static SystemDrawingReferenceDecoder Instance { get; } = new SystemDrawingReferenceDecoder();
1616

17-
public Image<TPixel> Decode<TPixel>(Configuration configuration, Stream stream)
17+
public Image<TPixel> Decode<TPixel>(Configuration configuration, Stream stream, CancellationToken cancellationToken)
1818
where TPixel : unmanaged, IPixel<TPixel>
1919
{
2020
using (var sourceBitmap = new System.Drawing.Bitmap(stream))
@@ -44,7 +44,7 @@ public Image<TPixel> Decode<TPixel>(Configuration configuration, Stream stream)
4444
}
4545
}
4646

47-
public IImageInfo Identify(Configuration configuration, Stream stream)
47+
public IImageInfo Identify(Configuration configuration, Stream stream, CancellationToken cancellationToken)
4848
{
4949
using (var sourceBitmap = new System.Drawing.Bitmap(stream))
5050
{
@@ -56,8 +56,8 @@ public IImageInfo Identify(Configuration configuration, Stream stream)
5656
public Task<IImageInfo> IdentifyAsync(Configuration configuration, Stream stream, CancellationToken cancellationToken)
5757
=> throw new System.NotImplementedException();
5858

59-
public Image Decode(Configuration configuration, Stream stream)
60-
=> this.Decode<Rgba32>(configuration, stream);
59+
public Image Decode(Configuration configuration, Stream stream, CancellationToken cancellationToken)
60+
=> this.Decode<Rgba32>(configuration, stream, cancellationToken);
6161

6262
public Task<Image<TPixel>> DecodeAsync<TPixel>(Configuration configuration, Stream stream, CancellationToken cancellationToken)
6363
where TPixel : unmanaged, IPixel<TPixel>

0 commit comments

Comments
 (0)