Skip to content
This repository was archived by the owner on Jan 18, 2020. It is now read-only.

Commit 4f12a19

Browse files
authored
Merge pull request #62 from SixLabors/outliner-styles
Add joint and cap styles to outliner
2 parents bca6cb1 + bb093a1 commit 4f12a19

File tree

7 files changed

+155
-13
lines changed

7 files changed

+155
-13
lines changed

samples/DrawShapesWithImageSharp/DrawShapesWithImageSharp.csproj

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
</ItemGroup>
1313

1414
<ItemGroup>
15-
<PackageReference Include="SixLabors.ImageSharp.Drawing" Version="1.0.0-dev001425" />
15+
<PackageReference Include="SixLabors.ImageSharp.Drawing" Version="1.0.0-dev002362" />
1616
<PackageReference Include="System.Numerics.Vectors" Version="4.5.0" />
1717
<PackageReference Include="System.Runtime.Numerics" Version="4.3.0" />
1818
</ItemGroup>

samples/DrawShapesWithImageSharp/ImageSharpLogo.cs

-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
using SixLabors.ImageSharp;
55
using SixLabors.ImageSharp.PixelFormats;
66
using SixLabors.ImageSharp.Processing;
7-
using SixLabors.ImageSharp.Processing.Drawing;
87

98
namespace SixLabors.Shapes.DrawShapesWithImageSharp
109
{

samples/DrawShapesWithImageSharp/Program.cs

+29-3
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
using System.Numerics;
77
using SixLabors.ImageSharp.PixelFormats;
88
using SixLabors.ImageSharp.Processing;
9-
using SixLabors.ImageSharp.Processing.Drawing;
109

1110
namespace SixLabors.Shapes.DrawShapesWithImageSharp
1211
{
@@ -22,6 +21,14 @@ public static void Main(string[] args)
2221

2322
private static void OutputStars()
2423
{
24+
OutputStarOutline(5, 150, 250, width: 20, jointStyle: JointStyle.Miter);
25+
OutputStarOutline(5, 150, 250, width: 20, jointStyle: JointStyle.Round);
26+
OutputStarOutline(5, 150, 250, width: 20, jointStyle: JointStyle.Square);
27+
28+
OutputStarOutlineDashed(5, 150, 250, width: 20, jointStyle: JointStyle.Square, cap: EndCapStyle.Butt);
29+
OutputStarOutlineDashed(5, 150, 250, width: 20, jointStyle: JointStyle.Round, cap: EndCapStyle.Round);
30+
OutputStarOutlineDashed(5, 150, 250, width: 20, jointStyle: JointStyle.Square, cap: EndCapStyle.Square);
31+
2532
OutputStar(3, 5);
2633
OutputStar(4);
2734
OutputStar(5);
@@ -39,7 +46,7 @@ private static void OutputStars()
3946
DrawFatL();
4047

4148
DrawText("Hello World");
42-
DrawText("Hello World Hello World Hello World Hello World Hello World Hello World Hello World", new Path(new CubicBezierLineSegment(
49+
DrawText("Hello World Hello World Hello World Hello World Hello World Hello World Hello World", new Path(new CubicBezierLineSegment(
4350
new Vector2(0, 0),
4451
new Vector2(150, -150),
4552
new Vector2(250, -150),
@@ -174,6 +181,25 @@ private static void OutputDrawnShapeHourGlass()
174181
sb.Build().Translate(0, 10).Scale(10).SaveImage("drawing", $"HourGlass.png");
175182
}
176183

184+
private static void OutputStarOutline(int points, float inner = 10, float outer = 20, float width = 5, JointStyle jointStyle = JointStyle.Miter)
185+
{
186+
// center the shape outerRadii + 10 px away from edges
187+
float offset = outer + 10;
188+
189+
Star star = new Star(offset, offset, points, inner, outer);
190+
var outline = Outliner.GenerateOutline(star, width, jointStyle);
191+
outline.SaveImage("Stars", $"StarOutline_{points}_{jointStyle}.png");
192+
}
193+
private static void OutputStarOutlineDashed(int points, float inner = 10, float outer = 20, float width = 5, JointStyle jointStyle = JointStyle.Miter, EndCapStyle cap = EndCapStyle.Butt)
194+
{
195+
// center the shape outerRadii + 10 px away from edges
196+
float offset = outer + 10;
197+
198+
Star star = new Star(offset, offset, points, inner, outer);
199+
var outline = Outliner.GenerateOutline(star, width, new float[] { 3, 3 }, false, jointStyle, cap);
200+
outline.SaveImage("Stars", $"StarOutlineDashed_{points}_{jointStyle}_{cap}.png");
201+
}
202+
177203
private static void OutputStar(int points, float inner = 10, float outer = 20)
178204
{
179205
// center the shape outerRadii + 10 px away from edges
@@ -228,7 +254,7 @@ public static void SaveImage(this IPath shape, int width, int height, params str
228254
{
229255
new PathCollection(shape).SaveImage(width, height, path);
230256
}
231-
public static void SaveImage(this IPathCollection shape, int width, int height, params string[] path)
257+
public static void SaveImage(this IPathCollection shape, int width, int height, params string[] path)
232258
{
233259
string fullPath = System.IO.Path.GetFullPath(System.IO.Path.Combine("Output", System.IO.Path.Combine(path)));
234260

src/SixLabors.Shapes/EndCapStyle.cs

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Copyright (c) Six Labors and contributors.
2+
// Licensed under the Apache License, Version 2.0.
3+
4+
namespace SixLabors.Shapes
5+
{
6+
/// <summary>
7+
/// The style to apply to the end cap when generating an outline.
8+
/// </summary>
9+
public enum EndCapStyle
10+
{
11+
/// <summary>
12+
/// The outline stops exactly at the end of the path.
13+
/// </summary>
14+
Butt = 0,
15+
16+
/// <summary>
17+
/// The outline extends with a rounded style passed the end of the path.
18+
/// </summary>
19+
Round = 1,
20+
21+
/// <summary>
22+
/// The outlines ends squared off passed the end of the path.
23+
/// </summary>
24+
Square = 2,
25+
}
26+
}

src/SixLabors.Shapes/JointStyle.cs

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Copyright (c) Six Labors and contributors.
2+
// Licensed under the Apache License, Version 2.0.
3+
4+
namespace SixLabors.Shapes
5+
{
6+
/// <summary>
7+
/// The style we use to generate the joints when outlining.
8+
/// </summary>
9+
public enum JointStyle
10+
{
11+
/// <summary>
12+
/// Joints will generate to a long point unless the end of the point will exceed 20 times the width then we generate the joint using <see cref="JointStyle.Square"/>.
13+
/// </summary>
14+
Miter = 2,
15+
16+
/// <summary>
17+
/// Rounded joints. Joints generate with a rounded profile.
18+
/// </summary>
19+
Round = 1,
20+
21+
/// <summary>
22+
/// Joints are squared off 1 width distance from the corner.
23+
/// </summary>
24+
Square = 0
25+
}
26+
}

src/SixLabors.Shapes/Outliner.cs

+71-7
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ namespace SixLabors.Shapes
1515
/// </summary>
1616
public static class Outliner
1717
{
18+
private const double MiterOffsetDelta = 20;
1819
private const float ScalingFactor = 1000.0f;
1920

2021
/// <summary>
@@ -59,15 +60,34 @@ public static IPath GenerateOutline(this IPath path, float width, float[] patter
5960
/// <param name="startOff">Weather the first item in the pattern is on or off.</param>
6061
/// <returns>A new path representing the outline.</returns>
6162
public static IPath GenerateOutline(this IPath path, float width, ReadOnlySpan<float> pattern, bool startOff)
63+
=> GenerateOutline(path, width, pattern, startOff, JointStyle.Square, EndCapStyle.Butt);
64+
65+
/// <summary>
66+
/// Generates a outline of the path with alternating on and off segments based on the pattern.
67+
/// </summary>
68+
/// <param name="path">the path to outline</param>
69+
/// <param name="width">The final width outline</param>
70+
/// <param name="pattern">The pattern made of multiples of the width.</param>
71+
/// <param name="startOff">Weather the first item in the pattern is on or off.</param>
72+
/// <param name="jointStyle">The style to render the joints.</param>
73+
/// <param name="patternSectionCapStyle">The style to render between sections of the specified pattern.</param>
74+
/// <returns>A new path representing the outline.</returns>
75+
public static IPath GenerateOutline(this IPath path, float width, ReadOnlySpan<float> pattern, bool startOff, JointStyle jointStyle = JointStyle.Square, EndCapStyle patternSectionCapStyle = EndCapStyle.Butt)
6276
{
6377
if (pattern.Length < 2)
6478
{
6579
return path.GenerateOutline(width);
6680
}
6781

82+
var style = Convert(jointStyle);
83+
var patternSectionCap = Convert(patternSectionCapStyle);
84+
6885
IEnumerable<ISimplePath> paths = path.Flatten();
6986

70-
var offset = new ClipperOffset();
87+
var offset = new ClipperOffset()
88+
{
89+
MiterLimit = MiterOffsetDelta
90+
};
7191

7292
var buffer = new List<IntPoint>(3);
7393
foreach (ISimplePath p in paths)
@@ -103,7 +123,7 @@ public static IPath GenerateOutline(this IPath path, float width, ReadOnlySpan<f
103123
// we now inset a line joining
104124
if (online)
105125
{
106-
offset.AddPath(buffer, JoinType.jtSquare, EndType.etOpenButt);
126+
offset.AddPath(buffer, style, patternSectionCap);
107127
}
108128

109129
online = !online;
@@ -138,7 +158,7 @@ public static IPath GenerateOutline(this IPath path, float width, ReadOnlySpan<f
138158

139159
if (online)
140160
{
141-
offset.AddPath(buffer, JoinType.jtSquare, EndType.etOpenButt);
161+
offset.AddPath(buffer, style, patternSectionCap);
142162
}
143163

144164
online = !online;
@@ -158,9 +178,25 @@ public static IPath GenerateOutline(this IPath path, float width, ReadOnlySpan<f
158178
/// <param name="path">the path to outline</param>
159179
/// <param name="width">The final width outline</param>
160180
/// <returns>A new path representing the outline.</returns>
161-
public static IPath GenerateOutline(this IPath path, float width)
181+
public static IPath GenerateOutline(this IPath path, float width) => GenerateOutline(path, width, JointStyle.Square, EndCapStyle.Butt);
182+
183+
/// <summary>
184+
/// Generates a solid outline of the path.
185+
/// </summary>
186+
/// <param name="path">the path to outline</param>
187+
/// <param name="width">The final width outline</param>
188+
/// <param name="jointStyle">The style to render the joints.</param>
189+
/// <param name="endCapStyle">The style to render the end caps of open paths (ignored on closed paths).</param>
190+
/// <returns>A new path representing the outline.</returns>
191+
public static IPath GenerateOutline(this IPath path, float width, JointStyle jointStyle = JointStyle.Square, EndCapStyle endCapStyle = EndCapStyle.Butt)
162192
{
163-
var offset = new ClipperOffset();
193+
var offset = new ClipperOffset()
194+
{
195+
MiterLimit = MiterOffsetDelta
196+
};
197+
198+
var style = Convert(jointStyle);
199+
var openEndCapStyle = Convert(endCapStyle);
164200

165201
// Pattern can be applied to the path by cutting it into segments
166202
IEnumerable<ISimplePath> paths = path.Flatten();
@@ -173,9 +209,9 @@ public static IPath GenerateOutline(this IPath path, float width)
173209
points.Add(new IntPoint(v.X * ScalingFactor, v.Y * ScalingFactor));
174210
}
175211

176-
EndType type = p.IsClosed ? EndType.etClosedLine : EndType.etOpenButt;
212+
EndType type = p.IsClosed ? EndType.etClosedLine : openEndCapStyle;
177213

178-
offset.AddPath(points, JoinType.jtSquare, type);
214+
offset.AddPath(points, style, type);
179215
}
180216

181217
return ExecuteOutliner(width, offset);
@@ -204,5 +240,33 @@ private static IntPoint ToPoint(this Vector2 vector)
204240
{
205241
return new IntPoint(vector.X * ScalingFactor, vector.Y * ScalingFactor);
206242
}
243+
244+
private static JoinType Convert(JointStyle style)
245+
{
246+
switch (style)
247+
{
248+
case JointStyle.Round:
249+
return JoinType.jtRound;
250+
case JointStyle.Miter:
251+
return JoinType.jtMiter;
252+
case JointStyle.Square:
253+
default:
254+
return JoinType.jtSquare;
255+
}
256+
}
257+
258+
private static EndType Convert(EndCapStyle style)
259+
{
260+
switch (style)
261+
{
262+
case EndCapStyle.Round:
263+
return EndType.etOpenRound;
264+
case EndCapStyle.Square:
265+
return EndType.etOpenSquare;
266+
case EndCapStyle.Butt:
267+
default:
268+
return EndType.etOpenButt;
269+
}
270+
}
207271
}
208272
}

src/SixLabors.Shapes/SixLabors.Shapes.csproj

+2-1
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,11 @@
3737

3838
<PropertyGroup>
3939
<CodeAnalysisRuleSet>..\..\standards\SixLabors.ruleset</CodeAnalysisRuleSet>
40+
<Version>1.0.0</Version>
4041
</PropertyGroup>
4142

4243
<ItemGroup>
43-
<PackageReference Include="StyleCop.Analyzers" Version="1.1.1-beta.61" PrivateAssets="All"/>
44+
<PackageReference Include="StyleCop.Analyzers" Version="1.1.1-beta.61" PrivateAssets="All" />
4445
<PackageReference Include="SixLabors.Core" Version="1.0.0-beta0007" />
4546
</ItemGroup>
4647
</Project>

0 commit comments

Comments
 (0)