Merge pull request #62 from SixLabors/outliner-styles

Add joint and cap styles to outliner
This commit is contained in:
Scott Williams 2019-02-06 23:14:21 +00:00 коммит произвёл GitHub
Родитель bca6cb1a67 bb093a1547
Коммит 4f12a19a60
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
7 изменённых файлов: 155 добавлений и 13 удалений

Просмотреть файл

@ -12,7 +12,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="SixLabors.ImageSharp.Drawing" Version="1.0.0-dev001425" />
<PackageReference Include="SixLabors.ImageSharp.Drawing" Version="1.0.0-dev002362" />
<PackageReference Include="System.Numerics.Vectors" Version="4.5.0" />
<PackageReference Include="System.Runtime.Numerics" Version="4.3.0" />
</ItemGroup>

Просмотреть файл

@ -4,7 +4,6 @@ using System.Numerics;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing;
using SixLabors.ImageSharp.Processing.Drawing;
namespace SixLabors.Shapes.DrawShapesWithImageSharp
{

Просмотреть файл

@ -6,7 +6,6 @@ using System.Linq;
using System.Numerics;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing;
using SixLabors.ImageSharp.Processing.Drawing;
namespace SixLabors.Shapes.DrawShapesWithImageSharp
{
@ -22,6 +21,14 @@ namespace SixLabors.Shapes.DrawShapesWithImageSharp
private static void OutputStars()
{
OutputStarOutline(5, 150, 250, width: 20, jointStyle: JointStyle.Miter);
OutputStarOutline(5, 150, 250, width: 20, jointStyle: JointStyle.Round);
OutputStarOutline(5, 150, 250, width: 20, jointStyle: JointStyle.Square);
OutputStarOutlineDashed(5, 150, 250, width: 20, jointStyle: JointStyle.Square, cap: EndCapStyle.Butt);
OutputStarOutlineDashed(5, 150, 250, width: 20, jointStyle: JointStyle.Round, cap: EndCapStyle.Round);
OutputStarOutlineDashed(5, 150, 250, width: 20, jointStyle: JointStyle.Square, cap: EndCapStyle.Square);
OutputStar(3, 5);
OutputStar(4);
OutputStar(5);
@ -39,7 +46,7 @@ namespace SixLabors.Shapes.DrawShapesWithImageSharp
DrawFatL();
DrawText("Hello World");
DrawText("Hello World Hello World Hello World Hello World Hello World Hello World Hello World", new Path(new CubicBezierLineSegment(
DrawText("Hello World Hello World Hello World Hello World Hello World Hello World Hello World", new Path(new CubicBezierLineSegment(
new Vector2(0, 0),
new Vector2(150, -150),
new Vector2(250, -150),
@ -174,6 +181,25 @@ namespace SixLabors.Shapes.DrawShapesWithImageSharp
sb.Build().Translate(0, 10).Scale(10).SaveImage("drawing", $"HourGlass.png");
}
private static void OutputStarOutline(int points, float inner = 10, float outer = 20, float width = 5, JointStyle jointStyle = JointStyle.Miter)
{
// center the shape outerRadii + 10 px away from edges
float offset = outer + 10;
Star star = new Star(offset, offset, points, inner, outer);
var outline = Outliner.GenerateOutline(star, width, jointStyle);
outline.SaveImage("Stars", $"StarOutline_{points}_{jointStyle}.png");
}
private static void OutputStarOutlineDashed(int points, float inner = 10, float outer = 20, float width = 5, JointStyle jointStyle = JointStyle.Miter, EndCapStyle cap = EndCapStyle.Butt)
{
// center the shape outerRadii + 10 px away from edges
float offset = outer + 10;
Star star = new Star(offset, offset, points, inner, outer);
var outline = Outliner.GenerateOutline(star, width, new float[] { 3, 3 }, false, jointStyle, cap);
outline.SaveImage("Stars", $"StarOutlineDashed_{points}_{jointStyle}_{cap}.png");
}
private static void OutputStar(int points, float inner = 10, float outer = 20)
{
// center the shape outerRadii + 10 px away from edges
@ -228,7 +254,7 @@ namespace SixLabors.Shapes.DrawShapesWithImageSharp
{
new PathCollection(shape).SaveImage(width, height, path);
}
public static void SaveImage(this IPathCollection shape, int width, int height, params string[] path)
public static void SaveImage(this IPathCollection shape, int width, int height, params string[] path)
{
string fullPath = System.IO.Path.GetFullPath(System.IO.Path.Combine("Output", System.IO.Path.Combine(path)));

Просмотреть файл

@ -0,0 +1,26 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
namespace SixLabors.Shapes
{
/// <summary>
/// The style to apply to the end cap when generating an outline.
/// </summary>
public enum EndCapStyle
{
/// <summary>
/// The outline stops exactly at the end of the path.
/// </summary>
Butt = 0,
/// <summary>
/// The outline extends with a rounded style passed the end of the path.
/// </summary>
Round = 1,
/// <summary>
/// The outlines ends squared off passed the end of the path.
/// </summary>
Square = 2,
}
}

Просмотреть файл

@ -0,0 +1,26 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
namespace SixLabors.Shapes
{
/// <summary>
/// The style we use to generate the joints when outlining.
/// </summary>
public enum JointStyle
{
/// <summary>
/// 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"/>.
/// </summary>
Miter = 2,
/// <summary>
/// Rounded joints. Joints generate with a rounded profile.
/// </summary>
Round = 1,
/// <summary>
/// Joints are squared off 1 width distance from the corner.
/// </summary>
Square = 0
}
}

Просмотреть файл

@ -15,6 +15,7 @@ namespace SixLabors.Shapes
/// </summary>
public static class Outliner
{
private const double MiterOffsetDelta = 20;
private const float ScalingFactor = 1000.0f;
/// <summary>
@ -59,15 +60,34 @@ namespace SixLabors.Shapes
/// <param name="startOff">Weather the first item in the pattern is on or off.</param>
/// <returns>A new path representing the outline.</returns>
public static IPath GenerateOutline(this IPath path, float width, ReadOnlySpan<float> pattern, bool startOff)
=> GenerateOutline(path, width, pattern, startOff, JointStyle.Square, EndCapStyle.Butt);
/// <summary>
/// Generates a outline of the path with alternating on and off segments based on the pattern.
/// </summary>
/// <param name="path">the path to outline</param>
/// <param name="width">The final width outline</param>
/// <param name="pattern">The pattern made of multiples of the width.</param>
/// <param name="startOff">Weather the first item in the pattern is on or off.</param>
/// <param name="jointStyle">The style to render the joints.</param>
/// <param name="patternSectionCapStyle">The style to render between sections of the specified pattern.</param>
/// <returns>A new path representing the outline.</returns>
public static IPath GenerateOutline(this IPath path, float width, ReadOnlySpan<float> pattern, bool startOff, JointStyle jointStyle = JointStyle.Square, EndCapStyle patternSectionCapStyle = EndCapStyle.Butt)
{
if (pattern.Length < 2)
{
return path.GenerateOutline(width);
}
var style = Convert(jointStyle);
var patternSectionCap = Convert(patternSectionCapStyle);
IEnumerable<ISimplePath> paths = path.Flatten();
var offset = new ClipperOffset();
var offset = new ClipperOffset()
{
MiterLimit = MiterOffsetDelta
};
var buffer = new List<IntPoint>(3);
foreach (ISimplePath p in paths)
@ -103,7 +123,7 @@ namespace SixLabors.Shapes
// we now inset a line joining
if (online)
{
offset.AddPath(buffer, JoinType.jtSquare, EndType.etOpenButt);
offset.AddPath(buffer, style, patternSectionCap);
}
online = !online;
@ -138,7 +158,7 @@ namespace SixLabors.Shapes
if (online)
{
offset.AddPath(buffer, JoinType.jtSquare, EndType.etOpenButt);
offset.AddPath(buffer, style, patternSectionCap);
}
online = !online;
@ -158,9 +178,25 @@ namespace SixLabors.Shapes
/// <param name="path">the path to outline</param>
/// <param name="width">The final width outline</param>
/// <returns>A new path representing the outline.</returns>
public static IPath GenerateOutline(this IPath path, float width)
public static IPath GenerateOutline(this IPath path, float width) => GenerateOutline(path, width, JointStyle.Square, EndCapStyle.Butt);
/// <summary>
/// Generates a solid outline of the path.
/// </summary>
/// <param name="path">the path to outline</param>
/// <param name="width">The final width outline</param>
/// <param name="jointStyle">The style to render the joints.</param>
/// <param name="endCapStyle">The style to render the end caps of open paths (ignored on closed paths).</param>
/// <returns>A new path representing the outline.</returns>
public static IPath GenerateOutline(this IPath path, float width, JointStyle jointStyle = JointStyle.Square, EndCapStyle endCapStyle = EndCapStyle.Butt)
{
var offset = new ClipperOffset();
var offset = new ClipperOffset()
{
MiterLimit = MiterOffsetDelta
};
var style = Convert(jointStyle);
var openEndCapStyle = Convert(endCapStyle);
// Pattern can be applied to the path by cutting it into segments
IEnumerable<ISimplePath> paths = path.Flatten();
@ -173,9 +209,9 @@ namespace SixLabors.Shapes
points.Add(new IntPoint(v.X * ScalingFactor, v.Y * ScalingFactor));
}
EndType type = p.IsClosed ? EndType.etClosedLine : EndType.etOpenButt;
EndType type = p.IsClosed ? EndType.etClosedLine : openEndCapStyle;
offset.AddPath(points, JoinType.jtSquare, type);
offset.AddPath(points, style, type);
}
return ExecuteOutliner(width, offset);
@ -204,5 +240,33 @@ namespace SixLabors.Shapes
{
return new IntPoint(vector.X * ScalingFactor, vector.Y * ScalingFactor);
}
private static JoinType Convert(JointStyle style)
{
switch (style)
{
case JointStyle.Round:
return JoinType.jtRound;
case JointStyle.Miter:
return JoinType.jtMiter;
case JointStyle.Square:
default:
return JoinType.jtSquare;
}
}
private static EndType Convert(EndCapStyle style)
{
switch (style)
{
case EndCapStyle.Round:
return EndType.etOpenRound;
case EndCapStyle.Square:
return EndType.etOpenSquare;
case EndCapStyle.Butt:
default:
return EndType.etOpenButt;
}
}
}
}

Просмотреть файл

@ -37,10 +37,11 @@
<PropertyGroup>
<CodeAnalysisRuleSet>..\..\standards\SixLabors.ruleset</CodeAnalysisRuleSet>
<Version>1.0.0</Version>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="StyleCop.Analyzers" Version="1.1.1-beta.61" PrivateAssets="All"/>
<PackageReference Include="StyleCop.Analyzers" Version="1.1.1-beta.61" PrivateAssets="All" />
<PackageReference Include="SixLabors.Core" Version="1.0.0-beta0007" />
</ItemGroup>
</Project>